mirror of https://github.com/lianthony/NT4.0
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.
3180 lines
66 KiB
3180 lines
66 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
miniport.c
|
|
|
|
Abstract:
|
|
|
|
NDIS miniport wrapper functions
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff (SeanSe) 05-Oct-93
|
|
Jameel Hyder (JameelH) Re-organization 01-Jun-95
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_MINIPORT
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WORK-ITEM CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOLEAN
|
|
NdisIMSwitchToMiniport(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
OUT PNDIS_HANDLE SwitchHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to synchronously grab the miniport's (specified
|
|
by MiniportAdapterHandle) spin-lock and local lock. If it succeeds
|
|
it will return TRUE, otherwise it will return FALSE.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
|
|
context we should nail down.
|
|
SwitchHandle - Pointer to storage for the current irql.
|
|
This is returned to the caller as a handle,
|
|
need-to-know basis baby.
|
|
|
|
Return Value:
|
|
|
|
TRUE if we obtain both locks, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
BOOLEAN LocalLock;
|
|
LONG Thread;
|
|
|
|
//
|
|
// Did we already acuqire the lock with this thread?
|
|
//
|
|
Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
|
|
if (CURRENT_THREAD == Thread)
|
|
{
|
|
//
|
|
// We've already acquired the lock...
|
|
//
|
|
ASSERT(Miniport->LockAcquired);
|
|
|
|
*SwitchHandle = (NDIS_HANDLE)-1;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, (PKIRQL)SwitchHandle);
|
|
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
if (!LocalLock)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)*SwitchHandle);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
VOID
|
|
NdisIMRevertBack(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE SwitchHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will undo what NdisMLockMiniport did. It will release the
|
|
local lock and free the spin lock.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
|
|
context we are releasing.
|
|
SwitchHandle - This is the original irql from the NdisMLockMiniport
|
|
call.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
|
|
//
|
|
// Before we unlock the miniport's context we need to pick up any
|
|
// stray workitems for this miniport that may have been generated by
|
|
// the caller.
|
|
//
|
|
|
|
#if _SEND_PRIORITY
|
|
//
|
|
// If we are not reseting and not halting then give priority to sends
|
|
// at this point.
|
|
//
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
|
|
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
|
|
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
|
|
{
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
|
|
}
|
|
else
|
|
{
|
|
ndisMProcessDeferredPrioritySends(Miniport);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
if ((NDIS_HANDLE)-1 == SwitchHandle)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, TRUE);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)SwitchHandle);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NdisIMQueueMiniportCallback(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN W_MINIPORT_CALLBACK CallbackRoutine,
|
|
IN PVOID CallbackContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to acquire the specified MiniportAdapterHandle's
|
|
miniport lock and local lock and call the callback routine with the context
|
|
information. If it cannot do so then it will queue a workitem to do it
|
|
later.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - PNDIS_MINIPORT_BLOCK of the miniport whose
|
|
context we are attempting to acquire.
|
|
CallbackRoutine - Pointer to the routine that we are to call.
|
|
CallbackContext - Context information for the callback routine.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS - If we were able to do this synchronously.
|
|
NDIS_STATUS_PENDING - If it will be called at a later time.
|
|
NDIS_STATUS_FAILURE - If the work item could not be queue'd.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
LONG Thread;
|
|
BOOLEAN LockAcquired;
|
|
|
|
//
|
|
// Did we already acuqire the lock with this thread?
|
|
//
|
|
Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
|
|
if (CURRENT_THREAD == Thread)
|
|
{
|
|
//
|
|
// We've already acquired the lock...
|
|
//
|
|
ASSERT(Miniport->LockAcquired);
|
|
LockAcquired = FALSE;
|
|
LocalLock = TRUE;
|
|
}
|
|
else
|
|
{
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
LockAcquired = TRUE;
|
|
}
|
|
|
|
if (!LocalLock)
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Queue the work item to do this later.
|
|
//
|
|
Status = NDISM_QUEUE_NEW_WORK_ITEM(
|
|
Miniport,
|
|
NdisWorkItemMiniportCallback,
|
|
CallbackRoutine,
|
|
CallbackContext);
|
|
|
|
if (LockAcquired)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
|
|
return((NDIS_STATUS_SUCCESS == Status) ? NDIS_STATUS_PENDING : NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Call the callback routine.
|
|
//
|
|
(*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
|
|
|
|
#if _SEND_PRIORITY
|
|
//
|
|
// If we are not reseting and not halting then give priority to sends
|
|
// at this point.
|
|
//
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
|
|
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
|
|
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
|
|
{
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
|
|
}
|
|
else
|
|
{
|
|
ndisMProcessDeferredPrioritySends(Miniport);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
if (LockAcquired)
|
|
{
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WORKITEM CODE FOR INTERMEDIATE MINIPORTS
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisIMQueueWorkItem(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queue's the specific workitem on the work queue.
|
|
|
|
NOTE!!!!!
|
|
|
|
This routine assumes that you have the correct lock acquire to
|
|
touch the SingleWorkItem that you requested to be queued.
|
|
|
|
NdisWorkItemSend - SendLock
|
|
NdisWorkItemResetRequested - Miniport lock
|
|
NdisWorkItemRequest - Miniport lock
|
|
NdisWorkItemDpc - Miniport lock
|
|
NdisWorkItemHalt - Miniport lock
|
|
|
|
Arguments:
|
|
|
|
Miniport - Pointer to the miniport block.
|
|
WorkItemType - Type of work item to queue.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
#ifdef NDIS_NT
|
|
|
|
NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
//
|
|
// If the status is not accepted then it means that there is already
|
|
// a workitem of this type queued and there should be a timer fired
|
|
// to process it.
|
|
//
|
|
if (Status != NDIS_STATUS_NOT_ACCEPTED)
|
|
{
|
|
NDISM_DEFER_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisIMQueueNewWorkItem(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will queue a workitem in the work queue even if there
|
|
are already work items queue for it.
|
|
|
|
THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport block to queue the workitem to.
|
|
WorkItem - Workitem to place on the queue.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
#ifdef NDIS_NT
|
|
|
|
NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
//
|
|
// Since we can have any number of these work items queued we
|
|
// need to be sure that they all get processed.
|
|
//
|
|
NDISM_DEFER_PROCESS_DEFERRED(Miniport);
|
|
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WORKITEM CODE FOR HARDWARE MINIPORTS
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisMDeQueueWorkItem(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
OUT PVOID *WorkItemContext1,
|
|
OUT PVOID *WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will dequeue a workitem of the given type and return any context
|
|
information that is associated with it.
|
|
|
|
NOTE:
|
|
|
|
FOR FULL-DUPLEX USAGE THE WORK LOCK MUST BE ACQUIRED BEFORE THIS ROUTINE IS CALLED !!!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Pointer to the miniport block.
|
|
WorkItemType - Type of workitem to dequeue.
|
|
WorkItemContext1 - Pointer to storage space for first piece of context information.
|
|
WorkItemContext2 - Pointer to storage space for second piece of context information.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PSINGLE_LIST_ENTRY Link;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
|
|
//
|
|
// Grab the first workitem of the given type.
|
|
//
|
|
Link = PopEntryList(&Miniport->WorkQueue[WorkItemType]);
|
|
if (Link != NULL)
|
|
{
|
|
//
|
|
// Get a pointer to the context information.
|
|
//
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
|
|
if (WorkItemContext1 != NULL)
|
|
{
|
|
*WorkItemContext1 = WorkItem->WorkItemContext1;
|
|
}
|
|
|
|
if (WorkItemContext2 != NULL)
|
|
{
|
|
*WorkItemContext2 = WorkItem->WorkItemContext2;
|
|
}
|
|
|
|
switch (WorkItemType)
|
|
{
|
|
case NdisWorkItemMiniportCallback:
|
|
case NdisWorkItemTimer:
|
|
case NdisWorkItemPendingOpen:
|
|
|
|
ASSERT(*WorkItemContext1 != NULL);
|
|
PushEntryList(&Miniport->WorkItemFreeQueue, Link);
|
|
break;
|
|
|
|
case NdisWorkItemResetInProgress:
|
|
|
|
PushEntryList(&Miniport->SingleWorkItems[NdisWorkItemResetRequested], Link);
|
|
break;
|
|
|
|
case NdisWorkItemResetRequested:
|
|
|
|
WorkItem->WorkItemType = NdisWorkItemResetInProgress;
|
|
PushEntryList(&Miniport->WorkQueue[NdisWorkItemResetInProgress], Link);
|
|
break;
|
|
|
|
default:
|
|
PushEntryList(&Miniport->SingleWorkItems[WorkItemType], Link);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisMQueueWorkItem(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
NDISM_QUEUE_WORK_ITEM_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisMQueueWorkItemFullDuplex(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queue's the specific workitem on the work queue.
|
|
|
|
NOTE!!!!!
|
|
|
|
This routine assumes that you have the correct lock acquire to
|
|
touch the SingleWorkItem that you requested to be queued.
|
|
|
|
NdisWorkItemSend - SendLock
|
|
NdisWorkItemResetRequested - Miniport lock
|
|
NdisWorkItemRequest - Miniport lock
|
|
NdisWorkItemDpc - Miniport lock
|
|
NdisWorkItemHalt - Miniport lock
|
|
|
|
Arguments:
|
|
|
|
Miniport - Pointer to the miniport block.
|
|
WorkItemType - Type of work item to queue.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
#ifdef NDIS_NT
|
|
|
|
NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisMQueueNewWorkItem(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will queue a workitem in the work queue even if there
|
|
are already work items queue for it.
|
|
|
|
THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport block to queue the workitem to.
|
|
WorkItem - Workitem to place on the queue.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
NDISM_QUEUE_NEW_WORK_ITEM_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisMQueueNewWorkItemFullDuplex(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_WORK_ITEM_TYPE WorkItemType,
|
|
IN PVOID WorkItemContext1,
|
|
IN PVOID WorkItemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will queue a workitem in the work queue even if there
|
|
are already work items queue for it.
|
|
|
|
THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport block to queue the workitem to.
|
|
WorkItem - Workitem to place on the queue.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
#ifdef NDIS_NT
|
|
|
|
NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
|
|
Miniport,
|
|
WorkItemType,
|
|
WorkItemContext1,
|
|
WorkItemContext2,
|
|
&Status);
|
|
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DEFERRED PROCESSING CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#if _SEND_PRIORITY
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisMProcessDeferredFullDuplexPrioritySends(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes all outstanding operations.
|
|
|
|
CALLED WITH THE LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifdef NDIS_NT
|
|
NDIS_STATUS Status;
|
|
BOOLEAN ProcessWorkItems;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
NDIS_WORK_ITEM_TYPE WorkItemType;
|
|
BOOLEAN AddressingReset;
|
|
PKDPC Dpc;
|
|
PMINIPORT_PENDING_OPEN PendingOpen;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("==>ndisMProcessDeferredFullDuplexPrioritySends\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Are there any sends to process?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
|
|
{
|
|
BOOLEAN fMoreSends;
|
|
|
|
//
|
|
// Process the sends.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
NDISM_START_SENDS(Miniport);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Are there any loopback packets to indicate?
|
|
//
|
|
if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
|
|
{
|
|
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("<==ndisMProcessDeferredFullDuplexPrioritySends\n"));
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisMProcessDeferredFullDuplex(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes all outstanding operations.
|
|
|
|
CALLED WITH THE LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifdef NDIS_NT
|
|
NDIS_STATUS Status;
|
|
BOOLEAN ProcessWorkItems;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
NDIS_WORK_ITEM_TYPE WorkItemType;
|
|
BOOLEAN AddressingReset;
|
|
PKDPC Dpc;
|
|
PMINIPORT_PENDING_OPEN PendingOpen;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("==>ndisMProcessDeferredFullDuplex\n"));
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
|
|
//
|
|
do
|
|
{
|
|
ProcessWorkItems = FALSE;
|
|
|
|
//
|
|
// Is there a reset currently in progress?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
|
|
{
|
|
//
|
|
// The only thing that can run during a reset in progress
|
|
// are the timers.
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing dpc timer\n"));
|
|
|
|
//
|
|
// Grab the timer workitem.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
|
|
|
|
//
|
|
// Queue the timer's dpc to fire.
|
|
//
|
|
QUEUE_DPC(Dpc);
|
|
}
|
|
else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
|
|
{
|
|
//
|
|
// We have requests to process that set up the packet
|
|
// filters.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
ndisMDoRequests(Miniport);
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the adapter is halting then get out of here.
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Miniport is halting\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If an intermediate miniport wants a call back do it now...
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
|
|
{
|
|
W_MINIPORT_CALLBACK CallbackRoutine;
|
|
PVOID CallbackContext;
|
|
|
|
//
|
|
// Get the callback routine and the context information for it.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(
|
|
Miniport,
|
|
NdisWorkItemMiniportCallback,
|
|
(PVOID *)&CallbackRoutine,
|
|
&CallbackContext);
|
|
|
|
//
|
|
// Call the intermediate drivers callback routine.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
(*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Does a deferred dpc need to run?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing DPC\n"));
|
|
|
|
//
|
|
// Queue the dpc to run.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
|
|
QUEUE_DPC(Dpc);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is there a timer to fire?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing dpc timer\n"));
|
|
|
|
//
|
|
// Queue the timer's dpc to fire.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
|
|
QUEUE_DPC(Dpc);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Finish any pending opens?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
|
|
{
|
|
//
|
|
// Grab the pending open block.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Finish the pending open.
|
|
//
|
|
Status = ndisMFinishPendingOpen(PendingOpen);
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Did it pend again?
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_QUEUE_NEW_WORK_ITEM(
|
|
Miniport,
|
|
NdisWorkItemPendingOpen,
|
|
PendingOpen,
|
|
NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Process more work items.
|
|
//
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Was there a reset requested?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Reset requested\n"));
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// We need to release the work item lock to
|
|
// indicate the status to the bindings
|
|
// and to call down to the miniport driver.
|
|
//
|
|
Status = ndisMProcessResetRequested(Miniport,
|
|
&AddressingReset);
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Reset is pending\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Do we need to run a dpc?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
|
|
{
|
|
//
|
|
// Queue the dpc to run.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
|
|
QUEUE_DPC(Dpc);
|
|
}
|
|
|
|
//
|
|
// The reset is still in progress so we need to stop
|
|
// processing workitems and wait for the completion.
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do step1 of the reset complete.
|
|
//
|
|
ndisMResetCompleteCommonStep1(Miniport,
|
|
Status,
|
|
AddressingReset);
|
|
if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
|
|
{
|
|
//
|
|
// If there is no addressing reset to be done or
|
|
// the reset failed in some way then we tell the
|
|
// bindings now.
|
|
//
|
|
ndisMResetCompleteCommonStep2(Miniport);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process any requests?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
|
|
{
|
|
//
|
|
// Process the requests.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
ndisMDoRequests(Miniport);
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Are there any loopback packets to indicate?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
|
|
{
|
|
BOOLEAN fMoreLoopback;
|
|
|
|
//
|
|
// Process the loopback packets.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
fMoreLoopback = ndisMIndicateLoopback(Miniport);
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
if (!fMoreLoopback)
|
|
{
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
|
|
}
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Are there any sends to process?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
|
|
{
|
|
BOOLEAN fMoreSends;
|
|
|
|
//
|
|
// Process the sends.
|
|
//
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
NDISM_START_SENDS(Miniport);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
} while (ProcessWorkItems);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("<==ndisMProcessDeferredFullDuplex\n"));
|
|
#endif
|
|
}
|
|
|
|
#if _SEND_PRIORITY
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisMProcessDeferredPrioritySends(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes all outstanding operations.
|
|
|
|
CALLED WITH THE LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("==>ndisMProcessDeferredPrioritySends\n"));
|
|
|
|
//
|
|
// Are there any sends to process?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
|
|
{
|
|
//
|
|
// Process the sends.
|
|
//
|
|
NDISM_START_SENDS(Miniport);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
//
|
|
// Are there any loopback packets to indicate?
|
|
//
|
|
if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
|
|
(Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
|
|
{
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("<==ndisMProcessDeferredPrioritySends\n"));
|
|
}
|
|
|
|
#endif
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisMProcessDeferred(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes all outstanding operations.
|
|
|
|
CALLED WITH THE LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
BOOLEAN ProcessWorkItems;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
NDIS_WORK_ITEM_TYPE WorkItemType;
|
|
BOOLEAN AddressingReset;
|
|
PKDPC Dpc;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
PMINIPORT_PENDING_OPEN PendingOpen;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("==>ndisMProcessDeferred\n"));
|
|
|
|
//
|
|
// DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
|
|
//
|
|
do
|
|
{
|
|
ProcessWorkItems = FALSE;
|
|
|
|
//
|
|
// Is there a reset currently in progress?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
|
|
{
|
|
//
|
|
// The only thing that can run during a reset in progress
|
|
// are the timers.
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing dpc timer\n"));
|
|
|
|
//
|
|
// Grab the timer workitem.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
|
|
|
|
//
|
|
// Queue the timer's dpc to fire.
|
|
//
|
|
QUEUE_DPC(Dpc);
|
|
}
|
|
else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
|
|
{
|
|
//
|
|
// We have requests to process that set up the packet
|
|
// filters.
|
|
//
|
|
ndisMDoRequests(Miniport);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the adapter is halting then get out of here.
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Miniport is halting\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If an intermediate miniport wants a call back do it now...
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
|
|
{
|
|
W_MINIPORT_CALLBACK CallbackRoutine;
|
|
PVOID CallbackContext;
|
|
|
|
//
|
|
// Get the callback routine and the context information for it.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(
|
|
Miniport,
|
|
NdisWorkItemMiniportCallback,
|
|
(PVOID *)&CallbackRoutine,
|
|
&CallbackContext);
|
|
|
|
//
|
|
// Call the intermediate drivers callback routine.
|
|
//
|
|
(*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Does a deferred dpc need to run?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing DPC\n"));
|
|
|
|
//
|
|
// Queue the dpc to run.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
|
|
QUEUE_DPC(Dpc);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is there a timer to fire?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Queuing dpc timer\n"));
|
|
|
|
//
|
|
// Queue the timer's dpc to fire.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
|
|
QUEUE_DPC(Dpc);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Finish any pending opens?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
|
|
{
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
|
|
|
|
//
|
|
// Finish the pending open.
|
|
//
|
|
Status = ndisMFinishPendingOpen(PendingOpen);
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_QUEUE_NEW_WORK_ITEM(
|
|
Miniport,
|
|
NdisWorkItemPendingOpen,
|
|
PendingOpen,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// Process more work items.
|
|
//
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Was there a reset requested?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Reset requested\n"));
|
|
//
|
|
// We need to release the work item lock to
|
|
// indicate the status to the bindings
|
|
// and to call down to the miniport driver.
|
|
//
|
|
Status = ndisMProcessResetRequested(Miniport,
|
|
&AddressingReset);
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Reset is pending\n"));
|
|
//
|
|
// Do we need to run a dpc?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
|
|
{
|
|
//
|
|
// Dequeue the dpc.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
|
|
|
|
//
|
|
// Queue the dpc to run.
|
|
//
|
|
QUEUE_DPC(Dpc);
|
|
}
|
|
|
|
//
|
|
// The reset is still in progress so we need to stop
|
|
// processing workitems and wait for the completion.
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do step1 of the reset complete.
|
|
//
|
|
ndisMResetCompleteCommonStep1(Miniport,
|
|
Status,
|
|
AddressingReset);
|
|
if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
|
|
{
|
|
//
|
|
// If there is no addressing reset to be done or
|
|
// the reset failed in some way then we tell the
|
|
// bindings now.
|
|
//
|
|
ndisMResetCompleteCommonStep2(Miniport);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We MUST complete the filter requests within
|
|
// the reset in progress workitem. Mainly because
|
|
// we don't want to do any sends at this time.
|
|
//
|
|
ProcessWorkItems = TRUE;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process any requests?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
|
|
{
|
|
//
|
|
// Process the requests.
|
|
//
|
|
ndisMDoRequests(Miniport);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Are there any loopback packets to indicate?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
|
|
{
|
|
BOOLEAN fMoreLoopback;
|
|
|
|
//
|
|
// Process the loopback packets.
|
|
//
|
|
fMoreLoopback = ndisMIndicateLoopback(Miniport);
|
|
|
|
if (!fMoreLoopback)
|
|
{
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
|
|
}
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
|
|
//
|
|
// Are there any sends to process?
|
|
//
|
|
if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
|
|
{
|
|
//
|
|
// Process the sends.
|
|
//
|
|
NDISM_START_SENDS(Miniport);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
ProcessWorkItems = TRUE;
|
|
}
|
|
} while (ProcessWorkItems);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("<==ndisMProcessDeferred\n"));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// INDICATE CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
NdisMIndicateStatus(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates a new status of the media/mini-port.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
GeneralStatus - The status to indicate.
|
|
|
|
StatusBuffer - Additional information.
|
|
|
|
StatusBufferSize - Length of the buffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
NDIS_STATUS Status;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
if ((GeneralStatus == NDIS_STATUS_RING_STATUS) &&
|
|
(StatusBufferSize == sizeof(NDIS_STATUS)))
|
|
{
|
|
|
|
Status = *((PNDIS_STATUS)StatusBuffer);
|
|
|
|
if (Status & (NDIS_RING_LOBE_WIRE_FAULT |
|
|
NDIS_RING_HARD_ERROR |
|
|
NDIS_RING_SIGNAL_LOSS))
|
|
{
|
|
Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
Open = Miniport->OpenQueue;
|
|
|
|
while (Open != NULL)
|
|
{
|
|
//
|
|
// Call Protocol to indicate status
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
|
|
Open->ProtocolBindingContext,
|
|
GeneralStatus,
|
|
StatusBuffer,
|
|
StatusBufferSize
|
|
);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NdisMIndicateStatusComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the status is complete.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
Open = Miniport->OpenQueue;
|
|
|
|
while (Open != NULL)
|
|
{
|
|
//
|
|
// Call Protocol to indicate status
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
|
|
Open->ProtocolBindingContext);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMWanIndicateReceive(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE NdisLinkContext,
|
|
IN PUCHAR Packet,
|
|
IN ULONG PacketSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the status is complete.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
Open = Miniport->OpenQueue;
|
|
|
|
while (Open != NULL)
|
|
{
|
|
//
|
|
// Call Protocol to indicate status
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
*Status = ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
|
|
NdisLinkContext,
|
|
Packet,
|
|
PacketSize);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NdisMWanIndicateReceiveComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE NdisLinkContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the status is complete.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
Open = Miniport->OpenQueue;
|
|
|
|
while (Open != NULL)
|
|
{
|
|
//
|
|
// Call Protocol to indicate status
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler)(NdisLinkContext);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisQueryReceiveInformation(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacContext,
|
|
OUT PLONGLONG TimeSent OPTIONAL,
|
|
OUT PLONGLONG TimeReceived OPTIONAL,
|
|
IN PUCHAR Buffer,
|
|
IN UINT BufferSize,
|
|
OUT PUINT SizeNeeded
|
|
)
|
|
{
|
|
PNDIS_OPEN_BLOCK OpenBlock = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
|
|
PNDIS_M_OPEN_BLOCK MOpenBlock = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MOpenBlock->MiniportHandle);
|
|
PNDIS_PACKET Packet = (PNDIS_PACKET)MacContext;
|
|
NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("NdisQueryReceiveInformation - Miniort %lx, Packet %lx\n",
|
|
Miniport, Packet));
|
|
|
|
//
|
|
// The following tests whether this is a mac or a miniport and also if we
|
|
// came here via a IndicatePacket or IndicateRecieve
|
|
//
|
|
if ((MOpenBlock->FakeOpen == OpenBlock) &&
|
|
(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID)))
|
|
{
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
|
|
*SizeNeeded = pOob->SizeMediaSpecificInfo;
|
|
if (BufferSize < *SizeNeeded)
|
|
{
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(Buffer, pOob->MediaSpecificInformation, *SizeNeeded);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
if (ARGUMENT_PRESENT(TimeSent))
|
|
{
|
|
*TimeSent = pOob->TimeSent;
|
|
}
|
|
if (ARGUMENT_PRESENT(TimeReceived))
|
|
{
|
|
*TimeReceived = pOob->TimeReceived;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisReturnPackets(
|
|
IN PNDIS_PACKET *PacketsToReturn,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrement the refcount for the packet and return back to the miniport if 0.
|
|
We take the Miniport lock here and hence are protected against other receives.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Handle to the open binding
|
|
PacketsToReturn - Pointer to the set of packets to return to the miniport
|
|
NumberOfPackets - self descriptive
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < NumberOfPackets; i++)
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
W_RETURN_PACKET_HANDLER Handler;
|
|
PNDIS_PACKET Packet;
|
|
BOOLEAN QueueWorkItem = FALSE;
|
|
|
|
Packet = PacketsToReturn[i];
|
|
ASSERT (Packet != NULL);
|
|
|
|
Miniport = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport;
|
|
ASSERT (Miniport != NULL);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
|
|
if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount == 0)
|
|
{
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID))
|
|
{
|
|
Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
|
|
(*Handler)(Miniport->MiniportAdapterContext, Packet);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket =
|
|
Miniport->ReturnPacketsQueue;
|
|
Miniport->ReturnPacketsQueue = Packet;
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED))
|
|
{
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
|
|
QueueWorkItem = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
if (QueueWorkItem)
|
|
{
|
|
ndisReferenceMiniport(Miniport);
|
|
QUEUE_WORK_ITEM(&Miniport->WorkItem, HyperCriticalWorkQueue);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMLazyReturnPackets(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_PACKET Packet, NextPacket;
|
|
W_RETURN_PACKET_HANDLER Handler;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED));
|
|
|
|
Packet = Miniport->ReturnPacketsQueue;
|
|
Miniport->ReturnPacketsQueue = NULL;
|
|
|
|
for (NOTHING;
|
|
Packet != NULL;
|
|
Packet = NextPacket)
|
|
{
|
|
NextPacket = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket;
|
|
Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
|
|
(*Handler)(Miniport->MiniportAdapterContext, Packet);
|
|
}
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
ndisDereferenceMiniport(Miniport);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMIndicatePacket(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Miniport to indicate packets to
|
|
all bindings. This is the code path for ndis 4.0 miniport drivers.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The Miniport block.
|
|
|
|
PacketArray - An array of Packets indicated by the miniport. Each packet consists of a
|
|
single buffer.
|
|
|
|
NumberOfPackets - Self-explanatory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// The private structure to indicate up with
|
|
//
|
|
PPNDIS_PACKET pPktArray = PacketArray;
|
|
|
|
//
|
|
// Pointer to the buffer in the ndispacket
|
|
//
|
|
PNDIS_BUFFER Buffer;
|
|
|
|
//
|
|
// Pointer to the 1st segment of the buffer, points to dest address
|
|
//
|
|
PUCHAR Address;
|
|
|
|
//
|
|
// Total packet length
|
|
//
|
|
UINT i, LASize,PacketSize, NumIndicates = 0;
|
|
|
|
//
|
|
// Decides whether we use the protocol's revpkt handler or fall
|
|
// back to old rcvindicate handler
|
|
//
|
|
BOOLEAN fFallBack, FixRef;
|
|
|
|
//
|
|
// The current open block
|
|
//
|
|
PNDIS_M_OPEN_BLOCK pOpenBlock, NextOpen;
|
|
|
|
NDIS_STATUS StatusOfReceive;
|
|
|
|
//
|
|
// Define a NULL Fiter structure so that the IndicateToProtocol macro can be used.
|
|
//
|
|
struct _NullFilter
|
|
{
|
|
PNDIS_SPIN_LOCK Lock;
|
|
} Filter;
|
|
|
|
Filter.Lock = &Miniport->Lock;
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
|
|
|
|
// Walk all the packets
|
|
for (i = 0; i < NumberOfPackets; i++, pPktArray++)
|
|
{
|
|
PNDIS_PACKET Packet = *pPktArray;
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
|
|
ASSERT(Packet != NULL);
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
|
|
|
|
NdisGetFirstBufferFromPacket(Packet,
|
|
&Buffer,
|
|
&Address,
|
|
&LASize,
|
|
&PacketSize);
|
|
ASSERT(Buffer != NULL);
|
|
|
|
//
|
|
// Set the status here that nobody is holding the packet. This will get
|
|
// overwritten by the real status from the protocol. Pay heed to what
|
|
// the miniport is saying.
|
|
//
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
|
|
|
|
if (pOob->Status != NDIS_STATUS_RESOURCES)
|
|
{
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
|
|
pOob->Status = NDIS_STATUS_SUCCESS;
|
|
fFallBack = FALSE;
|
|
FixRef = TRUE;
|
|
}
|
|
else
|
|
{
|
|
FixRef = FALSE;
|
|
fFallBack = TRUE;
|
|
}
|
|
|
|
//
|
|
// Ensure that we force re-calculation.
|
|
//
|
|
Packet->Private.ValidCounts = FALSE;
|
|
|
|
for (pOpenBlock = Miniport->OpenQueue;
|
|
pOpenBlock != NULL;
|
|
pOpenBlock = NextOpen)
|
|
{
|
|
//
|
|
// Get the next open to look at.
|
|
//
|
|
NextOpen = pOpenBlock->MiniportNextOpen;
|
|
pOpenBlock->ReceivedAPacket = TRUE;
|
|
pOpenBlock->References++;
|
|
NumIndicates ++;
|
|
|
|
IndicateToProtocol(Miniport,
|
|
&Filter,
|
|
pOpenBlock->FakeOpen,
|
|
Packet,
|
|
Address,
|
|
PacketSize,
|
|
pOob->HeaderSize,
|
|
&fFallBack,
|
|
FALSE,
|
|
NdisMediumMax); // A dummy medium since it is unknown
|
|
|
|
pOpenBlock->References--;
|
|
if (pOpenBlock->References == 0)
|
|
{
|
|
// Anything to do here ?
|
|
}
|
|
}
|
|
|
|
if (FixRef)
|
|
{
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
|
|
if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
|
|
{
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NumIndicates > 0)
|
|
{
|
|
for (pOpenBlock = Miniport->OpenQueue;
|
|
pOpenBlock != NULL;
|
|
pOpenBlock = NextOpen)
|
|
{
|
|
if (pOpenBlock->ReceiveCompleteHandler)
|
|
{
|
|
pOpenBlock->References++;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(*pOpenBlock->ReceiveCompleteHandler)(pOpenBlock->ProtocolBindingContext);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
if ((--(pOpenBlock->References)) == 0)
|
|
{
|
|
// Anything to do here ?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TRANSFER DATA CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
NdisMTransferDataComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the completion of a transfer data request.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Packet - The packet the data was copied into.
|
|
|
|
Status - Status of the operation.
|
|
|
|
BytesTransferred - Total number of bytes transferred.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_PACKET PrevPacket;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
ASSERT(Miniport->FirstTDPacket != NULL);
|
|
|
|
//
|
|
// Find the packet
|
|
//
|
|
|
|
if (Packet == Miniport->FirstTDPacket)
|
|
{
|
|
Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
}
|
|
else
|
|
{
|
|
PrevPacket = Miniport->FirstTDPacket;
|
|
|
|
while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet)
|
|
{
|
|
PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next;
|
|
|
|
ASSERT(PrevPacket != NULL);
|
|
}
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next =
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
|
|
if (Packet == Miniport->LastTDPacket)
|
|
{
|
|
Miniport->LastTDPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Indicate to Protocol;
|
|
//
|
|
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
|
|
Open->ProtocolBindingContext,
|
|
Packet,
|
|
Status,
|
|
BytesTransferred);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMTransferDataSync(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
NDIS_STATUS Status;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
|
|
|
|
//
|
|
// Handle non-loopback as the default case.
|
|
//
|
|
|
|
if (Miniport->LoopbackPacket == NULL)
|
|
{
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Call Miniport.
|
|
//
|
|
|
|
Status = (Reserved->Open->TransferDataHandler)(
|
|
Packet,
|
|
BytesTransferred,
|
|
Reserved->Open->MiniportAdapterContext,
|
|
MacReceiveContext,
|
|
ByteOffset,
|
|
BytesToTransfer);
|
|
//
|
|
// This miniport better not pend this send.
|
|
//
|
|
|
|
ASSERT(Status != NDIS_STATUS_PENDING);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// This packet is a loopback packet!
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
|
|
NdisCopyFromPacketToPacket(Packet,
|
|
0,
|
|
BytesToTransfer,
|
|
Miniport->LoopbackPacket,
|
|
ByteOffset + pOob->HeaderSize,
|
|
BytesTransferred);
|
|
|
|
if (*BytesTransferred == BytesToTransfer)
|
|
{
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMTransferData(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
PNDIS_PACKET PrevLast;
|
|
NDIS_STATUS Status;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
//
|
|
// Handle non-loopback as the default case.
|
|
//
|
|
|
|
if (Miniport->LoopbackPacket == NULL)
|
|
{
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Put this guy on the transfer data queue.
|
|
//
|
|
|
|
PrevLast = Miniport->LastTDPacket;
|
|
|
|
if (Miniport->FirstTDPacket == NULL)
|
|
{
|
|
Miniport->FirstTDPacket = Packet;
|
|
}
|
|
else
|
|
{
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet;
|
|
}
|
|
|
|
Miniport->LastTDPacket = Packet;
|
|
|
|
//
|
|
// Call Miniport
|
|
//
|
|
|
|
Status = (Reserved->Open->TransferDataHandler)(
|
|
Packet,
|
|
BytesTransferred,
|
|
Reserved->Open->MiniportAdapterContext,
|
|
MacReceiveContext,
|
|
ByteOffset,
|
|
BytesToTransfer);
|
|
|
|
//
|
|
// If it didn't pend then we won't get a transfer data complte call
|
|
// so we need to remove this guy now.
|
|
//
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
//
|
|
// Remove from queue
|
|
//
|
|
|
|
if (Miniport->FirstTDPacket != Packet)
|
|
{
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL;
|
|
Miniport->LastTDPacket = PrevLast;
|
|
}
|
|
else
|
|
{
|
|
Miniport->FirstTDPacket = NULL;
|
|
Miniport->LastTDPacket = NULL;
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// This packet is a loopback packet!
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
|
|
NdisCopyFromPacketToPacket(Packet,
|
|
0,
|
|
BytesToTransfer,
|
|
Miniport->LoopbackPacket,
|
|
ByteOffset + pOob->HeaderSize,
|
|
BytesTransferred);
|
|
|
|
if (*BytesTransferred == BytesToTransfer)
|
|
{
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMDummyTransferData(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer,
|
|
IN OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred
|
|
)
|
|
{
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
|
|
NdisCopyFromPacketToPacket(Packet,
|
|
0,
|
|
BytesToTransfer,
|
|
(PNDIS_PACKET)MacReceiveContext,
|
|
ByteOffset + pOob->HeaderSize,
|
|
BytesTransferred);
|
|
|
|
return ((*BytesTransferred == BytesToTransfer) ?
|
|
NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RESET CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
ndisMAbortPacketsAndRequests(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Aborts all outstanding requests on a mini-port.
|
|
|
|
CALLED WITH THE LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to abort.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET NextPacket;
|
|
PNDIS_REQUEST MiniportRequest;
|
|
PNDIS_REQUEST PendingRequest;
|
|
PNDIS_REQUEST NextRequest;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_PACKET ArcnetLimitPacket;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
BOOLEAN fRestoreDeferredState = FALSE;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Enter abort packets and requests\n"));
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
//
|
|
// Dequeue any send workitems and acquire the send spin lock
|
|
// if we are full duplex..
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
//
|
|
// Since we are full duplex we need to wrap the dequeue operation
|
|
// with spin lock acquire and release.
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Acquire the spin lock.
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// non-full duplex miniports can just dequeue any send work items
|
|
// that are queued
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
//
|
|
// Clear out the packet queues.
|
|
//
|
|
Packet = Miniport->FirstPacket;
|
|
ArcnetLimitPacket = Miniport->FirstPendingPacket;
|
|
|
|
Miniport->LastMiniportPacket = NULL;
|
|
Miniport->FirstPendingPacket = NULL;
|
|
Miniport->FirstPacket = NULL;
|
|
Miniport->LastPacket = NULL;
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'a');
|
|
|
|
//
|
|
// Go through the list of packets an return them to the
|
|
// bindings
|
|
//
|
|
while (Packet != NULL)
|
|
{
|
|
//
|
|
// Get a pointer to the next packet before we kill
|
|
// the current one.
|
|
//
|
|
NextPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
|
|
//
|
|
// Get the open that the packet came from.
|
|
//
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
|
|
|
|
//
|
|
// Set flag that we've reached the packets that are
|
|
// not on the mini-port.
|
|
//
|
|
|
|
if (Packet == ArcnetLimitPacket)
|
|
{
|
|
ArcnetLimitPacket = NULL;
|
|
}
|
|
|
|
//
|
|
// Now free the arcnet header.
|
|
//
|
|
|
|
if (Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket)
|
|
{
|
|
ndisMFreeArcnetHeader(Miniport, Packet);
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
|
|
Open->ProtocolBindingContext,
|
|
Packet,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// Re-acquire the send lock if we are full duplex.
|
|
// Note that the wrapper does NOT keep track of open
|
|
// references with regard to sends for full duplex miniports.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
Open->References--;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
if (Open->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport,Open);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the next packet.
|
|
//
|
|
Packet = NextPacket;
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'A');
|
|
|
|
Miniport->SendResourcesAvailable = 0x00ffffff;
|
|
|
|
//
|
|
// Dequeue any request workitems.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
//
|
|
// Release the send lock.
|
|
//
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// Since we are full duplex we need to wrap the dequeue operation
|
|
// with spin lock acquire and release.
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// non-full duplex miniports can just dequeue any send work items
|
|
// that are queued
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Clear the request timeout flag.
|
|
//
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
|
|
|
|
//
|
|
// We need to clear out the pending request queue before the currently in
|
|
// progress one so that when we complete the in-progress request we
|
|
// won't think that we have to process more requests.
|
|
//
|
|
PendingRequest = Miniport->PendingRequest;
|
|
Miniport->PendingRequest = NULL;
|
|
|
|
MiniportRequest = Miniport->MiniportRequest;
|
|
|
|
//
|
|
// If there is one then abort it.
|
|
//
|
|
if (MiniportRequest != NULL)
|
|
{
|
|
//
|
|
// Get a pointer to the open that the request came from.
|
|
//
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(MiniportRequest)->Open;
|
|
|
|
//
|
|
// Was this a statistics request?
|
|
//
|
|
if ((Open != NULL) &&
|
|
(MiniportRequest->RequestType == NdisRequestQueryStatistics))
|
|
{
|
|
ndisMAbortQueryStatisticsRequest(MiniportRequest,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
|
|
Miniport->MiniportRequest = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (MiniportRequest->RequestType == NdisRequestSetInformation)
|
|
{
|
|
ndisMSyncSetInformationComplete((NDIS_HANDLE)Miniport,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
}
|
|
else
|
|
{
|
|
ndisMSyncQueryInformationComplete((NDIS_HANDLE)Miniport,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Go through the pending request queue and clear it out.
|
|
//
|
|
while (PendingRequest != NULL)
|
|
{
|
|
//
|
|
// Get a pointer to the next request before we kill the
|
|
// current one.
|
|
//
|
|
NextRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Next;
|
|
|
|
//
|
|
// Get a pointer to the open that the request belongs to.
|
|
//
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Open;
|
|
|
|
if (PendingRequest->RequestType == NdisRequestQueryStatistics)
|
|
{
|
|
ndisMAbortQueryStatisticsRequest(
|
|
PendingRequest,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Make this request the request in progress.
|
|
//
|
|
Miniport->MiniportRequest = PendingRequest;
|
|
|
|
if (PendingRequest->RequestType == NdisRequestSetInformation)
|
|
{
|
|
ndisMSyncSetInformationComplete(Miniport,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
}
|
|
else
|
|
{
|
|
ndisMSyncQueryInformationComplete(Miniport,
|
|
NDIS_STATUS_REQUEST_ABORTED);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the next request.
|
|
//
|
|
PendingRequest = NextRequest;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Exit abort packets and requests\n"));
|
|
}
|
|
|
|
VOID
|
|
ndisMResetCompleteCommonStep2(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PSINGLE_LIST_ENTRY Link;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_M_OPEN_BLOCK tmpOpen;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
|
|
|
|
//
|
|
// Dequeue the reset in progress work item.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
//
|
|
// Acquire the work lock and dequeue the reset in progress work item.
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Grab the send lock so that we can clear the reset in progress flag.
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
|
|
|
|
for (tmpOpen = Miniport->OpenQueue;
|
|
tmpOpen != NULL;
|
|
tmpOpen = tmpOpen->MiniportNextOpen)
|
|
{
|
|
//
|
|
// Restore the send handler
|
|
//
|
|
tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
|
|
|
|
//
|
|
// Restore the send packets handler.
|
|
//
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
|
{
|
|
tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplex;
|
|
}
|
|
else
|
|
{
|
|
tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For non full duplex miniports we don't need to acquire the work lock.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
|
|
|
|
//
|
|
// Clear the reset in progress flag.
|
|
//
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
|
|
|
|
for (tmpOpen = Miniport->OpenQueue;
|
|
tmpOpen != NULL;
|
|
tmpOpen = tmpOpen->MiniportNextOpen)
|
|
{
|
|
//
|
|
// Restore the send handler
|
|
//
|
|
tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
|
|
|
|
//
|
|
// Restore the send packets handler.
|
|
//
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
|
{
|
|
tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPackets;
|
|
}
|
|
else
|
|
{
|
|
tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsToSend;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(Open != NULL);
|
|
|
|
//
|
|
// Indicate to Protocols the reset is complete
|
|
//
|
|
NdisMIndicateStatus(Miniport,
|
|
NDIS_STATUS_RESET_END,
|
|
&Miniport->ResetStatus,
|
|
sizeof(Miniport->ResetStatus));
|
|
|
|
NdisMIndicateStatusComplete(Miniport);
|
|
|
|
//
|
|
// If a protocol initiated the reset then notify it of the
|
|
// completion.
|
|
//
|
|
if (Open != (PNDIS_M_OPEN_BLOCK)Miniport)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
|
|
Open->ProtocolBindingContext,
|
|
Miniport->ResetStatus);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
Open->References--;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
if (Open->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport,Open);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ndisMResetCompleteCommonStep1(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN NDIS_STATUS Status,
|
|
IN BOOLEAN AddressingReset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
//
|
|
// Destroy all outstanding packets and requests.
|
|
//
|
|
ndisMAbortPacketsAndRequests(Miniport);
|
|
|
|
//
|
|
// Check if we are going to have to reset the
|
|
// adapter again. This happens when we are doing
|
|
// the reset because of a ring failure.
|
|
//
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
|
|
{
|
|
if (Miniport->TrResetRing == 1)
|
|
{
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Miniport->TrResetRing = 0;
|
|
}
|
|
else
|
|
{
|
|
Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we need to reset the miniports filter settings then
|
|
// queue the necessary requests & work items.
|
|
//
|
|
if (AddressingReset &&
|
|
(Status == NDIS_STATUS_SUCCESS) &&
|
|
((Miniport->EthDB != NULL) || (Miniport->TrDB != NULL) ||
|
|
(Miniport->FddiDB != NULL) || (Miniport->ArcDB != NULL)))
|
|
{
|
|
ndisMRestoreFilterSettings(Miniport, NULL);
|
|
}
|
|
|
|
//
|
|
// Save the reset status as it is now.
|
|
//
|
|
Miniport->ResetStatus = Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMProcessResetRequested(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
OUT PBOOLEAN pAddressingReset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
//
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
//
|
|
// We need to acquire the work lock to dequeue the reset requsted work item.
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
|
|
//
|
|
// We need to acquire the send lock to modify the reset requested and
|
|
// reset in progress flags.
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// Set the reset in progress bit so that the send path can see it.
|
|
//
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
|
|
|
|
//
|
|
// Replace the send handler for the open's
|
|
//
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
Open = Open->MiniportNextOpen)
|
|
{
|
|
if (NdisMediumWan == Miniport->MediaType)
|
|
{
|
|
Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
|
|
}
|
|
else
|
|
{
|
|
Open->FakeOpen->SendHandler = ndisMResetSend;
|
|
}
|
|
|
|
Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
|
|
}
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Dequeue the reset requested work item. this dequeuing will automatically
|
|
// queue the reset in progress work item.
|
|
//
|
|
NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
|
|
|
|
//
|
|
// Set the reset in progress bit so that the send path can see it.
|
|
//
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
|
|
|
|
//
|
|
// Replace the send handler for the open's
|
|
//
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
Open = Open->MiniportNextOpen)
|
|
{
|
|
if (NdisMediumWan == Miniport->MediaType)
|
|
{
|
|
Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
|
|
}
|
|
else
|
|
{
|
|
Open->FakeOpen->SendHandler = ndisMResetSend;
|
|
}
|
|
|
|
Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the reset status to the protocols.
|
|
//
|
|
NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
|
|
NdisMIndicateStatusComplete(Miniport);
|
|
|
|
DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
|
|
("Calling miniport reset\n"));
|
|
//
|
|
// Call the miniport's reset handler.
|
|
//
|
|
Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
|
|
pAddressingReset,
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMResetCompleteFullDuplex(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_STATUS Status,
|
|
IN BOOLEAN AddressingReset
|
|
)
|
|
{
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("Enter reset complete\n"));
|
|
|
|
//
|
|
// Code that is common for synchronous and async resets.
|
|
//
|
|
ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
|
|
if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
|
|
{
|
|
//
|
|
// If there is no addressing reset to be done or
|
|
// the reset failed in some way then we tell the
|
|
// bindings now.
|
|
//
|
|
ndisMResetCompleteCommonStep2(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("Exit reset complete\n"));
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
NdisMResetComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_STATUS Status,
|
|
IN BOOLEAN AddressingReset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the completion of a reset.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Status - Status of the reset.
|
|
|
|
AddressingReset - Do we have to submit a request to reload the address
|
|
information. This includes packet filter, and multicast/functional addresses.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("Enter reset complete\n"));
|
|
|
|
//
|
|
// Code that is common for synchronous and async resets.
|
|
//
|
|
ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
|
|
if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
|
|
{
|
|
//
|
|
// If there is no addressing reset to be done or
|
|
// the reset failed in some way then we tell the
|
|
// bindings now.
|
|
//
|
|
ndisMResetCompleteCommonStep2(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("Exit reset complete\n"));
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMResetFullDuplex(
|
|
IN NDIS_HANDLE NdisBindingHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
KIRQL OldIrql;
|
|
BOOLEAN LocalLock;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// Is there already a reset in progress?
|
|
//
|
|
Status = NDISM_QUEUE_WORK_ITEM(Miniport,
|
|
NdisWorkItemResetRequested,
|
|
NdisBindingHandle,
|
|
NULL);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return(NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
//
|
|
// Update the open's references.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle,
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// The reset requested flag is used by both the send path and the
|
|
// dpc path.
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// Grab the local lock.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// If we did not lock down the mini-port, then some other routine will
|
|
// do this processing for us. Otherwise we need to do this processing.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
#endif
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMReset(
|
|
IN NDIS_HANDLE NdisBindingHandle
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
KIRQL OldIrql;
|
|
BOOLEAN LocalLock;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
NDIS_STATUS Status;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// Is there already a reset in progress?
|
|
//
|
|
Status = NDISM_QUEUE_WORK_ITEM(Miniport,
|
|
NdisWorkItemResetRequested,
|
|
NdisBindingHandle,
|
|
NULL);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
return(NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
//
|
|
// Update the open's references.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// Set the reset requested flag.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
|
|
|
|
//
|
|
// Grab the local lock.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// If we did not lock down the mini-port, then some other routine will
|
|
// do this processing for us. Otherwise we need to do this processing.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|