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