VOID HelperPortCompleteScanProcess( _In_ PMP_HELPER_PORT HelperPort, _In_ PMP_SCAN_PARAMETERS ScanParameters, _In_ PNDIS_STATUS CompletionStatus ) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Completed the scan process of %p for port %p\n", ScanParameters, ScanParameters->RequestingPort)); MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // Clear the active pointer MPASSERT(ScanParameters == HelperPort->ScanContext.ActiveScanParameters); HelperPort->ScanContext.ActiveScanParameters = NULL; ScanParameters->State = SCAN_REQUEST_IN_USE; MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // Now perform the indication HelperPortIndicateScanCompletion(HelperPort, ScanParameters, CompletionStatus); // We reacquire the lock to ensure that the cancel does not conflict // with this completion MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // The scan is done ScanParameters->State = SCAN_COMPLETED; HelperPortScanParametersReleaseRef(HelperPort, ScanParameters); MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // If another scan is queued, run it now HelperPortProcessPendingScans(HelperPort); }
VOID BasePortFlushQueuedTxPackets( __in PMP_PORT Port ) { PMP_TX_MSDU currentPacket, packetListToComplete = NULL; ULONG count = 0; NDIS_STATUS completionStatus = BasePortGetPortStatus(Port); // Empty the pending TX queue MP_ACQUIRE_PORT_LOCK(Port, FALSE); while (!MpPacketQueueIsEmpty(&Port->PendingTxQueue)) { currentPacket = MP_MSDU_FROM_QUEUE_ENTRY(MpDequeuePacket(&Port->PendingTxQueue)); count++; MP_TX_MSDU_NEXT_MSDU(currentPacket) = NULL; MP_TX_MSDU_STATUS(currentPacket) = completionStatus; MP_TX_MSDU_NEXT_MSDU(currentPacket) = packetListToComplete; packetListToComplete = currentPacket; } MP_RELEASE_PORT_LOCK(Port, FALSE); if (packetListToComplete != NULL) { BasePortCompleteFailedPackets(Port, packetListToComplete, 0 ); } }
NDIS_STATUS HelperPortScanExAccessCallback( _In_ PMP_PORT Port, _In_ PVOID Ctx ) { PMP_SCAN_PARAMETERS scanParameters = (PMP_SCAN_PARAMETERS)Ctx; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); BOOLEAN performScan = TRUE; // The cancellation here is handled specially. Since we cannot abort // a request for exclusive access, its possible that our exclusive // access request gets honored after we have cancelled a scan HelperPortExclusiveAccessGranted(helperPort); MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); if ((scanParameters->State != SCAN_EXCLUSIVE_ACCESS_QUEUED) || (scanParameters->CancelScan)) { // The request has been cancelled and would get completed MpTrace(COMP_SCAN, DBG_NORMAL, ("Ignored exclusive access for cancelled/old scan request %p\n", scanParameters)); performScan = FALSE; } else { // Move forward with the scan scanParameters->State = SCAN_EXCLUSIVE_ACCESS_ACQUIRED; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); if (performScan) { HelperPortStartPartialScan(helperPort, scanParameters); } else { // Release exclusive access back to the HW HelperPortReleaseExclusiveAccess(helperPort); // Free the scan request HelperPortScanParametersReleaseRef(helperPort, scanParameters); } return NDIS_STATUS_SUCCESS; }
VOID HelperPortNotify( _In_ PMP_PORT Port, PVOID Notif ) { PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); PNOTIFICATION_DATA_HEADER notifyHeader = (PNOTIFICATION_DATA_HEADER)Notif; switch (notifyHeader->Type) { case NotificationOpLinkState: { POP_LINK_STATE_NOTIFICATION pMediaNotif = (POP_LINK_STATE_NOTIFICATION)Notif; MP_ACQUIRE_PORT_LOCK(Port, FALSE); if (pMediaNotif->MediaConnected) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Incrementing connect count for CONNECT. current = %d\n", helperPort->ScanContext.MediaConnectedCount)); MPASSERT(helperPort->ScanContext.MediaConnectedCount < MP_MAX_NUMBER_OF_PORT); helperPort->ScanContext.MediaConnectedCount++; } else { MpTrace(COMP_SCAN, DBG_NORMAL, ("Decrementing connect count for DISCONNECT. current = %d\n", helperPort->ScanContext.MediaConnectedCount)); MPASSERT(helperPort->ScanContext.MediaConnectedCount > 0); helperPort->ScanContext.MediaConnectedCount--; } MP_RELEASE_PORT_LOCK(Port, FALSE); break; } default: break; } }
VOID BasePortTransmitQueuedPackets( __in PMP_PORT Port, __in ULONG SendFlags ) { PMP_TX_MSDU currentPacket, prevPacketToForward = NULL, packetListToForward = NULL; ULONG count = 0, numPktToFwd = 0; NDIS_STATUS ndisStatus; PMP_TX_MSDU packetListToFail = NULL; // PORT_LOCK must be held // If I am pausing, this flag is set. We would not // be processing any pending packets. These packets get flushed on a pause // then not process these pending packets if (MP_TEST_PORT_STATUS(Port, MP_PORT_CANNOT_SEND_MASK)) { // // We dont do anything // MpTrace(COMP_SEND, DBG_NORMAL, ("Dropping sends as port should not be sending\n")); return; } while ((!MpPacketQueueIsEmpty(&Port->PendingTxQueue) && (count < MAX_SEND_MSDU_TO_PROCESS))) { // // Dequeue the first packet from the list // currentPacket = MP_MSDU_FROM_QUEUE_ENTRY(MpDequeuePacket(&Port->PendingTxQueue)); count++; // // Let the port pre-process the packets. We only let one // packet to get processed at a time // MP_TX_MSDU_NEXT_MSDU(currentPacket) = NULL; MP_TX_MSDU_STATUS(currentPacket) = NDIS_STATUS_SUCCESS; ndisStatus = Port11NotifySend(Port, currentPacket, SendFlags); if (ndisStatus == NDIS_STATUS_SUCCESS) { // // Look at the per-packet status values // ndisStatus = MP_TX_MSDU_STATUS(currentPacket); if (ndisStatus == NDIS_STATUS_SUCCESS) { // // Port is fine with processing these packets. Let us check if we can // continue sending this down. We only check with the VNIC // if (VNic11CanTransmit(PORT_GET_VNIC(Port)) == FALSE) { // // Some reason we cannot submit this packet to the // HW yet. Queue it in the pending Tx queue // ndisStatus = NDIS_STATUS_PENDING; // // In this case we indicate the packet to the Port again // the next time we attempt to send. Ensure that the port // can handle that // } } } else { // // Port returned PENDING or FAILURE for the packet list. We wont // be sending any of these packets // } // // All the above processing would give us one of the following status codes // // NDIS_STATUS_SUCCESS - The packets can be processed furthers. In this case // we forward the packet to the lower layer // NDIS_STATUS_PENDING - This packet should not be sent now, but can be sent later // In this case we requeue the packet and stop processing // further packets // NDIS_STATUS_FAILURE or anything other failure status // - The packet is not sent and we continue processing // other packets if (ndisStatus == NDIS_STATUS_SUCCESS) { numPktToFwd++; // Add this to the end of the chain we are forwarding to the HW if (packetListToForward == NULL) { packetListToForward = currentPacket; } else { MP_TX_MSDU_NEXT_MSDU(prevPacketToForward) = currentPacket; } prevPacketToForward = currentPacket; // // Increment the counter for the number of packets we have submitted // to the hardware. This would block the port from pausing, etc // PORT_INCREMENT_PNP_REFCOUNT(Port); } else if (ndisStatus == NDIS_STATUS_PENDING) { // // Put the packet back at the head of the packet queue. To avoid out of // order delivery we dont go forward and give any more packets to the // lower layer // MpQueuePacketPriority(&Port->PendingTxQueue, QUEUE_ENTRY_FROM_MP_MSDU(currentPacket)); break; } else { // // Put this packet in the list of packets to be failed // MpTrace(COMP_SEND, DBG_NORMAL, ("Port or VNic failed sends with status 0x%08x\n", ndisStatus)); MP_TX_MSDU_STATUS(currentPacket) = ndisStatus; MP_TX_MSDU_NEXT_MSDU(currentPacket) = packetListToFail; packetListToFail = currentPacket; } } if ((packetListToForward != NULL) || (packetListToFail != NULL)) { // Forward this list to the VNIC MP_RELEASE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)); if (packetListToForward != NULL) { VNic11SendPackets(PORT_GET_VNIC(Port), packetListToForward, numPktToFwd, SendFlags); } // // Complete the failed packets // if (packetListToFail != NULL) { BasePortCompleteFailedPackets(Port, packetListToFail, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0 ); } MP_ACQUIRE_PORT_LOCK(Port, NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags)); } }
VOID HelperPortStartScanProcess( _In_ PMP_HELPER_PORT HelperPort, _In_ PMP_SCAN_PARAMETERS ScanParameters ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONG scanChannelCount = 0; ULONG i; do { MpTrace(COMP_SCAN, DBG_NORMAL, ("Starting the scan process of %p for port %p\n", ScanParameters, ScanParameters->RequestingPort)); // // For optimal scanning, we specify the list of channels // that the HW should use if the port hasnt specified any. // Note that for ExtSTA the channels in the PhyTypeInfo // structures of the DOT11_SCAN_REQUEST are invalid. So we dont // need to consider those // if (ScanParameters->PortScanRequest->ChannelCount != 0) { // Use the list of channels specified by the port scanChannelCount = ScanParameters->PortScanRequest->ChannelCount; } else { if (HelperPort->ScanContext.MediaConnectedCount > 0) { // A port is connected (STA associated/AP started/Adhoc running) // We dont scan all channels in one shot. We do multiple partial // scans // The scan type determines the number of channels we scan at a time if (ScanParameters->PortScanRequest->Dot11ScanRequest->dot11ScanType & dot11_scan_type_active) scanChannelCount = HelperPort->RegInfo->ActiveScanChannelCount; else scanChannelCount = HelperPort->RegInfo->PassiveScanChannelCount; MpTrace(COMP_SCAN, DBG_NORMAL, ("Link Up scan will scan atmost %d channels at a time\n", scanChannelCount)); } else { // We can scan each phy in one scan. Find the maximum number of // channels in a phy & use that as our scan channels limit scanChannelCount = 0; for (i = 0; i < HW11_MAX_PHY_COUNT; i++) { if (HelperPort->ScanContext.ScanChannels[i].ChannelCount > scanChannelCount) { scanChannelCount = HelperPort->ScanContext.ScanChannels[i].ChannelCount; } } MpTrace(COMP_SCAN, DBG_NORMAL, ("Link Down scan will scan upto %d channels at a time\n", scanChannelCount)); } } ScanParameters->MaxChannelCount = scanChannelCount; // // Create a channel buffer that we would give to the lower layer // MP_ALLOCATE_MEMORY( HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, &ScanParameters->VNicScanRequest.ChannelList, scanChannelCount * sizeof(ULONG), PORT_MEMORY_TAG ); if (ScanParameters->VNicScanRequest.ChannelList == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; break; } // // Save scan start time // NdisGetCurrentSystemTime((PLARGE_INTEGER)&HelperPort->ScanContext.LastScanTime); ScanParameters->VNicScanRequest.Dot11ScanRequest = ScanParameters->PortScanRequest->Dot11ScanRequest; ScanParameters->VNicScanRequest.ScanRequestBufferLength = ScanParameters->PortScanRequest->ScanRequestBufferLength; MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (ScanParameters->CancelScan) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Aborting scan start for a cancelled scan request\n")); ndisStatus = NDIS_STATUS_REQUEST_ABORTED; } else { // We will queue an exclusive access request ScanParameters->State = SCAN_EXCLUSIVE_ACCESS_QUEUED; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // // Queue an exclusive access. The scan would be done in there // ndisStatus = HelperPortRequestExclusiveAccess(HelperPort, HelperPortScanExAccessCallback, ScanParameters, FALSE ); if (NDIS_STATUS_SUCCESS == ndisStatus) { // the function completed synchronously, call the callback ourselves HelperPortScanExAccessCallback(HELPPORT_GET_MP_PORT(HelperPort), ScanParameters); } else if (ndisStatus == NDIS_STATUS_PENDING) { // Pending is same as success if (ndisStatus == NDIS_STATUS_PENDING) { ndisStatus = NDIS_STATUS_SUCCESS; } } else { // The exclusive access request failed MpTrace(COMP_SCAN, DBG_SERIOUS, ("Exclusive access request for scan start failed. Status = 0x%08x\n", ndisStatus)); } }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { HelperPortCompleteScanProcess( HelperPort, ScanParameters, &ndisStatus ); } }
VOID HelperPortScanTimerCallback( _In_ PMP_HELPER_PORT HelperPort ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PMP_SCAN_PARAMETERS scanParameters; BOOLEAN queueExAccess = TRUE; MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); MPASSERT(HelperPort->ScanContext.ActiveScanParameters != NULL); scanParameters = HelperPort->ScanContext.ActiveScanParameters; if (scanParameters->CancelScan) { // Scan is being cancelled, dont need to queue exclusive access MpTrace(COMP_SCAN, DBG_NORMAL, ("Ignored scan timer for cancelled/old scan request %p\n", scanParameters)); queueExAccess = FALSE; } else { scanParameters->State = SCAN_EXCLUSIVE_ACCESS_QUEUED; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (queueExAccess) { // // Queue an exclusive access. The scan would be done in there // ndisStatus = HelperPortRequestExclusiveAccess(HelperPort, HelperPortScanExAccessCallback, HelperPort->ScanContext.ActiveScanParameters, FALSE ); if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING)) { // Exclusive access request was rejected MpTrace(COMP_SCAN, DBG_SERIOUS, ("Exclusive access request in scan timer failed. Status = 0x%08x\n", ndisStatus)); HelperPortCompleteScanProcess( HelperPort, scanParameters, &ndisStatus ); } else if (NDIS_STATUS_SUCCESS == ndisStatus) { // the function completed synchronously, call the callback ourselves HelperPortScanExAccessCallback(HELPPORT_GET_MP_PORT(HelperPort), HelperPort->ScanContext.ActiveScanParameters); } } else { // Abort the scan ndisStatus = NDIS_STATUS_REQUEST_ABORTED; HelperPortCompleteScanProcess( HelperPort, scanParameters, &ndisStatus ); } }
VOID HelperPortProcessPendingScans( _In_ PMP_HELPER_PORT HelperPort ) { ULONG i; PMP_SCAN_PARAMETERS scanParameters = NULL; BOOLEAN processScan = FALSE; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; // Add this scan request to the list MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (HelperPort->ScanContext.ActiveScanParameters != NULL) { // There is already a scan in progress. We dont do anything here } else { // Search for a scan request in our list for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++) { if (HelperPort->ScanContext.ScanParameters[i].State == SCAN_QUEUED_FOR_PROCESSING) { // Found a scan request, we will queue it up scanParameters = &HelperPort->ScanContext.ScanParameters[i]; break; } } } // If there is an active scan, check if we should perform the scan if (scanParameters != NULL) { // Check if we should perform this scan processScan = HelperPortShouldPerformScan(HelperPort, scanParameters); if (processScan) { // Set this as the active scan HelperPort->ScanContext.ActiveScanParameters = scanParameters; scanParameters->State = SCAN_STARTED; } else { // We will successfully complete this scan without processing scanParameters->State = SCAN_REQUEST_IN_USE; } } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (scanParameters == NULL) { // Nothing to process, we are done return; } if (processScan) { // Start the scan HelperPortStartScanProcess(HelperPort, scanParameters); } else { // There is a scan request that wont do a scan for, complete it without // actually processing it ndisStatus = NDIS_STATUS_SUCCESS; MpTrace(COMP_SCAN, DBG_NORMAL, ("Vetoed a scan request\n")); // Now perform the indication HelperPortIndicateScanCompletion(HelperPort, scanParameters, &ndisStatus); // We reacquire the lock to ensure that the cancel does not conflict // with this completion MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // The scan is done scanParameters->State = SCAN_COMPLETED; HelperPortScanParametersReleaseRef(HelperPort, scanParameters); MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); } }
VOID HelperPortCancelScan( _In_ PMP_PORT Port, _In_ PMP_PORT RequestingPort ) { ULONG i; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); PMP_SCAN_PARAMETERS scanParameters = NULL; MP_SCAN_STATE preCancelState = SCAN_EMPTY_REQUEST; NDIS_STATUS ndisStatus; BOOLEAN timerCancelled = FALSE; // Add this scan request to the list MP_ACQUIRE_PORT_LOCK(Port, FALSE); // Search for the scan request in our list for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++) { if ((helperPort->ScanContext.ScanParameters[i].State != SCAN_EMPTY_REQUEST) && (helperPort->ScanContext.ScanParameters[i].State != SCAN_COMPLETED) && (helperPort->ScanContext.ScanParameters[i].RequestingPort == RequestingPort)) { // The scan request from this port is in the queue scanParameters = &helperPort->ScanContext.ScanParameters[i]; scanParameters->CancelScan = TRUE; // Add a refcount to ensure that the structure does not get deleted on us MP_INCREMENT_SCAN_PARAMETER_REF(scanParameters); preCancelState = scanParameters->State; // Save the previous state (for tracking) scanParameters->TrackingPreCancelState = preCancelState; if (preCancelState == SCAN_QUEUED_FOR_PROCESSING) { // This request is not yet activated for processing. // Remove the request from the pending scan list. This is done right now // with the lock held so that the request does not get requeued scanParameters->State = SCAN_REQUEST_IN_USE; MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling unprocessed scan request\n")); } else if (preCancelState == SCAN_EXCLUSIVE_ACCESS_QUEUED) { // We are unsure if the exclusive access request would // be granted or not. It would be granted if the cancel was part of // a pause or something. It would not be granted if this was // a halt MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling scan request waiting for exclusive access\n")); } break; } } MP_RELEASE_PORT_LOCK(Port, FALSE); if (scanParameters == NULL) { // No scan to cancel. return; } if (preCancelState != SCAN_QUEUED_FOR_PROCESSING) { // NOTE: Since we added the ref, we know that the ScanParameters buffer is available // If we have the timer running, force fire the timer timerCancelled = NdisCancelTimerObject(helperPort->ScanContext.Timer_Scan); if (timerCancelled == TRUE) { // We cancelled the timer, so we would need to invoke the complete ourselves MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling scan request waiting for scan timer\n")); HelperPortScanTimerCallback(helperPort); } else { // We could be waiting for exclusive access if (preCancelState == SCAN_EXCLUSIVE_ACCESS_QUEUED) { // We would complete the scan here. Because of the cancel flag, the // exclusive access routine would not proceed with the scan // if it got called ndisStatus = NDIS_STATUS_REQUEST_ABORTED; MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); // Clear the active pointer helperPort->ScanContext.ActiveScanParameters = NULL; scanParameters->State = SCAN_COMPLETED; MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); // Now perform the indication HelperPortIndicateScanCompletion(helperPort, scanParameters, &ndisStatus); // We dont remove the reference here. We wait for the ex or the scan // to do it } // Ask the HW to cancel the scan (if it has it) VNic11CancelScan(HELPPORT_GET_VNIC(helperPort)); } // Now wait for the scan complete to get indicated while (scanParameters->State != SCAN_COMPLETED) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Waiting for scan operation to complete\n")); NdisMSleep(20 * 1000); } // This lock is acquired to ensure that the free here does not conflict with an // in progress scan completion MP_ACQUIRE_PORT_LOCK(Port, FALSE); HelperPortScanParametersReleaseRef(helperPort, scanParameters); MP_RELEASE_PORT_LOCK(Port, FALSE); // If there is a different second scan pending, process it HelperPortProcessPendingScans(helperPort); } else { // This scan was never started, we need to complete the scan request & we are done ndisStatus = NDIS_STATUS_REQUEST_ABORTED; HelperPortIndicateScanCompletion(helperPort, scanParameters, &ndisStatus); MP_ACQUIRE_PORT_LOCK(Port, FALSE); scanParameters->State = SCAN_COMPLETED; HelperPortScanParametersReleaseRef(helperPort, scanParameters); MP_RELEASE_PORT_LOCK(Port, FALSE); } }
NDIS_STATUS HelperPortHandleScan( _In_ PMP_PORT Port, _In_ PMP_PORT RequestingPort, _In_ PMP_SCAN_REQUEST ScanRequest, _In_ PORT11_GENERIC_CALLBACK_FUNC CompletionHandler ) { PMP_SCAN_PARAMETERS scanParameters = NULL; // If we cannot find an empty slot, we return media in use NDIS_STATUS ndisStatus = NDIS_STATUS_DOT11_MEDIA_IN_USE; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); ULONG i; do { // Add this scan request to the pending scan list MP_ACQUIRE_PORT_LOCK(Port, FALSE); // Find a structure we can use for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++) { if (helperPort->ScanContext.ScanParameters[i].State == SCAN_EMPTY_REQUEST) { scanParameters = &helperPort->ScanContext.ScanParameters[i]; helperPort->ScanContext.ParametersCount++; MP_INCREMENT_SCAN_PARAMETER_REF(scanParameters); // Save the passed in information scanParameters->RequestingPort = RequestingPort; scanParameters->PortScanRequest = ScanRequest; scanParameters->CompletionHandler = CompletionHandler; // Scan would start at the first channel of the first phy scanParameters->NextChannelIndex = 0; scanParameters->CurrentPhyIndex = 0; // Queue it for processing scanParameters->CancelScan = 0; scanParameters->State = SCAN_QUEUED_FOR_PROCESSING; ndisStatus = NDIS_STATUS_SUCCESS; break; } } MP_RELEASE_PORT_LOCK(Port, FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("Unable to save scan parameters\n")); break; } // Let the scan request proceed HelperPortProcessPendingScans(helperPort); }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Free stuff that we may have allocated if (scanParameters != NULL) { // This cannot be left in our list HelperPortScanParametersReleaseRef(helperPort, scanParameters); } } return ndisStatus; }
// Called when scan on a set of channels is completed VOID HelperPortCompletePartialScan( _In_ PMP_HELPER_PORT HelperPort, _In_ PMP_SCAN_PARAMETERS ScanParameters, _In_ PNDIS_STATUS CompletionStatus ) { LARGE_INTEGER rescheduleTime; BOOLEAN requeueScan = TRUE; ULONG i; // release exclusive access HelperPortReleaseExclusiveAccess(HelperPort); // Determine the next step for scan MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (ScanParameters->PortScanRequest->ChannelCount != 0) { // All port specified channels are scanned in one shot requeueScan = FALSE; } else { // Determine if we are done with all the channels on current PHY if (ScanParameters->NextChannelIndex >= HelperPort->ScanContext.ScanChannels[ScanParameters->CurrentPhyIndex].ChannelCount) { // We are done with all phys on current channel, check if there is another // phy we need to scan requeueScan = FALSE; // Start with a negative for (i = ScanParameters->CurrentPhyIndex + 1; i < HW11_MAX_PHY_COUNT; i++) { if (HelperPort->ScanContext.ScanChannels[i].ChannelCount > 0) { // Found a phy to scan we will requeue the scan. requeueScan = TRUE; // Start from first channel on this new phy ScanParameters->CurrentPhyIndex = i; ScanParameters->NextChannelIndex = 0; } } } } if (ScanParameters->CancelScan) { // Cancelled requeueScan = FALSE; } if (requeueScan == FALSE) { // We will queuing the scan timer ScanParameters->State = SCAN_WAITING_FOR_TIMER; } if ((*CompletionStatus) != NDIS_STATUS_SUCCESS) { // Partial scan failed MpTrace(COMP_SCAN, DBG_NORMAL, ("Partial scan failed. Status = 0x%08x\n", (*CompletionStatus))); requeueScan = FALSE; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); MpTrace(COMP_SCAN, DBG_LOUD, ("Completed partial scan of %p\n", ScanParameters)); if (requeueScan) { if (HelperPort->ScanContext.MediaConnectedCount > 0) { // Queue the timer for another scan. We try to schedule this after one // context switch interval rescheduleTime.QuadPart = Int32x32To64(HelperPort->RegInfo->ScanRescheduleTime, -10000); } else { // Noboby is connected yet, Queue the timer for another scan rescheduleTime.QuadPart = Int32x32To64(MP_SCAN_RESCHEDULE_TIME_NOT_CONNECTED, -10000); } NdisSetTimerObject(HelperPort->ScanContext.Timer_Scan, rescheduleTime, 0, NULL); } else { // We have finished scanning all channels, call the scan completion HelperPortCompleteScanProcess( HelperPort, ScanParameters, CompletionStatus ); } }
// Scans a set of channels. Called with exclusive access held. Also only called when we have a channel // to scan. VOID HelperPortStartPartialScan( _In_ PMP_HELPER_PORT HelperPort, _In_ PMP_SCAN_PARAMETERS ScanParameters ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONG i, currentChannelCount; PMP_SCAN_CHANNEL_LIST currentChannelList; do { MpTrace(COMP_SCAN, DBG_LOUD, ("Starting partial scan of %p\n", ScanParameters)); MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); // Check if the request should be cancelled if (ScanParameters->CancelScan) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Aborting partial scan for cancelled/old scan request %p\n", ScanParameters)); ndisStatus = NDIS_STATUS_REQUEST_ABORTED; } else { // We are going to send this on the hardware ScanParameters->State = SCAN_HARDWARE_SCANNING; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // Determine the channels to scan. If specified by the port, use those, else // use our if (ScanParameters->PortScanRequest->ChannelCount != 0) { currentChannelCount = ScanParameters->PortScanRequest->ChannelCount; // // Populate the channels for this scan with what the port requested // ScanParameters->VNicScanRequest.ChannelCount = currentChannelCount; for (i = 0; i < currentChannelCount; i++) { ScanParameters->VNicScanRequest.ChannelList[i] = ScanParameters->PortScanRequest->ChannelList[i]; } ScanParameters->VNicScanRequest.PhyId = ScanParameters->PortScanRequest->PhyId; } else { currentChannelList = &HelperPort->ScanContext.ScanChannels[ScanParameters->CurrentPhyIndex]; // We must have atleast one channel in the current phy index that we can scan MPASSERT(currentChannelList->ChannelCount > ScanParameters->NextChannelIndex); // Determine the number of channels to use for this scan currentChannelCount = ScanParameters->MaxChannelCount; if ((ScanParameters->NextChannelIndex + currentChannelCount) > currentChannelList->ChannelCount) { // We have fewer remaining channels that our MaxChannelCount, adjust the channel count currentChannelCount = currentChannelList->ChannelCount - ScanParameters->NextChannelIndex; } // // Populate the channels for this scan // ScanParameters->VNicScanRequest.ChannelCount = currentChannelCount; for (i = 0; i < currentChannelCount; i++) { ScanParameters->VNicScanRequest.ChannelList[i] = currentChannelList->ChannelList[ScanParameters->NextChannelIndex + i]; } ScanParameters->VNicScanRequest.PhyId = currentChannelList->PhyId; // Next time we start scan at the next channel ScanParameters->NextChannelIndex = ScanParameters->NextChannelIndex + currentChannelCount; } ndisStatus = VNic11StartScan(HELPPORT_GET_VNIC(HelperPort), &ScanParameters->VNicScanRequest, HelperPortScanCompleteCallback ); if (ndisStatus == NDIS_STATUS_SUCCESS) { // the function completed synchronously - call the callback ourselves HelperPortScanCompleteCallback(HELPPORT_GET_MP_PORT(HelperPort), &ndisStatus); } else if (NDIS_STATUS_PENDING != ndisStatus) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("VNic11StartScan failed for channel index %d\n", ScanParameters->NextChannelIndex - currentChannelCount)); break; } } while (FALSE); if (ndisStatus != NDIS_STATUS_PENDING && ndisStatus != NDIS_STATUS_SUCCESS) { // We call the complete function HelperPortCompletePartialScan(HelperPort, ScanParameters, &ndisStatus); } }