NDIS_STATUS Hw11FindNic( __in PHW Hw, __out NDIS_ERROR_CODE* ErrorCode, __out PULONG ErrorValue ) { ULONG size; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; UCHAR buffer[HW11_PCI_CONFIG_BUFFER_LENGTH]; PPCI_COMMON_CONFIG pciConfig = (PPCI_COMMON_CONFIG) buffer; // // Make sure adapter is present on the bus. // If present,verify the PCI configuration values. // do { // Load the PCI config information into our local buffer size = NdisMGetBusData(Hw->MiniportAdapterHandle, PCI_WHICHSPACE_CONFIG, FIELD_OFFSET(PCI_COMMON_CONFIG,VendorID), pciConfig, HW11_PCI_CONFIG_BUFFER_LENGTH ); if (size != HW11_PCI_CONFIG_BUFFER_LENGTH) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("NdisReadPciSlotInformation failed. Number of bytes of PCI config info returned is %d\n", size)); *ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND; *ErrorValue = ERRLOG_READ_PCI_SLOT_FAILED; ndisStatus = NDIS_STATUS_ADAPTER_NOT_FOUND; break; } // // We have read the hardware ID, etc. Create the appropriate HAL // object that corresponds to our hardware. This allocates the HAL // structure and populates the HAL function pointers // #ifdef EXPORT_DRIVER_HAL // Invoke the export driver ndisStatus = HalDriverCreateWLANHal(Hw->MiniportAdapterHandle, pciConfig->VendorID, pciConfig->DeviceID, pciConfig->RevisionID, &Hw->Hal ); #else // Invoke the HAL library ndisStatus = HalCreateWLANHal(Hw->MiniportAdapterHandle, pciConfig->VendorID, pciConfig->DeviceID, pciConfig->RevisionID, &Hw->Hal ); #endif if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HalCreateWLANHal failed. Status = 0x%08x\n", ndisStatus)); *ErrorCode = NDIS_ERROR_CODE_ADAPTER_NOT_FOUND; *ErrorValue = ERRLOG_VENDOR_DEVICE_MISMATCH; break; } // // Let the HAL layer read the registry. This may depend on the NIC // and hence we do this here after we have found the NIC and create the HAL // and not during the first Hw11ReadRegistryConfiguration call // ndisStatus = HalReadRegistryConfiguration(Hw->Hal); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Read registry should only fail for test purposes. If registry data is invalid the // driver should load the defaults and NOT fail driver initialize MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HalReadRegistryConfiguration failed. Status = 0x%08x\n", ndisStatus)); MPASSERT(ndisStatus == NDIS_STATUS_RESOURCES); } // // Allow the HAL to look at PCI config information. This may also modify the // HAL // ndisStatus = HalParsePciConfiguration(Hw->Hal, buffer, size); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HalParsePciConfiguration failed. Status = 0x%08x\n", ndisStatus)); *ErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; *ErrorValue = ERRLOG_INVALID_PCI_CONFIGURATION; break; } }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // The only thing done so far is create the WLAN hal if (Hw->Hal != NULL) { HalFreeNic(Hw->Hal); Hw->Hal = NULL; } } return ndisStatus; }
USHORT HwSelectTXDataRate( __in PHW_MAC_CONTEXT HwMac, __in PDOT11_RATE_SET RemoteRateSet, __in ULONG LinkQuality ) { PDOT11_RATE_SET operationalRateSet; PDOT11_RATE_SET activeRateSet; ULONG indexLocalRates; ULONG indexRemoteRates; USHORT maximumRate; OP_RATE_CHANGE_NOTIFICATION rateNotification; // The active rate set structure needs to be protected HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); // // Select the best rate supported by both AP and us. // operationalRateSet = &(HwMac->PhyContext[HwMac->OperatingPhyId].OperationalRateSet); activeRateSet = &(HwMac->PhyContext[HwMac->OperatingPhyId].ActiveRateSet); activeRateSet->uRateSetLength = 0; // // We merge the rates from the AP and the client to create the // currently active data rates table // for (indexLocalRates = 0; indexLocalRates < operationalRateSet->uRateSetLength; indexLocalRates++) { for (indexRemoteRates = 0; indexRemoteRates < RemoteRateSet->uRateSetLength; indexRemoteRates++) { if (operationalRateSet->ucRateSet[indexLocalRates] == (RemoteRateSet->ucRateSet[indexRemoteRates] & 0x7f)) { activeRateSet->ucRateSet[activeRateSet->uRateSetLength] = operationalRateSet->ucRateSet[indexLocalRates]; activeRateSet->uRateSetLength++; break; } } } // // If we dont find any rates, we will stick with our management packet rate // if (activeRateSet->uRateSetLength == 0) { activeRateSet->ucRateSet[0] = (UCHAR)HalGetBeaconRate(HwMac->Hw->Hal, HwMac->OperatingPhyId); activeRateSet->uRateSetLength = 1; } else if (activeRateSet->uRateSetLength > 1) { // bubble sort data rates in ascending order INT i, j; UCHAR temp; for (i = activeRateSet->uRateSetLength - 1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (activeRateSet->ucRateSet[j - 1] > activeRateSet->ucRateSet[j]) { temp = activeRateSet->ucRateSet[j - 1]; activeRateSet->ucRateSet[j - 1] = activeRateSet->ucRateSet[j]; activeRateSet->ucRateSet[j] = temp; } } } } // // Now that the active rate set is populated and updated, select // the best rate // // // Determine what the maximum TX rate should be // maximumRate = HW11_MAX_DATA_RATE; // Start with max supported by HW if (LinkQuality < HW_LOW_RATE_LINK_QUALITY_THRESHOLD) { // // The link quality is low, we will go for the lower start rate instead of // the max supported. The hardware does rate fallback, so we pick // something that would cause the least number of retrys // maximumRate = HW_LOW_RATE_MAX_DATA_RATE; } // // Check if this is greater than max permitted value read from the registry // if (maximumRate > HwMac->Hw->RegInfo.MaximumTxRate) { maximumRate = (USHORT)HwMac->Hw->RegInfo.MaximumTxRate; } // // Now find the best matching rate between us and the AP // for (indexLocalRates = activeRateSet->uRateSetLength - 1; indexLocalRates > 0; indexLocalRates--) { // // Check for a rate supported by both us and the AP that is below the max we prefer to use // if (activeRateSet->ucRateSet[indexLocalRates] <= maximumRate) { // // Found the rate we want to use // break; } } HwMac->DefaultTXDataRate = activeRateSet->ucRateSet[indexLocalRates]; // Update our rate info table. In our current implementation this is not-per peer HwMac->RateInfo.CurrentTXDataRate = HwMac->DefaultTXDataRate; MpTrace(COMP_ASSOC, DBG_LOUD, ("TX Data rate: %d\n", HwMac->DefaultTXDataRate)); HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); // // Indicate NDIS_STATUS_LINK_STATE to inform the OS about the new // link speed // HwIndicateLinkSpeed(HwMac, HwMac->DefaultTXDataRate); // Indicate change of link speed to the port so that it // can take any necessary action rateNotification.Header.Type = NotificationOpRateChange; rateNotification.Header.Size = sizeof(OP_RATE_CHANGE_NOTIFICATION); rateNotification.Header.pSourceVNic = NULL; rateNotification.NewRate = HwMac->DefaultTXDataRate; rateNotification.OldRate = 0; rateNotification.LowestRate = FALSE; VNic11Notify(HwMac->VNic, &rateNotification); return (UCHAR)HwMac->DefaultTXDataRate; }
NDIS_STATUS Hw11Allocate( __in NDIS_HANDLE MiniportAdapterHandle, __deref_out_opt PHW* Hw, __in PADAPTER Adapter ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PHW newHw = NULL; ULONG size; NDIS_TIMER_CHARACTERISTICS timerChar; *Hw = NULL; do { // Allocate a HW data structure MP_ALLOCATE_MEMORY(MiniportAdapterHandle, &newHw, sizeof(HW), HW_MEMORY_TAG); if (newHw == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate %d bytes for HW\n", sizeof(HW))); ndisStatus = NDIS_STATUS_RESOURCES; break; } // Clear everything NdisZeroMemory(newHw, sizeof(HW)); // We start in the PAUSED state HW_SET_ADAPTER_STATUS(newHw, HW_ADAPTER_PAUSED); newHw->InterruptDisableCount = 1; // Since we are paused, we want the interrupts to be disabled #if DBG NdisInterlockedIncrement(&newHw->Tracking_InterruptDisable[HW_ISR_TRACKING_PAUSE]); #endif // Allocate memory for fields inside the HW structure size = sizeof(DOT11_REG_DOMAINS_SUPPORT_VALUE) + (HW_MAX_NUM_DOT11_REG_DOMAINS_VALUE - 1) * sizeof(DOT11_REG_DOMAIN_VALUE); MP_ALLOCATE_MEMORY(MiniportAdapterHandle, &(newHw->PhyState.RegDomainsSupportValue), size, HW_MEMORY_TAG); if (newHw->PhyState.RegDomainsSupportValue == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate memory for RegDomainsSupportValue\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } NdisZeroMemory(newHw->PhyState.RegDomainsSupportValue, size); size = sizeof(DOT11_DIVERSITY_SELECTION_RX_LIST) + (HW_MAX_NUM_DIVERSITY_SELECTION_RX_LIST - 1) * sizeof(DOT11_DIVERSITY_SELECTION_RX); MP_ALLOCATE_MEMORY(MiniportAdapterHandle, &(newHw->PhyState.DiversitySelectionRxList), size, HW_MEMORY_TAG); if (newHw->PhyState.DiversitySelectionRxList == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate memory for DiversitySelectionRxList\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } NdisZeroMemory(newHw->PhyState.DiversitySelectionRxList, size); NdisZeroMemory(&timerChar, sizeof(NDIS_TIMER_CHARACTERISTICS)); // Allocate the power save wake timer 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 = HW_MEMORY_TAG; timerChar.TimerFunction = HwAwakeTimer; timerChar.FunctionContext = newHw; ndisStatus = NdisAllocateTimerObject( MiniportAdapterHandle, &timerChar, &newHw->PhyState.Timer_Awake ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate power save awake timer\n")); break; } // Allocate the power save sleep timer timerChar.TimerFunction = HwDozeTimer; timerChar.FunctionContext = newHw; ndisStatus = NdisAllocateTimerObject( MiniportAdapterHandle, &timerChar, &newHw->PhyState.Timer_Doze ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate power save doze timer\n")); break; } // Allocate the scan timer timerChar.TimerFunction = HwScanTimer; timerChar.FunctionContext = newHw; ndisStatus = NdisAllocateTimerObject( MiniportAdapterHandle, &timerChar, &newHw->ScanContext.Timer_Scan ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate scan timer\n")); break; } newHw->PhyState.PhyProgramWorkItem = NdisAllocateIoWorkItem(MiniportAdapterHandle); if(newHw->PhyState.PhyProgramWorkItem == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate channel switch work item\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } // The hardware lock NdisAllocateSpinLock(&newHw->Lock); // Save the Adapter pointer in the HW newHw->Adapter = Adapter; newHw->MiniportAdapterHandle = MiniportAdapterHandle; // Return the newly created structure to the caller *Hw = newHw; } while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { if (newHw != NULL) { Hw11Free(newHw); } } return ndisStatus; }
/** This implementation picks the NDIS 6.2 Read/Write lock structures & API on OS versions where NDIS support those and would pick the older API on NDIS 6.0. Since the new API are not available on NDIS 6.0 OS, it does not link the new API into the binary, instead it dynamically loads the API address & uses them. This way the same binary can run on both NDIS 6.0 & 6.2 OSes, using the correct API for that OS. */ NDIS_STATUS MpDetermineRWLockType() { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONG ndisVersion; NDIS_STRING allocateRoutineName; NDIS_STRING freeRoutineName; NDIS_STRING acquireReadRoutineName; NDIS_STRING acquireWriteRoutineName; NDIS_STRING releaseRoutineName; do { NdisZeroMemory(&GlobalRWLockHandlers, sizeof(MP_RW_LOCK_HANDLERS)); // Start with pre NDIS 6.2 using the old API. If this is NDIS 6.2+ and // we cannot find address of new API, we will fail GlobalRWLockHandlers.AllocateHandler = MpAllocateOldRWLock; GlobalRWLockHandlers.FreeHandler = MpFreeOldRWLock; GlobalRWLockHandlers.AcquireReadHandler = MpAcquireOldRWLockForRead; GlobalRWLockHandlers.AcquireWriteHandler = MpAcquireOldRWLockForWrite; GlobalRWLockHandlers.ReleaseHandler = MpReleaseOldRWLock; ndisVersion = NdisGetVersion(); if (ndisVersion > MP_NDIS_VERSION_NEEDS_COMPATIBILITY) { // NDIS 6.2 or above. Use the new API // Load the address of the new NDisRead/Write lock API NdisInitUnicodeString(&allocateRoutineName, L"NdisAllocateRWLock"); NdisInitUnicodeString(&freeRoutineName, L"NdisFreeRWLock"); NdisInitUnicodeString(&acquireReadRoutineName, L"NdisAcquireRWLockRead"); NdisInitUnicodeString(&acquireWriteRoutineName, L"NdisAcquireRWLockWrite"); NdisInitUnicodeString(&releaseRoutineName, L"NdisReleaseRWLock"); *((PVOID *)&MpNdisAllocateRWLock) = NdisGetRoutineAddress(&allocateRoutineName); if (MpNdisAllocateRWLock == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to find address of NdisAllocateRWLock\n")); break; } *((PVOID *)&MpNdisFreeRWLock) = NdisGetRoutineAddress(&freeRoutineName); if (MpNdisFreeRWLock == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to find address of NdisFreeRWLock\n")); break; } *((PVOID *)&MpNdisAcquireRWLockRead) = NdisGetRoutineAddress(&acquireReadRoutineName); if (MpNdisAcquireRWLockRead == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to find address of NdisAcquireRWLockRead\n")); break; } *((PVOID *)&MpNdisAcquireRWLockWrite) = NdisGetRoutineAddress(&acquireWriteRoutineName); if (MpNdisAcquireRWLockWrite == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to find address of NdisAcquireRWLockWrite\n")); break; } *((PVOID *)&MpNdisReleaseRWLock) = NdisGetRoutineAddress(&releaseRoutineName); if (MpNdisReleaseRWLock == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to find address of NdisReleaseRWLock\n")); break; } // Set our pointers GlobalRWLockHandlers.AllocateHandler = MpAllocateNewRWLock; GlobalRWLockHandlers.FreeHandler = MpFreeNewRWLock; GlobalRWLockHandlers.AcquireReadHandler = MpAcquireNewRWLockForRead; GlobalRWLockHandlers.AcquireWriteHandler = MpAcquireNewRWLockForWrite; GlobalRWLockHandlers.ReleaseHandler = MpReleaseNewRWLock; } }while (FALSE); 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 ); } }
NDIS_STATUS Hw11Start( __in PHW Hw, __out NDIS_ERROR_CODE* ErrorCode, __out PULONG ErrorValue ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN interruptRegistered = FALSE, hardwareStarted = FALSE; // // Disable interrupts // We should disable interrupts before the are registered. // They will be enabled right at the end of Initialize // HwDisableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); do { // // Register interrupt with NDIS // ndisStatus = HwRegisterInterrupt( Hw, ErrorCode, ErrorValue ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to register interrupt with NDIS\n")); break; } interruptRegistered = TRUE; Hw->PhyState.Debug_SoftwareRadioOff = Hw->PhyState.SoftwareRadioOff; if (Hw->PhyState.SoftwareRadioOff) { HalSetRFPowerState(Hw->Hal, RF_SHUT_DOWN); } else { HalSetRFPowerState(Hw->Hal, RF_ON); } // // Start the HAL. If anything fails after this point, // we must issue a Halt to the HAL before returning // from initialize // ndisStatus = HalStart(Hw->Hal, FALSE); if(ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to start HAL successfully.\n")); break; } hardwareStarted = TRUE; // Enable the interrupts on the hardware HwEnableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Disable interrupts and deregister them first HwDisableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); if (interruptRegistered) HwDeregisterInterrupt(Hw); if (hardwareStarted) { HalStop(Hw->Hal); HalHaltNic(Hw->Hal); } } return ndisStatus; }
NDIS_STATUS HelperPortInsertBSSEntry( __in PMP_HELPER_PORT HelperPort, __in PMP_RX_MPDU pFragment, __in PDOT11_BEACON_FRAME pDot11BeaconFrame, __in ULONG BeaconDataLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONGLONG ullHostTimeStamp; MP_RW_LOCK_STATE LockState; PMP_BSS_ENTRY pBSSEntry = NULL; PDOT11_MGMT_HEADER pMgmtPktHeader; BOOLEAN bNewAp = FALSE; PMP_BSS_LIST pDiscoveredBSSList = &(HelperPort->BSSList); pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment); NdisGetCurrentSystemTime((PLARGE_INTEGER)&ullHostTimeStamp); // // We acquire the write lock as we are adding entries to the list // MP_ACQUIRE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); do { // // Check again if this entry already exists in the list. This is to handle // if the AP was added since we first checked (possible if the // flush routine was running) // pBSSEntry = HelperPortFindBSSEntry( pDiscoveredBSSList, pMgmtPktHeader->SA ); if (pBSSEntry == NULL) { bNewAp = TRUE; // New AP // // We havent found this AP yet, we would add it to the list // if (pDiscoveredBSSList->NumOfBSSEntries >= pDiscoveredBSSList->MaxNumOfBSSEntries) { // // We need to replace an entry thats in the list // pBSSEntry = HelperPortExpireBSSEntry( pDiscoveredBSSList, HelperPort->RegInfo->BSSEntryExpireTime, ullHostTimeStamp ); if (pBSSEntry != NULL) { // // Add initial in-use refcount // pBSSEntry->RefCount = 1; } // // Dont zero out the AP entry so that we can // reuse the info element blob // } else { // // Create a new entry for this AP // MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, &pBSSEntry, sizeof(MP_BSS_ENTRY), PORT_MEMORY_TAG ); if (pBSSEntry != NULL) { // // Initialize the new entry // NdisZeroMemory(pBSSEntry, sizeof(MP_BSS_ENTRY)); pBSSEntry->RefCount = 1; // Add initial in-use refcount NdisAllocateSpinLock(&(pBSSEntry->Lock)); } } if (pBSSEntry == NULL) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("Not enough space to add 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])); ndisStatus = NDIS_STATUS_RESOURCES; break; } // // This Entry is not yet in the list // // We will be updating the beacon & probe response frames pBSSEntry->BeaconFrameSize = 0; pBSSEntry->ProbeFrameSize = 0; pBSSEntry->AssocCost = 0; NdisMoveMemory( pBSSEntry->Dot11BSSID, pMgmtPktHeader->BSSID, sizeof(DOT11_MAC_ADDRESS) ); NdisMoveMemory( pBSSEntry->MacAddress, pMgmtPktHeader->SA, sizeof(DOT11_MAC_ADDRESS) ); } // Update the information in this BSS entry (either new or reused entry) ndisStatus = HelperPortUpdateBSSEntry( HelperPort, pBSSEntry, pFragment, pDot11BeaconFrame, BeaconDataLength ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // // Add the new BSS to our list // if (bNewAp) { MpTrace(COMP_SCAN, DBG_LOUD, ("AP %02X-%02X-%02X-%02X-%02X-%02X at channel: %d (%d)\n", pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5], pBSSEntry->Channel, pFragment->Msdu->Channel)); HelperPortAddBSSEntry(pDiscoveredBSSList, pBSSEntry); } // // Note: If any code is added below here, remember to remove entry // from the list // } while (FALSE); MP_RELEASE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Free the new entry we may have created if ((bNewAp) && (pBSSEntry != NULL)) { if (pBSSEntry->pDot11BeaconFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame); pBSSEntry->pDot11BeaconFrame = NULL; pBSSEntry->BeaconFrameSize = 0; pBSSEntry->MaxBeaconFrameSize= 0; } if (pBSSEntry->pDot11ProbeFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame); pBSSEntry->pDot11ProbeFrame = NULL; pBSSEntry->ProbeFrameSize = 0; pBSSEntry->MaxProbeFrameSize= 0; } pBSSEntry->pDot11InfoElemBlob = NULL; pBSSEntry->InfoElemBlobSize = 0; MP_FREE_MEMORY(pBSSEntry); } } return 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 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 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); } }
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); } }
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; }
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; }
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 Hw11DiscoverNicResources( __in PHW Hw, __in PNDIS_RESOURCE_LIST ResList, __out NDIS_ERROR_CODE* ErrorCode, __out PULONG ErrorValue ) { ULONG index; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN resPort = FALSE, resInterrupt = FALSE, resMemory = FALSE; PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc; do { for(index=0; index < ResList->Count; index++) { resDesc = &ResList->PartialDescriptors[index]; // // Notify Hw11 about the resources found // ndisStatus = HalAddAdapterResource(Hw->Hal, resDesc); // // If the resource was successfully accepted, remember its type // if (ndisStatus == NDIS_STATUS_SUCCESS) { switch(resDesc->Type) { case CmResourceTypePort: resPort = TRUE; break; case CmResourceTypeInterrupt: resInterrupt = TRUE; break; case CmResourceTypeMemory: resMemory = TRUE; break; } } else if(ndisStatus != NDIS_STATUS_NOT_ACCEPTED) { // // This is an unrecoverable error. The Hw11 probably came across a resource // that caused fatal error while being mapped or used. Details about the // the failure should be in the event log. Bail out. // MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to add adapter resource. Status = 0x%08x\n", ndisStatus)); break; } } // // Make sure that the hardware has found its port, interrupt and memory resources. // If any of them is missing, fail initialization // if(!resInterrupt || !resMemory) { ndisStatus = NDIS_STATUS_RESOURCE_CONFLICT; *ErrorCode = NDIS_ERROR_CODE_RESOURCE_CONFLICT; if(!resPort) *ErrorValue = ERRLOG_NO_IO_RESOURCE; else if(!resInterrupt) *ErrorValue = ERRLOG_NO_INTERRUPT_RESOURCE; else *ErrorValue = ERRLOG_NO_MEMORY_RESOURCE; break; } } while(FALSE); return ndisStatus; }
void SocTransport::OnTimer(long tCurrent) { // If we're Advertising broadcast a SERVERINFO message if (m_socBroadcast != INVALID_SOCKET) { sockaddr_in soca; soca.sin_family = AF_INET; #ifdef IPHONE soca.sin_addr.s_addr = INADDR_BROADCAST; #else soca.sin_addr.S_un.S_addr = INADDR_BROADCAST; #endif ServerInfoNetMessage nm(m_szGameName); MpTrace("> %s", PszFromNetMessage(&nm)); // Broadcast to 4 ports to support running 4 clients on the same machine for (int i = 0; i < 4; i++) { soca.sin_port = htons(SERVERINFO_BROADCAST_PORT + i); if (sendto(m_socBroadcast, (char *)&nm, sizeof(nm), 0, (sockaddr *)&soca, sizeof(soca)) == SOCKET_ERROR) { #ifdef DEBUG HostMessageBox(TEXT("sendto err: %s"), PszFromSocError()); #endif } } } // If we're searching for hosts check for receipt of a SERVERINFO message if (m_socBroadcastListen != INVALID_SOCKET) { NetAddress nad; #ifdef IPHONE socklen_t cbSocaServer = sizeof(nad); #else int cbSocaServer = sizeof(nad); #endif ServerInfoNetMessage sinm; if (recvfrom(m_socBroadcastListen, (char *)&sinm, sizeof(sinm), 0, (sockaddr *)&nad, &cbSocaServer) == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT) { #ifdef DEBUG HostMessageBox(TEXT("recvfrom err: %s"), PszFromSocError(err)); // UNDONE: If we discover any errors that would cause us to want to abort the // game search operation... // if (m_ptcb != NULL) // m_ptcb->OnTransportError(ktraeGameSearchFailed); #endif return; } } else { MpTrace("< GAMEHOSTFOUND"); if (m_fBlockNextGameHost) return; // Fill in a NetAddress ourselves so we can be sure no random numbers are present NetAddress nadT; memset(&nadT, 0, sizeof(nadT)); // HACK: this is the port the game is going to want to connect to ((sockaddr_in *)&nadT)->sin_port = htons(SERVER_LISTEN_PORT); ((sockaddr_in *)&nadT)->sin_family = ((sockaddr_in *)&nad)->sin_family; ((sockaddr_in *)&nadT)->sin_addr = ((sockaddr_in *)&nad)->sin_addr; if (m_ptcb != NULL) { m_fBlockNextGameHost = true; m_ptcb->OnGameHostFound(&nadT); } } } }
NDIS_STATUS Hw11Initialize( __in PHW Hw, __in PHVL Hvl, __out NDIS_ERROR_CODE* ErrorCode, __out PULONG ErrorValue ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; Hw->Hvl = Hvl; do { // // Initialize the HAL layer // ndisStatus = HalInitialize(Hw->Hal); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HalInitialize failed. Status = 0x%08x\n", ndisStatus)); break; } // // Read the HW capabilities // HalGetPowerSaveCapabilities(Hw->Hal, &Hw->MacState.HalPowerSaveCapability); // // Reset our state to its initial value // HwResetSoftwareMacState(Hw); // Resets the software data HwResetSoftwarePhyState(Hw); // Resets the software data NdisZeroMemory(&Hw->Stats, sizeof(NIC_STATISTICS)); // // Clear any stale state from the hardware // ndisStatus = HwClearNicState(Hw); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HwClearNicState failed. Status = 0x%08x\n", ndisStatus)); break; } // // Program our new state on the hardware // ndisStatus = HwSetNicState(Hw); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HwSetNicState failed. Status = 0x%08x\n", ndisStatus)); break; } // // Initialize the scatter gather DMA with NDIS for send. This also allocates stuff // for receive shared memory allocation // ndisStatus = HwInitializeScatterGatherDma(Hw, ErrorCode, ErrorValue); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } } while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // // Deregister the DMA from NDIS // if (Hw->MiniportDmaHandle != NULL) { NdisMDeregisterScatterGatherDma(Hw->MiniportDmaHandle); } } return ndisStatus; }
Connection *SocTransport::AsyncConnect(NetAddress *pnad) { MpTrace("AsyncConnect(%s)", pnad != NULL ? inet_ntoa(((sockaddr_in *)pnad)->sin_addr) : "loopback"); Connection *pcon; // A NULL pnad means this device is the server and is now trying to // connect to itself as a client. Use the LoopbackConnection to satisfy // this. if (pnad == NULL) { pcon = new LoopbackConnection(this); Assert(pcon != NULL, "out of memory!"); if (pcon == NULL) return NULL; m_fAsyncConnectLoopback = true; } else { // Create the socket for connecting to the server SOCKET soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (soc == INVALID_SOCKET) { #ifdef DEBUG HostMessageBox(TEXT("socket err: 0x%lx"), PszFromSocError()); #endif return NULL; } // Disable nagle algorithm int nTrue = 1; setsockopt(soc, IPPROTO_TCP, TCP_NODELAY, (NetBuff)&nTrue, sizeof(int)); // Disable excessive 'lingering' (particularly a problem on PalmOS <=5 which has only 16 sockets) linger lngr; lngr.l_onoff = 1; lngr.l_linger = 0; setsockopt(soc, SOL_SOCKET, SO_LINGER, (NetBuff)&lngr, sizeof(lngr)); // Connect to the server // UNDONE: On PalmOS <=5 this occasionally times out after 2 secs. Longer would be better if (connect(soc, (const sockaddr *)pnad, sizeof(sockaddr_in)) != 0) { switch (WSAGetLastError()) { case WSAEHOSTUNREACH: HtMessageBox(kfMbWhiteBorder, "Comm Problem", "Host unreachable."); break; case WSAECONNREFUSED: HtMessageBox(kfMbWhiteBorder, "Comm Problem", "Connection refused."); break; case WSAETIMEDOUT: HtMessageBox(kfMbWhiteBorder, "Comm Problem", "Timed out trying to connect to host."); break; default: HtMessageBox(kfMbWhiteBorder, "Comm Problem", "Unable to connect. Error %d", WSAGetLastError()); break; } closesocket(soc); return NULL; } pcon = NewConnection(soc); if (pcon == NULL) { closesocket(soc); return NULL; } m_fAsyncConnectLoopback = false; } AddConnection(pcon); Assert(m_pconAsyncConnect == NULL, "Can only have one pending AsyncConnect at a time"); m_pconAsyncConnect = pcon; return pcon; }
// Write lock on the list must be held // Returns an entry that can be expired. The caller frees it PMP_BSS_ENTRY HelperPortExpireBSSEntry( __in PMP_BSS_LIST pBSSList, __in ULONGLONG ullMaxActiveTime, __in ULONGLONG ullExpireTimeStamp ) { PLIST_ENTRY pHead = NULL, pEntry = NULL; PMP_BSS_ENTRY pBSSEntry = NULL; BOOLEAN bFound = FALSE; // // We can expire an entry that has been around for longer // than this time // if (ullMaxActiveTime <= ullExpireTimeStamp) ullExpireTimeStamp -= ullMaxActiveTime; pHead = &(pBSSList->List); pEntry = pHead->Flink; while(pEntry != pHead) { pBSSEntry = CONTAINING_RECORD(pEntry, MP_BSS_ENTRY, Link); pEntry = pEntry->Flink; NdisAcquireSpinLock(&(pBSSEntry->Lock)); // // If the entry is older than we expected and its not in // use, we can expire it // if (pBSSEntry->HostTimestamp < ullExpireTimeStamp) { if (NdisInterlockedDecrement(&(pBSSEntry->RefCount)) == 0) { MpTrace(COMP_SCAN, DBG_LOUD, ("Expiring AP: %02X-%02X-%02X-%02X-%02X-%02X\n", pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5])); MPASSERT(pBSSEntry->pAssocRequest == NULL); MPASSERT(pBSSEntry->pAssocResponse == NULL); // // This is the entry we can expire. Remove it from the list. // NdisReleaseSpinLock(&(pBSSEntry->Lock)); HelperPortRemoveBSSEntry(pBSSList, pBSSEntry); bFound = TRUE; break; } else { // Someone is using the entry, we cannot remove/delete this. Add back // a ref and we will delete later on // This is subobtimal. Ideally the last person to decrement // refcount should delete the entry and not us. Modify to remove // the entry from the list, decrement its refcount and only free // the memory if the refcount has gone to zero NdisInterlockedIncrement(&(pBSSEntry->RefCount)); } } NdisReleaseSpinLock(&(pBSSEntry->Lock)); } if (bFound != TRUE) { pBSSEntry = NULL; } return pBSSEntry;
bool SocConnection::Poll() { if (m_fDisconnecting) { m_fDisconnecting = false; if (m_pccb != NULL) m_pccb->OnDisconnect(this); return false; } if (m_soc == INVALID_SOCKET) return false; // Test if any incoming data is pending fd_set fds; FD_ZERO(&fds); FD_SET(m_soc, &fds); TIMEVAL tvTimeout; tvTimeout.tv_sec = 0; tvTimeout.tv_usec = 0; fd_set fdsDummy; FD_ZERO(&fdsDummy); // MpTrace("m_soc = %d, fds = %ld", (UInt16)m_soc, (UInt32)fds); int nSelected = select(((int)m_soc) + 1, &fds, &fdsDummy, &fdsDummy, &tvTimeout); if (nSelected == SOCKET_ERROR) { #ifdef DEBUG HostMessageBox(TEXT("select err: %s"), PszFromSocError()); #endif return false; } if (nSelected == 1) { NetMessage nm; int cb = recv(m_soc, (char *)&nm, sizeof(NetMessage), 0); // MpTrace("recv: cb %d", cb); if (cb != sizeof(NetMessage)) { HandleRecvError(); return false; } int cbT = BigWord(nm.cb); NetMessage *pnm = (NetMessage *)new byte[cbT]; if (pnm == NULL) { // Data is still pending but we can't do anything about it. // Follow the usual course of action (HandleRecvError will close the Connection) HandleRecvError(); return false; } memcpy(pnm, &nm, sizeof(NetMessage)); int cbRemaining = cbT - sizeof(NetMessage); // UNDONE: this now is a blocking operation until all of the message is // received. Better would be to accumulate the pieces of the message in // a temp buffer (SocConnection member) until it is complete, in a non- // blocking fashion. byte *pbT = (byte *)(pnm + 1); while (cbRemaining != 0) { cbT = recv(m_soc, (char *)pbT, cbRemaining, 0); if (cbT == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) { delete[] pnm; HandleRecvError(); return false; } } pbT += cbT; cbRemaining -= cbT; } if (m_pccb != NULL) { // Before calling OnReceive, order in native byte order NetMessageByteOrderSwap(pnm, false); MpTrace("< %s", PszFromNetMessage(pnm)); m_pccb->OnReceive(this, pnm); } delete[] pnm; } return true; }
// 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;
/* Tx rate adaptation algorithm: Preconditions to update tx data rate: 1) device is in connect state; 2)device has sent at least 100 data packets retransmitPercentage = (toal retry) / (total packets sent) if retransmit percentage <= threshold for rate increase which default to 35% if not sending at the highest rate if previously came down from higher rate and wait count < wait required increase wait count and exit else if not previously came down from higher rate reset wait required else leave wait required unchanged increase current tx rate to next higher rate, reset all other counters and exit if retransmit percentage >= threshold for roam which default to 350% if already send at the lowest rate try to roam to a better AP, reset all counters and exit else if there are at least fallback skip (which default to 3) lower data rates available reduce current tx rate to third lower data rate, reset all counters and exit else if current sending at second lowest rate set current tx rate to the lowest value, reset all counters and exit else fall through to following rate fallback handler if retransmit percentage >= threshold for rate fallback which default to 125% and not sending at the lowest rate if previously came up from lower rate double current wait required else reset wait required reduce current tx rate to next lower value, reset all other counters and exit */ VOID HwUpdateTxDataRate( __in PHW_MAC_CONTEXT MacContext ) { PDOT11_RATE_SET activeRateSet; PHW_RATE_INFO rateInfo = &MacContext->RateInfo; // We are not doing per peer rate adaptation ULONG rateIndex = 0; USHORT prevTxRate = 0; ULONG totalRetry = rateInfo->TotalRetryCount; ULONG totalSend = rateInfo->PacketsSentForTxRateCheck; ULONG retransmitPercentage = 0; OP_RATE_CHANGE_NOTIFICATION rateNotification; if (HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_CANNOT_SEND_FLAGS) || !HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_LINK_UP)) { // MAC context wont be sending to a peer. There isnt anything for us to do return; } // Check the send threshold if (totalSend < MacContext->Hw->RegInfo.MinPacketsSentForTxRateUpdate) { return; } // reset counters InterlockedExchange(&rateInfo->TotalRetryCount, 0); InterlockedExchange((LONG*)&rateInfo->PacketsSentForTxRateCheck, 0); // The active rate set structure needs to be protected HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); do { activeRateSet = &(MacContext->PhyContext[MacContext->OperatingPhyId].ActiveRateSet); for (rateIndex = 0; rateIndex < activeRateSet->uRateSetLength; rateIndex++) { if (rateInfo->CurrentTXDataRate == activeRateSet->ucRateSet[rateIndex]) { prevTxRate = rateInfo->CurrentTXDataRate; break; } } // prevTxRate equals 0 means rateInfo->CurrentTXDataRate // is not in activeRateSet->ucRateSet list if (prevTxRate == 0) { MpTrace(COMP_MISC, DBG_LOUD, ("Current TX data rate is not in active rate set\n")); break; } retransmitPercentage = totalRetry * 100 / totalSend; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: retransmitPercentage=%d(%d/%d), waitCount=%d, " "waitRequired=%d, prevRate=%d\n", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); if (retransmitPercentage <= MacContext->Hw->RegInfo.TxFailureThresholdForRateIncrease) { // Consider going up if (rateIndex < activeRateSet->uRateSetLength - 1) { if ((rateInfo->PrevTxDataRate == activeRateSet->ucRateSet[rateIndex + 1]) && (rateInfo->TxRateIncreaseWaitCount + 1 < rateInfo->TxRateIncreaseWaitRequired)) { // I just came down from the rate above me, i dont want to go up yet due to WaitRequired rateInfo->TxRateIncreaseWaitCount++; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: WAIT before increasing Tx rate. retransmitPercentage=%d(%d/%d), " "waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); } else { // 1. I came down rate above me and WaitCount >= WaitRequired // 2. I came up from rate below me, no need to wait for additional time if (rateInfo->PrevTxDataRate != activeRateSet->ucRateSet[rateIndex + 1]) { // Case 2 above rateInfo->TxRateIncreaseWaitRequired = 1; } else { // Case 1 above /** don't reset TxRateIncreaseWaitRequired as we need to double */ /** the value if fallback to the current rate again */ } rateInfo->PrevTxDataRate = rateInfo->CurrentTXDataRate; rateInfo->TxRateIncreaseWaitCount = 0; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: increasing Tx data rate from %d to %d. " "retransmitPercentage = %d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex + 1], retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex + 1]; } } break; } if (retransmitPercentage >= MacContext->Hw->RegInfo.TxFailureThresholdForRoam) { ULONG rateSkipLevel = MacContext->Hw->RegInfo.TxDataRateFallbackSkipLevel; // Really large retry count, consider roaming if (rateIndex == 0) { // I am sending at the lowest rate. Either roam or disconnect. MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened while " "transmitting at the lowest data rate. Attempting to roam. " "retransmitPercentage=%d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); // Our packets arent going through, jump up to using best data rate & // hopefully our packets will go through rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[activeRateSet->uRateSetLength - 1]; // reset counters rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else if (rateIndex >= rateSkipLevel) { // try to go down three rates MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened. Reducing Tx rate from %d to %d.\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex - rateSkipLevel])); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex - rateSkipLevel]; rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else if (rateIndex != 1) { // set tx rate to the lowest rate MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened. Reducing Tx rate from " "%d to lowest %d.\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[0])); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[0]; rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else { // rateIndex equals to 1. this is the same as lowering tx rate by 1 level // which is what rate fallback handler does. fall through. } } if ((retransmitPercentage >= MacContext->Hw->RegInfo.TxFailureThresholdForRateFallback) && (rateIndex > 0)) { // consider going down. no need to wait for additional time if (rateInfo->PrevTxDataRate == activeRateSet->ucRateSet[rateIndex - 1]) { rateInfo->TxRateIncreaseWaitRequired *= 2; } else { rateInfo->TxRateIncreaseWaitRequired = 1; } rateInfo->PrevTxDataRate = rateInfo->CurrentTXDataRate; rateInfo->TxRateIncreaseWaitCount = 0; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: reducing Tx data rate from %d to %d. " "retransmitPercentage=%d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex - 1], retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex - 1]; break; } } while (FALSE); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); if (prevTxRate != rateInfo->CurrentTXDataRate) { // Indicate new link speed HwIndicateLinkSpeed(MacContext, rateInfo->CurrentTXDataRate); // Indicate change of link speed to the port so that it // can take any necessary action rateNotification.Header.Type = NotificationOpRateChange; rateNotification.Header.Size = sizeof(OP_RATE_CHANGE_NOTIFICATION); rateNotification.Header.pSourceVNic = NULL; rateNotification.NewRate = rateInfo->CurrentTXDataRate; rateNotification.OldRate = prevTxRate; if (rateIndex == 0) rateNotification.LowestRate = TRUE; else rateNotification.LowestRate = FALSE; VNic11Notify(MacContext->VNic, &rateNotification); } }
NDIS_STATUS VNic11JoinBSS( _In_ PVNIC pVNic, _In_ PMP_BSS_DESCRIPTION BSSDescription, _In_ ULONG JoinFailureTimeout, _In_ PORT11_GENERIC_CALLBACK_FUNC CompletionHandler ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN fLocked = FALSE; BOOLEAN fProcessReqNow = FALSE; PVNIC_COMPLETION_CTX pCtx = NULL; do { VNicLock(pVNic); fLocked = TRUE; ndisStatus = VNicCanProcessReqNow(pVNic, &fProcessReqNow); if (NDIS_STATUS_SUCCESS != ndisStatus) { MpTrace(COMP_HVL, DBG_NORMAL, ("VNic(%d): VNicCanProcessReqNow failed 0x%x\n", VNIC_PORT_NO, ndisStatus)); break; } if (fProcessReqNow) { ndisStatus = ALLOC_MEM(pVNic->MiniportAdapterHandle, sizeof(VNIC_COMPLETION_CTX), &pCtx); if (NDIS_STATUS_SUCCESS != ndisStatus) { MpTrace(COMP_HVL, DBG_SERIOUS, ("VNic(%d): Failed to allocate memory for a new completion context \n", VNIC_PORT_NO)); /* Do not call the station's callback function since the station doesn't expect to be called back if there is a failure */ break; } pCtx->CompletionFn = CompletionHandler; ndisStatus = VNicJoinBSSHelper(pVNic, BSSDescription, JoinFailureTimeout, pCtx); if (NDIS_STATUS_PENDING != ndisStatus) { MpTrace(COMP_HVL, DBG_NORMAL, ("VNic(%d): VNicJoinBSSHelper completed synchronously %!x!\n", VNIC_PORT_NO, ndisStatus)); /* The call to the hardware completed synchronously. Do not call the station's callback function. */ FREE_MEM(pCtx); break; } } else { /* We are not currently active or there are pending operations. Queue the Join request internally */ ndisStatus = VNicQueueJoinRequest( pVNic, BSSDescription, JoinFailureTimeout, CompletionHandler ); if (NDIS_STATUS_SUCCESS == ndisStatus) { MpTrace(COMP_HVL, DBG_NORMAL, ("VNic(%d): Queued the join request \n", VNIC_PORT_NO)); // Return pending since the request is not going to be completed synchrnously ndisStatus = NDIS_STATUS_PENDING; } else { MpTrace(COMP_HVL, DBG_NORMAL, ("VNic(%d): VNicQueueJoinRequest failed %!x!\n", VNIC_PORT_NO, ndisStatus)); } } } while (FALSE); if (fLocked) { VNicUnlock(pVNic); } 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); } }