Пример #1
0
// BSS list lock acquired & called at Dispatch
NDIS_STATUS 
HelperPortUpdateBSSEntry(
    __in  PMP_HELPER_PORT        HelperPort,
    __in  PMP_BSS_ENTRY  pBSSEntry,
    __in  PMP_RX_MPDU        pFragment,
    __in  PDOT11_BEACON_FRAME pDot11BeaconPRFrame,
    __in  ULONG           BeaconPRDataLength
    )
{
    NDIS_STATUS         ndisStatus = NDIS_STATUS_SUCCESS;
    PDOT11_MGMT_HEADER  pMgmtPktHeader;
    ULONGLONG           ullHostTimeStamp;
    PVOID               pSavedBeaconPRBuffer = NULL;
    ULONG               uOffsetOfInfoElemBlob = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements);
    UCHAR               channel;
    DOT11_PHY_TYPE      PhyType;

    pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment);
    NdisGetCurrentSystemTime((PLARGE_INTEGER)&ullHostTimeStamp);
    
    do
    {
        // 
        // Modifying data in the AP entry
        //
        NdisDprAcquireSpinLock(&(pBSSEntry->Lock));

        if (pDot11BeaconPRFrame->Capability.IBSS)
        {
            pBSSEntry->Dot11BSSType = dot11_BSS_type_independent;
        }
        else
        {   
            pBSSEntry->Dot11BSSType = dot11_BSS_type_infrastructure;
        }
        
        //
        // Adhoc station can leave adhoc cell and create a new cell. SoftAPs
        // can move. This means the BSSID can change
        //
        NdisMoveMemory(
            pBSSEntry->Dot11BSSID,
            pMgmtPktHeader->BSSID,
            sizeof(DOT11_MAC_ADDRESS)
            );

        pBSSEntry->HostTimestamp = ullHostTimeStamp;
        pBSSEntry->BeaconTimestamp = pDot11BeaconPRFrame->Timestamp;
        pBSSEntry->BeaconInterval = pDot11BeaconPRFrame->BeaconInterval;
        pBSSEntry->Dot11Capability = pDot11BeaconPRFrame->Capability;
        pBSSEntry->RSSI = pFragment->Msdu->RecvContext.lRSSI;
        pBSSEntry->LinkQuality = pFragment->Msdu->LinkQuality;
        pBSSEntry->ChannelCenterFrequency 
            = pFragment->Msdu->RecvContext.uChCenterFrequency;

        //
        // If signal strength was below our threshold, catch that
        //
        if (pBSSEntry->LinkQuality < HelperPort->RegInfo->RSSILinkQualityThreshold)
        {
            pBSSEntry->LowQualityCount++;
        }
        else
        {
            pBSSEntry->LowQualityCount = 0;
        }

#if 0
        if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc)
        {
            MpTrace(COMP_ASSOC, DBG_LOUD, ("Received beacon from associated AP: %02X-%02X-%02X-%02X-%02X-%02X\n",
                pMgmtPktHeader->SA[0], pMgmtPktHeader->SA[1], pMgmtPktHeader->SA[2], 
                pMgmtPktHeader->SA[3], pMgmtPktHeader->SA[4], pMgmtPktHeader->SA[5]));
        }
