Windows NT 4.0 source code leak
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

/*++
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);
}