// 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;
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 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, ¤tChannelList->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, ¤tChannelList->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, ¤tChannelList->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; }
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; }
// 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); } }