#endif

        //
        // Get channel number at which the frame was received.
        //
        if (Dot11GetChannelForDSPhy(Add2Ptr(pDot11BeaconPRFrame, uOffsetOfInfoElemBlob),
                                    BeaconPRDataLength - uOffsetOfInfoElemBlob, 
                                    &channel) != NDIS_STATUS_SUCCESS)
        {
            channel = pFragment->Msdu->Channel;
        }

        if (channel != 0)
        {
            pBSSEntry->Channel = channel;
        }

        //
        // Get PhyType and PhyId
        //
        PhyType = VNic11DeterminePHYType(HELPPORT_GET_VNIC(HelperPort), 
                                       pBSSEntry->Dot11Capability,
                                       pBSSEntry->Channel);
        if (pBSSEntry->Dot11PhyType != PhyType)
        {
            pBSSEntry->Dot11PhyType = PhyType;
            pBSSEntry->PhyId = BasePortGetPhyIdFromType(HELPPORT_GET_MP_PORT(HelperPort), PhyType);
        }

        if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_BEACON)
        {
            //
            // Increase the beacon frame size if necessary
            //
            if (pBSSEntry->MaxBeaconFrameSize < BeaconPRDataLength)
            {
                MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, 
                    &pSavedBeaconPRBuffer, 
                    BeaconPRDataLength,
                    PORT_MEMORY_TAG
                    );
                    
                if (pSavedBeaconPRBuffer == NULL)
                {
                    //
                    // Unable to allocate memory for information elements.
                    // If this is a new AP entry, we wont be adding it to the list.
                    // For existing entries, we end up ignoring the new IE blob
                    //
                    ndisStatus = NDIS_STATUS_RESOURCES;
                    NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
                    break;
                }
                //
                // Delete any old blob buffer
                //
                if (pBSSEntry->pDot11BeaconFrame != NULL)
                {
                    MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame);
                }

                pBSSEntry->pDot11BeaconFrame = pSavedBeaconPRBuffer;
                pBSSEntry->MaxBeaconFrameSize = BeaconPRDataLength;
            }

            // Update the beacon
            pBSSEntry->BeaconFrameSize = BeaconPRDataLength;
            
            // Also save this as the IE blob pointer
            pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob;
            pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11BeaconFrame + uOffsetOfInfoElemBlob;
            
            //
            // Update/Save the beacon information element block
            //
            NdisMoveMemory(
                pBSSEntry->pDot11BeaconFrame,
                pDot11BeaconPRFrame,
                BeaconPRDataLength
                );
        }
    
        if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_PROBE_RESPONSE)
        {
            //
            // Increase the probe response frame size if necessary
            //
            if (pBSSEntry->MaxProbeFrameSize < BeaconPRDataLength)
            {
                MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, 
                    &pSavedBeaconPRBuffer, 
                    BeaconPRDataLength,
                    PORT_MEMORY_TAG
                    );
                    
                if (pSavedBeaconPRBuffer == NULL)
                {
                    //
                    // Unable to allocate memory for information elements.
                    // If this is a new AP entry, we wont be adding it to the list.
                    // For existing entries, we end up ignoring the new IE blob
                    //
                    ndisStatus = NDIS_STATUS_RESOURCES;
                    NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
                    break;
                }
                //
                // Delete any old blob buffer
                //
                if (pBSSEntry->pDot11ProbeFrame != NULL)
                {
                    MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame);
                }

                pBSSEntry->pDot11ProbeFrame = pSavedBeaconPRBuffer;
                pBSSEntry->MaxProbeFrameSize = BeaconPRDataLength;
            }
            
            pBSSEntry->ProbeFrameSize = BeaconPRDataLength;

            // Also save this as the IE blob pointer
            pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob;
            pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11ProbeFrame + uOffsetOfInfoElemBlob;

            //
            // Update/Save the beacon information element block
            //
            NdisMoveMemory(
                pBSSEntry->pDot11ProbeFrame,
                pDot11BeaconPRFrame,
                BeaconPRDataLength
                );

        }

#if 0
        if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc)
        {
            MpTrace(COMP_SCAN, DBG_LOUD, ("Received %d for AP %02X-%02X-%02X-%02X-%02X-%02X \n", 
                    pMgmtPktHeader->FrameControl.Subtype,
                    pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], 
                    pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5]));
        }
#endif

        //
        // Done with our modification of the AP entry
        //
        NdisDprReleaseSpinLock(&(pBSSEntry->Lock));
        
    } while (FALSE);

    return ndisStatus;
Пример #2
0
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);        
    }

}
Пример #3
0
NDIS_STATUS
HelperPortCreateScanChannelList(
    _In_  PMP_HELPER_PORT         HelperPort
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    ULONG                       phyId, channelListIndex = 0;
    PDOT11_SUPPORTED_PHY_TYPES  supportedPhyTypes;
    UCHAR                       buffer[(sizeof(DOT11_SUPPORTED_PHY_TYPES) + 
                                    sizeof(DOT11_PHY_TYPE) * HW11_MAX_PHY_COUNT)];  
    PMP_SCAN_CHANNEL_LIST       currentChannelList;
    DOT11_PHY_TYPE              bgScanPhy;

    do
    {
        //
        // Get supported PHY types.
        //
        supportedPhyTypes = (PDOT11_SUPPORTED_PHY_TYPES) buffer;
        supportedPhyTypes->uNumOfEntries = 0;
        VNic11QuerySupportedPHYTypes(HELPPORT_GET_VNIC(HelperPort), 
            HW11_MAX_PHY_COUNT, 
            supportedPhyTypes
            );

        //
        // For devices supporting both b & g phys, we only scan on g. Check if
        // we need to do this here
        //
        bgScanPhy = dot11_phy_type_hrdsss;
        for (phyId = 0; phyId < supportedPhyTypes->uNumOfEntries; phyId++)
        {
            if (supportedPhyTypes->dot11PHYType[phyId] == dot11_phy_type_erp)
            {
                // Support g, no need to scan b
                bgScanPhy = dot11_phy_type_erp;
                break;
            }
        }        

        //
        // Go through the list to see if there is a phy type we scan for
        //
        for (phyId = 0; phyId < supportedPhyTypes->uNumOfEntries; phyId++)
        {
            // We only scan on g(or b) & a phy
            if ((supportedPhyTypes->dot11PHYType[phyId] == bgScanPhy) ||
                (supportedPhyTypes->dot11PHYType[phyId] == dot11_phy_type_ofdm))
            {
                // Query for the channel list
                currentChannelList = &HelperPort->ScanContext.ScanChannels[channelListIndex];

                // Start with a zero length buffer to determine the size
                currentChannelList->ChannelCount = 0;
                ndisStatus = VNic11QuerySupportedChannels(HELPPORT_GET_VNIC(HelperPort), 
                                    phyId,
                                    &currentChannelList->ChannelCount, 
                                    NULL
                                    );
                if (ndisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)
                {
                    MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Unable to query size of the channel list for phy ID %d\n", phyId));    
                    // We skip this PHY
                    ndisStatus = NDIS_STATUS_SUCCESS;
                    break;
                }
                
                MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle,
                    &currentChannelList->ChannelList,
                    currentChannelList->ChannelCount * sizeof(ULONG),
                    PORT_MEMORY_TAG
                    );
                if (currentChannelList->ChannelList == NULL)
                {
                    MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Unable to allocate memory for the channel list for phy ID %d\n", phyId));
                    ndisStatus = NDIS_STATUS_RESOURCES;
                    break;
                }

                // Query again
                ndisStatus = VNic11QuerySupportedChannels(HELPPORT_GET_VNIC(HelperPort), 
                                    phyId,
                                    &currentChannelList->ChannelCount, 
                                    currentChannelList->ChannelList
                                    );
                if (ndisStatus != NDIS_STATUS_SUCCESS)
                {
                    MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Unable to query channel list for phy ID %d\n", phyId));
                    break;
                }

                currentChannelList->PhyId = phyId;
                
                // Populated one set of channels
                channelListIndex++;
            }

            if (ndisStatus != NDIS_STATUS_SUCCESS)
            {
                break;
            }
        }
    } while (FALSE);

    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        for (channelListIndex = 0; channelListIndex < HW11_MAX_PHY_COUNT; channelListIndex++)
        {
            if (HelperPort->ScanContext.ScanChannels[channelListIndex].ChannelList != NULL)
            {
                MP_FREE_MEMORY(HelperPort->ScanContext.ScanChannels[channelListIndex].ChannelList);
                HelperPort->ScanContext.ScanChannels[channelListIndex].ChannelList = NULL;
            }
        }
    }

    return ndisStatus;
}
Пример #4
0
NDIS_STATUS
HelperPortInitializeScanContext(
    _In_  PMP_HELPER_PORT         HelperPort
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NDIS_TIMER_CHARACTERISTICS  timerChar;               
    ULONG                       i;
    do
    {
        HelperPort->ScanContext.ActiveScanParameters = NULL;

        // Allocate the power save timeout call back
        NdisZeroMemory(&timerChar, sizeof(NDIS_TIMER_CHARACTERISTICS));
        
        timerChar.Header.Type = NDIS_OBJECT_TYPE_TIMER_CHARACTERISTICS;
        timerChar.Header.Revision = NDIS_TIMER_CHARACTERISTICS_REVISION_1;
        timerChar.Header.Size = sizeof(NDIS_TIMER_CHARACTERISTICS);
        timerChar.AllocationTag = PORT_MEMORY_TAG;
        
        timerChar.TimerFunction = HelperPortScanTimer;
        timerChar.FunctionContext = HelperPort;

        ndisStatus = NdisAllocateTimerObject(
                        HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle,
                        &timerChar,
                        &HelperPort->ScanContext.Timer_Scan
                        );
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate helper port scan timer\n"));
            break;
        }

        //
        // Get list of channels we would scan
        //
        ndisStatus = HelperPortCreateScanChannelList(HelperPort);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to create helper port scan list\n"));
            break;
        }        

        // Initialize the preallocated scan parameter structures
        for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++)
        {
            NdisZeroMemory(&HelperPort->ScanContext.ScanParameters[i], sizeof(MP_SCAN_PARAMETERS));
            
            HelperPort->ScanContext.ScanParameters[i].State = SCAN_EMPTY_REQUEST;
            HelperPort->ScanContext.ScanParameters[i].UsageCount = 0;
        }

        // To maintain the scan list, we need to receive all beacons and probe responses. Set the
        // appropriate packet filter
        VNic11SetPacketFilter(HELPPORT_GET_VNIC(HelperPort), 
            NDIS_PACKET_TYPE_802_11_BROADCAST_MGMT | NDIS_PACKET_TYPE_802_11_DIRECTED_MGMT
            );
        
    }while (FALSE);

    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        if (HelperPort->ScanContext.Timer_Scan)
        {
            NdisFreeTimerObject(HelperPort->ScanContext.Timer_Scan);
            HelperPort->ScanContext.Timer_Scan = NULL;
        }
    
        for (i = 0; i < HW11_MAX_PHY_COUNT; i++)
        {
            if (HelperPort->ScanContext.ScanChannels[i].ChannelList != NULL)
            {
                MP_FREE_MEMORY(HelperPort->ScanContext.ScanChannels[i].ChannelList);
                HelperPort->ScanContext.ScanChannels[i].ChannelList = NULL;
            }
        }

    }
    
    return ndisStatus;
}
Пример #5
0
// 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);
    }
}