Sample Code
Windows Driver Samples/ Native Wi-Fi Miniport Sample Driver/ C++/ hw/ hw_context.c/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: hw_context.c Abstract: Implements for MAC context management for the HW layer Revision History: When What ---------- ---------------------------------------------- 09-04-2007 Created Notes: --*/ #include "precomp.h" #include "hw_context.h" #include "hw_isr.h" #include "hw_main.h" #include "hw_mac.h" #include "hw_phy.h" #include "hw_rate.h" #if DOT11_TRACE_ENABLED #include "hw_context.tmh" #endif NDIS_STATUS Hw11AllocateMACContext( _In_ PHW Hw, _Outptr_result_maybenull_ PHW_MAC_CONTEXT* MacContext, _In_ PVNIC VNic, _In_ NDIS_PORT_NUMBER PortNumber ) { UCHAR i; NDIS_STATUS ndisStatus = NDIS_STATUS_FAILURE; *MacContext = NULL; HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); for (i = 0; i < HW_MAX_NUMBER_OF_MAC; i++) { if (!HW_MAC_CONTEXT_IS_VALID(&Hw->MacContext[i])) { ndisStatus = HwInitializeMACContext(Hw, &Hw->MacContext[i], VNic, i); if (ndisStatus == NDIS_STATUS_SUCCESS) { // Return this MAC to the caller Hw->MacContextCount++; HW_SET_MAC_CONTEXT_STATUS(&Hw->MacContext[i], HW_MAC_CONTEXT_VALID | HW_MAC_CONTEXT_PAUSED); Hw->MacContext[i].PortNumber = PortNumber; *MacContext = &Hw->MacContext[i]; } // Success of failure, we break out break; } } HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); if (*MacContext == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate MAC context in HW for VNIC\n")); } return ndisStatus; } VOID Hw11FreeMACContext( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { BOOLEAN isActive = FALSE; HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); if (HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVE)) { isActive = TRUE; } if (isActive) { // We are still active, we need to clear our state from the HW before bailing out HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); if (MacContext->BSSStarted) { // Stop beaconing HwStopBSS(Hw); } // delete all the keys that are currently set on the hardware HwDeleteAllKeysFromHw(MacContext); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); } MacContext->Status = 0; HwTerminateMACContext(Hw, MacContext); Hw->MacContextCount--; HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); } NDIS_STATUS Hw11EnableMACContext( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN fAlreadyActive = FALSE; MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Hw11EnableMACContext called\n", HW_MAC_PORT_NO(MacContext))); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); if (HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVE)) { fAlreadyActive = TRUE; } else { HW_SET_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVATING); } HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); if (fAlreadyActive) { MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("MAC context is already active. Returning.\n")); return NDIS_STATUS_SUCCESS; } // // Program the MAC context on the hardware // ndisStatus = HwSetMACContextOnNic(Hw, MacContext); // Do I need this lock? HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVE); HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVATING); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); return ndisStatus; } NDIS_STATUS Hw11DisableMACContext( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN notActive = FALSE; MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Hw11DisableMACContext called\n", HW_MAC_PORT_NO(MacContext))); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); if (!HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVE)) { // This can happen when we have been terminated and the MAC is // being disabled after the terminate finished notActive = TRUE; } HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_ACTIVE); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); if (notActive) { return ndisStatus; } // Wait for the refcount to go down to 0 while (MacContext->GenericRefCount > 0) NdisMSleep(1000); // Wait for the refcount to go down to 0 while (MacContext->SendRefCount > 0) NdisMSleep(1000); // // Remove this MAC context from the hardware // ndisStatus = HwClearMACContextFromNic(Hw, MacContext); return ndisStatus; } NDIS_STATUS Hw11PauseMACContext( _In_ PHW_MAC_CONTEXT MacContext ) { HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); HW_SET_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_PAUSING); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Hw11PauseMACContext called\n", HW_MAC_PORT_NO(MacContext))); // // Wait for the periodic timer to finish. It would see the pausing // flag and give up // while (MacContext->PeriodicTimerQueued != 0) { if (NdisCancelTimerObject(MacContext->Timer_Periodic) == TRUE) { // // Periodic timer is done // MacContext->PeriodicTimerQueued = 0; } else { // Sleep a bit and try again NdisMSleep(1000); } } // Wait for the refcount to go down to 0 while (MacContext->GenericRefCount > 0) NdisMSleep(1000); // Wait for the refcount to go down to 0 while (MacContext->SendRefCount > 0) NdisMSleep(1000); // Wait for the refcount to go down to 0 HwWaitForPendingReceives(MacContext->Hw, MacContext); HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); HW_SET_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_PAUSED); HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_PAUSING); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); return NDIS_STATUS_SUCCESS; } VOID Hw11RestartMACContext( _In_ PHW_MAC_CONTEXT MacContext ) { LARGE_INTEGER periodicTimerDuration; MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Hw11RestartMACContext called\n", HW_MAC_PORT_NO(MacContext))); HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_PAUSED); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); // Queue the periodic time periodicTimerDuration.QuadPart = HW_CONTEXT_PERIODIC_TIMER_DURATION * -1 * 10000; // We dont add a ref for the periodic timer. Instead we set a flag that its queued MacContext->PeriodicTimerQueued = 1; NdisSetTimerObject(MacContext->Timer_Periodic, periodicTimerDuration, 0, NULL); } // Called with Lock held NDIS_STATUS HwInitializeMACContext( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext, _In_ PVNIC VNic, _In_ ULONG ContextId ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; DOT11_RESET_REQUEST resetRequest; NDIS_TIMER_CHARACTERISTICS timerChar; do { NdisZeroMemory(MacContext, sizeof(HW_MAC_CONTEXT)); // Program the default values MacContext->Hw = Hw; MacContext->VNic = VNic; // Default everything comes up in ExtSTA mode. This does not // get changed on a reset but on a set op mode MacContext->CurrentOpMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION; 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 = HW_MEMORY_TAG; // Allocate the Join timeout call back timerChar.TimerFunction = HwJoinTimeoutTimer; timerChar.FunctionContext = MacContext; ndisStatus = NdisAllocateTimerObject( Hw->MiniportAdapterHandle, &timerChar, &MacContext->Timer_JoinTimeout ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate join timer for MAC context\n")); break; } // Allocate the periodic timeout call back timerChar.TimerFunction = HwMACContextPeriodicTimer; timerChar.FunctionContext = MacContext; ndisStatus = NdisAllocateTimerObject( Hw->MiniportAdapterHandle, &timerChar, &MacContext->Timer_Periodic ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate periodic timer for MAC context\n")); break; } // // Assign a MAC address to this context. // NdisMoveMemory(MacContext->MacAddress, Hw->MacState.MacAddress, DOT11_ADDRESS_SIZE ); if (Hw->RegInfo.MultipleMacAddressEnabled) { // Let the HW assign a separate MAC address to this port. If it HW supports // multiple MAC addresses, it would provide us a new one for each context. // Else it would use the default ndisStatus = HalAssignMACAddress(Hw->Hal, ContextId, MacContext->MacAddress); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to assign MAC address for MAC context\n")); break; } } // // Reset the MAC context state // NdisZeroMemory(&resetRequest, sizeof(DOT11_RESET_REQUEST)); resetRequest.dot11ResetType = dot11_reset_type_phy_and_mac; resetRequest.bSetDefaultMIB = TRUE; // Before we enable it, we reset its contents HwResetMACContext(MacContext, &resetRequest); }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Cleanup HwTerminateMACContext(Hw, MacContext); } return ndisStatus; } // Called with lock held VOID HwTerminateMACContext( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { ULONG i; UNREFERENCED_PARAMETER(Hw); MPASSERT(MacContext->GenericRefCount == 0); // // Delete any keys we may be holding // for (i = 0; i < HW11_PEER_TABLE_SIZE; i++) { // function checks for validity HwFreePeerNode(MacContext, &MacContext->PeerTable[i]); } HwFreePeerNode(MacContext, &MacContext->DefaultPeer); if (MacContext->Timer_Periodic) { NdisFreeTimerObject(MacContext->Timer_Periodic); MacContext->Timer_Periodic = NULL; } if (MacContext->Timer_JoinTimeout) { NdisFreeTimerObject(MacContext->Timer_JoinTimeout); MacContext->Timer_JoinTimeout = NULL; } if (MacContext->BeaconIEBlob != NULL) { MP_FREE_MEMORY(MacContext->BeaconIEBlob); } if (MacContext->ProbeResponseIEBlob != NULL) { MP_FREE_MEMORY(MacContext->ProbeResponseIEBlob); } NdisZeroMemory(MacContext, sizeof(HW_MAC_CONTEXT)); } // // Dot11Reset Step 1 - Cleanup any "pending" operations // VOID HwDot11ResetStep1( _In_ PHW_MAC_CONTEXT MacContext, _In_ PDOT11_RESET_REQUEST Dot11ResetRequest ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PHW hw = MacContext->Hw; UNREFERENCED_PARAMETER(Dot11ResetRequest); HW_ACQUIRE_HARDWARE_LOCK(hw, FALSE); HW_SET_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_IN_DOT11_RESET); HW_SET_ADAPTER_STATUS(hw, HW_ADAPTER_IN_DOT11_RESET); HW_RELEASE_HARDWARE_LOCK(hw, FALSE); // Wait for pending operations in the hardware to finish HW_WAIT_FOR_ACTIVE_OPERATIONS_TO_FINISH(hw); // Wait for active sends to be finish HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(hw); // Wait for pending operations and receives in the MAC contexts to get completed. We dont wait // for sends while (MacContext->GenericRefCount > 0) NdisMSleep(1000); // If we have started a BSS, stop beaconing if (MacContext->BSSStarted) HwStopBSS(hw); // Disable interrupts // MpTrace(COMP_TESTING, DBG_SERIOUS, ("HwDot11ResetStep1 \n")); HwDisableInterrupt(hw, HW_ISR_TRACKING_DOT11_RESET); ndisStatus = HalResetStart(hw->Hal); MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS); HalStop(hw->Hal); // Flush sends and wait for pending receives from this mac context HwFlushSendEngine(hw, FALSE); HwWaitForPendingReceives(hw, MacContext); } // // Dot11Reset Step 2 - Reset our state // NDIS_STATUS HwDot11ResetStep2( _In_ PHW_MAC_CONTEXT MacContext, _In_ PDOT11_RESET_REQUEST Dot11ResetRequest ) { PHW hw = MacContext->Hw; MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Reseting state\n", HW_MAC_PORT_NO(MacContext))); // Reset the send and receive engine HwResetSendEngine(hw, FALSE); HwResetReceiveEngine(hw, FALSE); // Remove keys from hardware HwDeleteAllKeysFromHw(MacContext); // Reset HW MAC & PHY state HwResetSoftwareMacState(hw); HwResetSoftwarePhyState(hw); NdisZeroMemory(&hw->Stats, sizeof(NIC_STATISTICS)); // Reset the MAC context HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); HwResetMACContext(MacContext, Dot11ResetRequest); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Reapplying new state\n", HW_MAC_PORT_NO(MacContext))); // // Restart everything // HalStart(hw->Hal, TRUE); // Push the new state on the hardware HwSetNicState(hw); HalResetEnd(hw->Hal); MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Setting MAC Context\n", HW_MAC_PORT_NO(MacContext))); // // Now program this MAC context on the HW // HwSetMACContextOnNic(hw, MacContext); // Renable the interrupts // MpTrace(COMP_TESTING, DBG_SERIOUS, ("HwDot11ResetStep2 \n")); HwEnableInterruptWithSync(hw, HW_ISR_TRACKING_DOT11_RESET); HW_CLEAR_ADAPTER_STATUS(hw, HW_ADAPTER_IN_DOT11_RESET); HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_IN_DOT11_RESET); return NDIS_STATUS_SUCCESS; } NDIS_STATUS Hw11Dot11Reset( _In_ PHW_MAC_CONTEXT MacContext, _In_ PDOT11_RESET_REQUEST Dot11ResetRequest ) { MpTrace(COMP_MISC, DBG_NORMAL, ("HwMac(%d): Hw11Dot11Reset called\n", HW_MAC_PORT_NO(MacContext))); // The reset is a 2 step process HwDot11ResetStep1(MacContext, Dot11ResetRequest); return HwDot11ResetStep2(MacContext, Dot11ResetRequest); } // // Resets the software state but does not program the hardware // NDIS_STATUS HwResetMACContext( _In_ PHW_MAC_CONTEXT MacContext, _In_ PDOT11_RESET_REQUEST Dot11ResetRequest ) { UCHAR index; PNICPHYMIB phyMib; DOT11_MAC_ADDRESS broadcastAddress = {0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF}; // // Load the default MAC address // if ((Dot11ResetRequest->dot11ResetType == dot11_reset_type_phy_and_mac) || (Dot11ResetRequest->dot11ResetType == dot11_reset_type_mac)) { // We dont let the OS change the MAC address // NdisMoveMemory(MacContext->MacAddress, Dot11ResetRequest->dot11MacAddress, DOT11_ADDRESS_SIZE); } HW_CLEAR_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_LINK_UP); MacContext->PowerMgmtMode.dot11PowerMode = dot11_power_mode_active; // // Default BSSID // NdisMoveMemory(MacContext->DesiredBSSID, broadcastAddress, DOT11_ADDRESS_SIZE); MacContext->BssType = dot11_BSS_type_infrastructure; MacContext->SSID.uSSIDLength = 0; MacContext->BeaconPeriod = MacContext->Hw->RegInfo.BeaconPeriod; MacContext->AtimWindow = 0; // Set when in PS mode MacContext->LastBeaconTimestamp = 0; MacContext->RTSThreshold = MacContext->Hw->RegInfo.RTSThreshold; MacContext->FragmentationThreshold = MacContext->Hw->RegInfo.FragmentationThreshold; MacContext->ShortRetryLimit = HalGetShortRetryLimit(MacContext->Hw->Hal); MacContext->LongRetryLimit = HalGetLongRetryLimit(MacContext->Hw->Hal); // Invalidate all the keys for (index = 0; index < HW11_KEY_TABLE_SIZE; index++) { MPASSERT(MacContext->KeyTable[index].hCNGKey == NULL); HwFreeKey(&MacContext->KeyTable[index]); } MacContext->DefaultKeyIndex = 0; MacContext->KeyMappingKeyCount = 0; // Clear the peer node count for (index = 0; index < HW11_PEER_TABLE_SIZE; index++) { HwFreePeerNode(MacContext, &MacContext->PeerTable[index]); } MacContext->PeerNodeCount = 0; // Default peer is valid HwFreePeerNode(MacContext, &MacContext->DefaultPeer); MacContext->DefaultPeer.Valid = TRUE; ETH_COPY_NETWORK_ADDRESS(MacContext->DefaultPeer.PeerMac, broadcastAddress); MacContext->AuthAlgorithm = DOT11_AUTH_OPEN_SYSTEM; MacContext->UnicastCipher = DOT11_CIPHER_ALGO_NONE; MacContext->MulticastCipher = DOT11_CIPHER_ALGO_NONE; MacContext->MulticastAddressCount = 0; MacContext->AcceptAllMulticast = FALSE; // We do not reset the packet filter here. The Port would set this // MacContext->PacketFilter = NDIS_PACKET_TYPE_802_11_BROADCAST_MGMT // | NDIS_PACKET_TYPE_802_11_DIRECTED_MGMT; MacContext->OperatingPhyId = 0; MacContext->SelectedPhyId = 0; // Reset all the PHY parameters to their default value for (index = 0; index < MAX_NUM_PHY_TYPES; index++) { phyMib = HalGetPhyMIB(MacContext->Hw->Hal, index); // Ensure that all the parameters are reset here // Reset the channel to the channel currently set on the HAL structure MacContext->PhyContext[index].Channel = phyMib->Channel; // Also get the operation rate set NdisMoveMemory(&(MacContext->PhyContext[index].OperationalRateSet), &(phyMib->OperationalRateSet), sizeof(DOT11_RATE_SET)); // This is also the current active rate set NdisMoveMemory(&(MacContext->PhyContext[index].ActiveRateSet), &(phyMib->OperationalRateSet), sizeof(DOT11_RATE_SET)); } MacContext->ShortSlotTimeOptionEnabled = FALSE; MacContext->CTSToSelfEnabled = FALSE; // Load the default reg domain MacContext->CurrentRegDomain = MacContext->Hw->PhyState.DefaultRegDomain; MacContext->DefaultTXDataRate = 22; // Default data rate = 11 Mbps MacContext->DefaultTXMgmtRate = HalGetBeaconRate(MacContext->Hw->Hal, MacContext->OperatingPhyId); // Clear the rate information NdisZeroMemory(&MacContext->RateInfo, sizeof(HW_RATE_INFO)); MacContext->RateInfo.CurrentTXDataRate = MacContext->DefaultTXDataRate; MacContext->JoinContext = NULL; MacContext->ChannelSwitchContext = NULL; MacContext->ScanContext = NULL; // Reset statistics NdisZeroMemory(&MacContext->UnicastCounters, sizeof(DOT11_MAC_FRAME_STATISTICS)); NdisZeroMemory(&MacContext->MulticastCounters, sizeof(DOT11_MAC_FRAME_STATISTICS)); // Reset general data if (MacContext->BeaconIEBlob != NULL) { MP_FREE_MEMORY(MacContext->BeaconIEBlob); MacContext->BeaconIEBlob = NULL; } MacContext->BeaconIEBlobSize = 0; if (MacContext->ProbeResponseIEBlob != NULL) { MP_FREE_MEMORY(MacContext->ProbeResponseIEBlob); MacContext->ProbeResponseIEBlob = NULL; } MacContext->ProbeResponseIEBlobSize = 0; // We always come up as enabled. The upper layer would disable it if it wants to MacContext->BeaconEnabled = TRUE; MacContext->BSSStarted = FALSE; return NDIS_STATUS_SUCCESS; } NDIS_STATUS HwSetMACContextOnNic( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { ULONG PhyId = 0, index = 0; PHW_KEY_ENTRY KeyEntry = NULL; // // This function is called each time a MAC context becomes active. We need to take // the config from the MAC context and set it on the HW. If a MAC is already active, // we need to merge the config with the existing hardware config, else // we can just update the existing programmed value // if (HW_TEST_ADAPTER_STATUS(Hw, HW_CANNOT_ACCESS_HARDWARE)) { // HW should not be touched return NDIS_STATUS_SUCCESS; } HwUpdateBSSType(Hw, MacContext); MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Set the BSS type %d \n", MacContext->BssType)); // Op Mode HwUpdateOperationMode(Hw, MacContext); // Program this MAC context's phy state on the HW PhyId = MacContext->OperatingPhyId; HwProgramPhy(MacContext->Hw, MacContext, PhyId, &MacContext->PhyContext[PhyId], NULL ); // Update the link state HwUpdateLinkState(MacContext->Hw, MacContext); // set the BSSID HwUpdateBSSID(Hw, MacContext); // beacon interval Hw11SetBeaconPeriod(MacContext, MacContext->BeaconPeriod, TRUE); // packet filter HwUpdatePacketFilter(Hw, MacContext); // Multicast list HwUpdateMulticastAddressList(Hw, MacContext); // encryption HwUpdateUnicastCipher(MacContext->Hw, MacContext); for (index = 0; index < HW11_KEY_TABLE_SIZE; index++) { KeyEntry = &MacContext->KeyTable[index]; if (KeyEntry->Key.Valid) { MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Adding key entry (index = %d)\n", index)); HwAddKeyEntry(MacContext->Hw, KeyEntry); } } // If BSS is started, enable it on the H/W if (MacContext->BSSStarted) { // Start BSS on the H/W HwResumeBSS(Hw, MacContext, MacContext->BeaconEnabled); MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Resummed BSS on the hardware.\n")); } return NDIS_STATUS_SUCCESS; } NDIS_STATUS HwClearMACContextFromNic( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext ) { UNREFERENCED_PARAMETER(Hw); if (HW_TEST_ADAPTER_STATUS(Hw, HW_CANNOT_ACCESS_HARDWARE)) { // HW should not be touched return NDIS_STATUS_SUCCESS; } // // This function is called each time a MAC context becomes inactive. We should // unset settings from the hardware. Example - remove keys, disable beaconing in // Adhoc or AP mode, etc. // if (MacContext->BSSStarted) { // Pause BSS (we may already be in no-beacon mode) HwPauseBSS(Hw); } // delete all the keys that are currently set on the hardware HwDeleteAllKeysFromHw(MacContext); // Disable this specific MAC context from the hardware HwUpdateUnicastCipher(Hw, MacContext); return NDIS_STATUS_SUCCESS; } NDIS_STATUS HwUpdateBSSDescription( _In_ PHW_MAC_CONTEXT HwMac, _In_ PMP_BSS_DESCRIPTION BSSDescription, _In_ BOOLEAN BSSStart ) { NDIS_STATUS ndisStatus; PHW_PEER_NODE peerNode; PUCHAR remoteRatesIE; UCHAR remoteRatesIELength; PDOT11_RATE_SET localRateSet; PNICPHYMIB phyMib; PUCHAR ieBlob = NULL; ULONG ieBlobSize; // Both IE blobs must be set (can be set to the same value) MPASSERT(BSSDescription->BeaconIEBlobSize > 0); MPASSERT(BSSDescription->ProbeIEBlobSize > 0); if (BSSStart) { MPASSERT(MP_COMPARE_MAC_ADDRESS(HwMac->MacAddress, BSSDescription->MacAddress)); if (HwMac->BeaconIEBlob != NULL) { MP_FREE_MEMORY(HwMac->BeaconIEBlob); HwMac->BeaconIEBlobSize = 0; } if (HwMac->ProbeResponseIEBlob != NULL) { MP_FREE_MEMORY(HwMac->ProbeResponseIEBlob); HwMac->ProbeResponseIEBlobSize = 0; } // We are starting a BSS. Store the information in the default peer node peerNode = &HwMac->DefaultPeer; // Copy the BSS beacon information into local buffer MP_ALLOCATE_MEMORY(HwMac->Hw->MiniportAdapterHandle, &HwMac->BeaconIEBlob, BSSDescription->BeaconIEBlobSize, HW_MEMORY_TAG ); if (HwMac->BeaconIEBlob == NULL) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to allocate space to store beacon information\n")); return NDIS_STATUS_RESOURCES; } // Copy the BSS probe response information into local buffer MP_ALLOCATE_MEMORY(HwMac->Hw->MiniportAdapterHandle, &HwMac->ProbeResponseIEBlob, BSSDescription->ProbeIEBlobSize, HW_MEMORY_TAG ); if (HwMac->ProbeResponseIEBlob == NULL) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to allocate space to store probe response information\n")); MP_FREE_MEMORY(HwMac->BeaconIEBlob); HwMac->BeaconIEBlob = NULL; return NDIS_STATUS_RESOURCES; } NdisMoveMemory(HwMac->BeaconIEBlob, &BSSDescription->IEBlobs[BSSDescription->BeaconIEBlobOffset], BSSDescription->BeaconIEBlobSize ); HwMac->BeaconIEBlobSize = BSSDescription->BeaconIEBlobSize; NdisMoveMemory(HwMac->ProbeResponseIEBlob, &BSSDescription->IEBlobs[BSSDescription->ProbeIEBlobOffset], BSSDescription->ProbeIEBlobSize ); HwMac->ProbeResponseIEBlobSize = BSSDescription->ProbeIEBlobSize; } else { MPASSERT(!MP_COMPARE_MAC_ADDRESS(HwMac->MacAddress, BSSDescription->MacAddress)); // Allocate or find a peer node structure to use for this. // The TRUE is needed for Adhoc/AP mode peerNode = HwFindPeerNode(HwMac, BSSDescription->MacAddress, TRUE); if (peerNode == NULL) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to reserve space for peer node information\n")); return NDIS_STATUS_RESOURCES; } } // Some of the information gets loaded into the MAC context HwMac->BssType = BSSDescription->BSSType; NdisMoveMemory(HwMac->DesiredBSSID, BSSDescription->BSSID, sizeof(DOT11_MAC_ADDRESS)); // The use settings from the beacon IE blob ieBlob = &BSSDescription->IEBlobs[BSSDescription->BeaconIEBlobOffset]; ieBlobSize = BSSDescription->BeaconIEBlobSize; // Copy the SSID ndisStatus = Dot11CopySSIDFromMemoryBlob( ieBlob, ieBlobSize, &HwMac->SSID ); if (ndisStatus != NDIS_STATUS_SUCCESS) { // // A required IE is missing. Fail the request. // MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Mandatory SSID Info Element not found in BSS description\n")); return NDIS_STATUS_INVALID_DATA; } HwMac->BeaconPeriod = HW_LIMIT_BEACON_PERIOD(BSSDescription->BeaconPeriod); HwMac->LastBeaconTimestamp = BSSDescription->Timestamp; // Some stuff goes into the peer node fields peerNode->CapabilityInfo = BSSDescription->Capability.usValue; // // If called has not selected PhyID/Channel, use the current one // if (BSSDescription->Channel == 0) { // // Channel/PhyID // MpTrace(COMP_ASSOC, DBG_NORMAL, ("Channel/PhyID not specified for join. Using current values\n")); BSSDescription->PhyId = HwMac->OperatingPhyId; BSSDescription->Channel = HwMac->PhyContext[BSSDescription->PhyId].Channel; } // // For management packets, pick the lowest basic data rate supported between the AP and us as the // rate for management packets // phyMib = HalGetPhyMIB(HwMac->Hw->Hal, BSSDescription->PhyId); localRateSet = &phyMib->BasicRateSet; // TODO: Should this happen with MAC context specific rate set? HwMac->DefaultTXMgmtRate = HalGetBeaconRate(HwMac->Hw->Hal, BSSDescription->PhyId); ndisStatus = Dot11GetInfoEle( ieBlob, ieBlobSize, DOT11_INFO_ELEMENT_ID_SUPPORTED_RATES, &remoteRatesIELength, &remoteRatesIE ); if (ndisStatus == NDIS_STATUS_SUCCESS) { if (!HwSelectLowestMatchingRate( remoteRatesIE, remoteRatesIELength, localRateSet, &HwMac->DefaultTXMgmtRate )) { // // Look in the extended rates set // ndisStatus = Dot11GetInfoEle( ieBlob, ieBlobSize, DOT11_INFO_ELEMENT_ID_EXTD_SUPPORTED_RATES, &remoteRatesIELength, &remoteRatesIE ); if (ndisStatus == NDIS_STATUS_SUCCESS) { if (!HwSelectLowestMatchingRate( remoteRatesIE, remoteRatesIELength, localRateSet, &HwMac->DefaultTXMgmtRate )) { // // Didnt find any prefered data rate, select the default // HwMac->DefaultTXMgmtRate = HalGetBeaconRate(HwMac->Hw->Hal, BSSDescription->PhyId); } } } } return NDIS_STATUS_SUCCESS; } VOID Hw11StopBSS( _In_ PHW_MAC_CONTEXT HwMac ) { // Stop BSS HwStopBSS(HwMac->Hw); HwMac->BSSStarted = FALSE; } NDIS_STATUS Hw11StartBSS( _In_ PHW_MAC_CONTEXT HwMac, _In_ PMP_BSS_DESCRIPTION BSSDescription ) { NDIS_STATUS ndisStatus; // // Check if we are in the middle of an operation that does not // let us start a BSS. Any operation that blocks a receive blocks // us from starting a BSS // HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); if (HW_TEST_ADAPTER_STATUS(HwMac->Hw, HW_CANNOT_RECEIVE_FLAGS)) { // We cannot perform the start HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Start BSS failed because HW is in invalid state 0x%08x\n", HwMac->Hw->Status)); return HwGetAdapterStatus(HwMac->Hw); } // // We should fail the start request if the radio is OFF // if (HW_TEST_ADAPTER_STATUS(HwMac->Hw, HW_CANNOT_ACCESS_HARDWARE)) { // We cannot perform the start HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Start BSS failed because hardware is not available\n")); return HwGetAdapterStatus(HwMac->Hw); } HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); do { // // Copy the information from the BSS to our buffer // ndisStatus = HwUpdateBSSDescription(HwMac, BSSDescription, TRUE); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // BSS has been started HwMac->BSSStarted = TRUE; // Pass this to the hardware ndisStatus = HwStartBSS(HwMac->Hw, HwMac, HwMac->BeaconEnabled); } while (FALSE); return ndisStatus; } NDIS_STATUS Hw11JoinBSS( _In_ PHW_MAC_CONTEXT HwMac, _In_ PMP_BSS_DESCRIPTION BSSDescription, _In_ ULONG JoinFailureTimeout, _In_ VNIC11_GENERIC_CALLBACK_FUNC CompletionHandler, _In_ PVOID JoinContext ) { NDIS_STATUS ndisStatus; ULONG origPhyId; UCHAR origChannel; // // Check if we are in the middle of an operation that does not // let us do a join. Any operation that blocks a receive blocks // us from joining // HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); if (HW_TEST_ADAPTER_STATUS(HwMac->Hw, HW_CANNOT_RECEIVE_FLAGS)) { // We cannot perform the join HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Join failed because HW is in invalid state 0x%08x\n", HwMac->Hw->Status)); return HwGetAdapterStatus(HwMac->Hw); } if (HW_TEST_ADAPTER_STATUS(HwMac->Hw, HW_CANNOT_ACCESS_HARDWARE)) { // We cannot perform the join HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Join failed because adapter is not available\n")); return HwGetAdapterStatus(HwMac->Hw); } // Add a ref count to the MAC context to avoid it from getting context // switched, etc HW_ADD_MAC_CONTEXT_REF(HwMac, 1); // Save the completion handler HwMac->PendingJoinCallback = CompletionHandler; HwMac->JoinContext = JoinContext; HwMac->JoinFailureTimeout = JoinFailureTimeout; HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); // Now the actual the join operation do { // // Copy the information from the BSS to our buffer // ndisStatus = HwUpdateBSSDescription(HwMac, BSSDescription, FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Clear this HwMac->PendingJoinCallback = NULL; break; } // // If the current Phy ID or Channel does not match the one specified in // the BSS description, change the channel // if ((HwMac->OperatingPhyId != BSSDescription->PhyId) || (HwMac->PhyContext[BSSDescription->PhyId].Channel != BSSDescription->Channel)) { origPhyId = HwMac->OperatingPhyId; origChannel = HwMac->PhyContext[HwMac->OperatingPhyId].Channel; // Need to switch. Update our local phy state and program the HW HwMac->OperatingPhyId = BSSDescription->PhyId; HwMac->PhyContext[BSSDescription->PhyId].Channel = BSSDescription->Channel; ndisStatus = HwProgramPhy(HwMac->Hw, HwMac, BSSDescription->PhyId, &HwMac->PhyContext[BSSDescription->PhyId], HwJoinChannelSwitchComplete ); if (ndisStatus != NDIS_STATUS_PENDING) { MPASSERT(ndisStatus != NDIS_STATUS_SUCCESS); HwMac->PendingJoinCallback = NULL; // Restore original values HwMac->OperatingPhyId = origPhyId; HwMac->PhyContext[HwMac->OperatingPhyId].Channel = origChannel; } } else { HwJoinChannelSwitchComplete(HwMac->Hw, HwMac, NULL); ndisStatus = NDIS_STATUS_PENDING; } } while (FALSE); if (ndisStatus != NDIS_STATUS_PENDING) { HW_REMOVE_MAC_CONTEXT_REF(HwMac, 1); } return ndisStatus; } NDIS_STATUS HwJoinChannelSwitchComplete( _In_ PHW Hw, _In_ PHW_MAC_CONTEXT MacContext, _In_opt_ PVOID Data ) { LARGE_INTEGER joinFailureInMs; UNREFERENCED_PARAMETER(Hw); UNREFERENCED_PARAMETER(Data); // // Channel switch for the join is done. Now wait for the join // HwPrepareToJoinBSS(MacContext->Hw, MacContext); // Timeout passed in is in Beacon Periods. For relative time, the set timer // function requires a negative timeout in 100nanoseconds. joinFailureInMs.QuadPart = HW_TU_TO_MS(MacContext->JoinFailureTimeout * MacContext->BeaconPeriod); joinFailureInMs.QuadPart = joinFailureInMs.QuadPart * -1 * 10000; // Add a ref for the async function and set the timer HW_INCREMENT_ACTIVE_OPERATION_REF(Hw); NdisSetTimerObject(MacContext->Timer_JoinTimeout, joinFailureInMs, 0, NULL); // Set the bit that we are waiting for join HW_WAIT_FOR_BSS_JOIN(MacContext); return NDIS_STATUS_SUCCESS; } VOID HwJoinBSSComplete( _In_ PHW_MAC_CONTEXT HwMac, _In_opt_ PHW_RX_MPDU Mpdu, _In_ NDIS_STATUS Status ) { VNIC11_GENERIC_CALLBACK_FUNC completionHandler = NULL; PVOID completeContext = NULL; UNREFERENCED_PARAMETER(Mpdu); MpTrace(COMP_ASSOC, DBG_NORMAL, ("Join completed with status 0x%08x\n", Status)); HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); completionHandler = HwMac->PendingJoinCallback; completeContext = HwMac->JoinContext; HwMac->PendingJoinCallback = NULL; HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MPASSERT(completeContext != NULL); // Invoke the completion handler completionHandler(HwMac->VNic, completeContext, &Status); // Remove the extra ref HW_REMOVE_MAC_CONTEXT_REF(HwMac, 1); } VOID HwJoinTimeoutTimer( PVOID SystemSpecific1, PVOID FunctionContext, PVOID SystemSpecific2, PVOID SystemSpecific3 ) { PHW_MAC_CONTEXT macContext = (PHW_MAC_CONTEXT)FunctionContext; UNREFERENCED_PARAMETER(SystemSpecific1); UNREFERENCED_PARAMETER(SystemSpecific2); UNREFERENCED_PARAMETER(SystemSpecific3); // // Cancel the join operation if it has not already completed // if (HW_STOP_WAITING_FOR_JOIN(macContext)) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("Cancelled the Join Operation as it took too long\n")); HwJoinBSSComplete(macContext, NULL, NDIS_STATUS_FILE_NOT_FOUND); } // Remove the Async function ref HW_DECREMENT_ACTIVE_OPERATION_REF(macContext->Hw); } VOID Hw11NotifyEventConnectionState( _In_ PHW_MAC_CONTEXT HwMac, _In_ BOOLEAN Connected, _In_ ULONG StatusType, _In_ PVOID StatusBuffer, _In_ ULONG StatusBufferSize, _In_ BOOLEAN fProgramHardware ) { PHW_PEER_NODE peerNode; PDOT11_ASSOCIATION_START_PARAMETERS startParams; PDOT11_ASSOCIATION_COMPLETION_PARAMETERS completionParams; PDOT11_DISASSOCIATION_PARAMETERS disassocParams; ULONG associateID; UNREFERENCED_PARAMETER(StatusBufferSize); UNREFERENCED_PARAMETER(fProgramHardware); // // Inform the HW update change in connect state for this MAC // if (Connected) { HW_SET_MAC_CONTEXT_STATUS(HwMac, HW_MAC_CONTEXT_LINK_UP); } else { HW_CLEAR_MAC_CONTEXT_STATUS(HwMac, HW_MAC_CONTEXT_LINK_UP); } HwUpdateLinkState(HwMac->Hw, HwMac); switch (StatusType) { case NDIS_STATUS_DOT11_ASSOCIATION_START: { // Attempt to allocate a peer node data structure startParams = (PDOT11_ASSOCIATION_START_PARAMETERS)StatusBuffer; peerNode = HwFindPeerNode(HwMac, startParams->MacAddr, TRUE); if (peerNode == NULL) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("Unable to allocate state for new association peer\n")); break; } } break; case NDIS_STATUS_DOT11_ASSOCIATION_COMPLETION: { // Set the Association ID on the hardware completionParams = (PDOT11_ASSOCIATION_COMPLETION_PARAMETERS)StatusBuffer; if (Connected && (completionParams->uIHVDataOffset != 0)) { associateID = *((ULONG*)((PUCHAR)StatusBuffer + completionParams->uIHVDataOffset)); } else { associateID = 0; } peerNode = HwFindPeerNode(HwMac, completionParams->MacAddr, FALSE); if (peerNode != NULL) { // If the peer node is NULL, then we are reseting or something. peerNode->AssociateId = (USHORT)associateID; HwUpdateAssociateId(HwMac->Hw, peerNode->AssociateId); } else { MpTrace(COMP_ASSOC, DBG_NORMAL, ("Unable to find peer node on peer association completion\n")); } } break; case NDIS_STATUS_DOT11_DISASSOCIATION: { disassocParams = (PDOT11_DISASSOCIATION_PARAMETERS)StatusBuffer; // Invalidate the node that we just found peerNode = HwFindPeerNode(HwMac, disassocParams->MacAddr, FALSE); if (peerNode != NULL) { // This peer is no longer "active" HwFreePeerNode(HwMac, peerNode); // Clear the associate ID from the HW HwUpdateAssociateId(HwMac->Hw, 0); } } break; default: break; } } NDIS_STATUS Hw11StartScan( _In_ PHW_MAC_CONTEXT HwMac, _In_ PMP_SCAN_REQUEST ScanRequest, _In_ VNIC11_GENERIC_CALLBACK_FUNC CompletionHandler, _In_ PVOID ScanContext ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; // // Check if we are in the middle of an operation that does not // let us do a scan. Any operation that blocks a receive blocks // us from scan // HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); if (HW_TEST_ADAPTER_STATUS(HwMac->Hw, HW_CANNOT_RECEIVE_FLAGS | HW_CANNOT_SEND_FLAGS)) { // We cannot perform the scan HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); return HwGetAdapterStatus(HwMac->Hw); } // Add a ref count to the MAC context to avoid it from getting context // switched, etc HW_ADD_MAC_CONTEXT_REF(HwMac, 1); // // Save the scan completion handler and the scan context // HwMac->PendingScanCallback = CompletionHandler; HwMac->ScanContext = ScanContext; HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); // // Pass the scan to the HW // ndisStatus = HwStartScan(HwMac->Hw, HwMac, ScanRequest); if (ndisStatus != NDIS_STATUS_SUCCESS) { HwMac->PendingScanCallback = NULL; // Remove the extra ref HW_REMOVE_MAC_CONTEXT_REF(HwMac, 1); } else { // return pending since we are going to callback ndisStatus = NDIS_STATUS_PENDING; } return ndisStatus; } VOID HwScanComplete( _In_ PHW_MAC_CONTEXT HwMac, _In_ NDIS_STATUS Status ) { VNIC11_GENERIC_CALLBACK_FUNC completionHandler = NULL; PVOID completeContext = NULL; MpTrace(COMP_SCAN, DBG_NORMAL, ("Scan completed with status 0x%08x\n", Status)); HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); completionHandler = HwMac->PendingScanCallback; completeContext = HwMac->ScanContext; HwMac->PendingScanCallback = NULL; HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); MPASSERT(completeContext != NULL); // Invoke the completion handler completionHandler(HwMac->VNic, completeContext, &Status); // Remove the extra ref HW_REMOVE_MAC_CONTEXT_REF(HwMac, 1); } VOID Hw11CancelScan( _In_ PHW_MAC_CONTEXT HwMac ) { HwCancelScan(HwMac->Hw); } VOID HwMACContextPeriodicTimer( PVOID SystemSpecific1, PVOID FunctionContext, PVOID SystemSpecific2, PVOID SystemSpecific3 ) { PHW_MAC_CONTEXT macContext = (PHW_MAC_CONTEXT)FunctionContext; BOOLEAN requeue = TRUE; LARGE_INTEGER periodicTimerDuration; UNREFERENCED_PARAMETER(SystemSpecific1); UNREFERENCED_PARAMETER(SystemSpecific2); UNREFERENCED_PARAMETER(SystemSpecific3); do { MPASSERT(macContext->PeriodicTimerQueued != 0); // Dont continue if we are pausing, etc if (HW_TEST_MAC_CONTEXT_STATUS(macContext, (HW_MAC_CONTEXT_PAUSED | HW_MAC_CONTEXT_PAUSING))) { MpTrace(COMP_MISC, DBG_NORMAL, ("Aborting MAC context periodic timer\n")); requeue = FALSE; break; } // Update the TX data rate. HwUpdateTxDataRate(macContext); }while (FALSE); if (requeue) { MpTrace(COMP_MISC, DBG_LOUD, ("Requeuing MAC context periodic timer\n")); // Requeue the periodic time periodicTimerDuration.QuadPart = Int32x32To64(HW_CONTEXT_PERIODIC_TIMER_DURATION, -10000); // We dont add a ref for the periodic timer. Instead we set a flag that its queued. This is // because we dont want to wait for this timer when we are being deactivated, etc macContext->PeriodicTimerQueued = 1; NdisSetTimerObject(macContext->Timer_Periodic, periodicTimerDuration, 0, NULL); } else { // Dont queue again macContext->PeriodicTimerQueued = 0; } } NDIS_STATUS Hw11SetBeaconEnabledFlag( _In_ PHW_MAC_CONTEXT HwMac, BOOLEAN BeaconEnabled, BOOLEAN fProgramHardware ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; if (BeaconEnabled == HwMac->BeaconEnabled) { // Do nothing MpTrace(COMP_MISC, DBG_LOUD, ("HwMac(%d): Ignoring Beacon Enabled flag with no change\n", HwMac->PortNumber)); return NDIS_STATUS_SUCCESS; } // We dont want a context switch to happen while we are doing this HW_INCREMENT_ACTIVE_OPERATION_REF(HwMac->Hw); HwMac->BeaconEnabled = BeaconEnabled; if (fProgramHardware && (HwMac->BSSStarted == TRUE)) { if (BeaconEnabled) { // Start BSS MpTrace(COMP_MISC, DBG_LOUD, ("HwMac(%d): Starting BSS beaconing\n", HwMac->PortNumber)); HwEnableBSSBeacon(HwMac->Hw, HwMac); } else { // Stop BSS MpTrace(COMP_MISC, DBG_LOUD, ("HwMac(%d): Stopping BSS beaconing\n", HwMac->PortNumber)); HwDisableBSSBeacon(HwMac->Hw); } } else { // Just update the local state MpTrace(COMP_MISC, DBG_LOUD, ("HwMac(%d): Updated Beacon Enabled flag to %s WITH__out programming hardware\n", HwMac->PortNumber, (BeaconEnabled ? "TRUE" : "FALSE") )); } HW_DECREMENT_ACTIVE_OPERATION_REF(HwMac->Hw); return ndisStatus; } NDIS_STATUS Hw11SetBeaconIE( _In_ PHW_MAC_CONTEXT HwMac, _In_ PVOID pBeaconIEBlob, _In_ ULONG uBeaconIEBlobSize, _In_ BOOLEAN fProgramHardware ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PUCHAR oldBeaconIEBlob = NULL; PUCHAR newBeaconIEBlob = NULL; // // The ISR can be reading the beacon IE at this time. Process // this OID at device IRQL // if (HwMac->BeaconIEBlob != NULL) { // Save the old beacon since we would be replacing it oldBeaconIEBlob = HwMac->BeaconIEBlob; } MP_ALLOCATE_MEMORY(HwMac->Hw->MiniportAdapterHandle, &newBeaconIEBlob, uBeaconIEBlobSize, HW_MEMORY_TAG ); if (newBeaconIEBlob == NULL) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to allocate space to store beacon information\n")); return NDIS_STATUS_RESOURCES; } NdisMoveMemory(newBeaconIEBlob, pBeaconIEBlob, uBeaconIEBlobSize); // Raise to device IRQL before updating the Beacon IE blob. This will // ensure that if the HwProcessBeaconInterrupt is in progress it will get the // correct value HwSetBeaconIEWithSync(HwMac, newBeaconIEBlob, uBeaconIEBlobSize); if (fProgramHardware) { // Update the beacon on the hardware. HwSetupBeacon(HwMac->Hw, HwMac); } // Free the old beacon buffer. It has been replaced with the new beacon buffer if (oldBeaconIEBlob) MP_FREE_MEMORY(oldBeaconIEBlob); return ndisStatus; } NDIS_STATUS Hw11SetProbeResponseIE( _In_ PHW_MAC_CONTEXT HwMac, _In_ PVOID pResponseIEBlob, _In_ ULONG uResponseIEBlobSize, _In_ BOOLEAN fProgramHardware ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; // This doesnt need to be programmed on the hardware. It gets picked up UNREFERENCED_PARAMETER(fProgramHardware); HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); do { if (HwMac->ProbeResponseIEBlob != NULL) { MP_FREE_MEMORY(HwMac->ProbeResponseIEBlob); } HwMac->ProbeResponseIEBlobSize = 0; MP_ALLOCATE_MEMORY(HwMac->Hw->MiniportAdapterHandle, &HwMac->ProbeResponseIEBlob, uResponseIEBlobSize, HW_MEMORY_TAG ); if (HwMac->ProbeResponseIEBlob == NULL) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to allocate space to store probe response information\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } NdisMoveMemory(HwMac->ProbeResponseIEBlob, pResponseIEBlob, uResponseIEBlobSize); HwMac->ProbeResponseIEBlobSize = uResponseIEBlobSize; }while (FALSE); HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); return ndisStatus; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials