Sample Code
Windows Driver Samples/ Native Wi-Fi Miniport Sample Driver/ C++/ extsta/ st_adhoc.c/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: St_Adhoc.c Abstract: STA layer adhoc connection functions Revision History: When What ---------- ---------------------------------------------- 08-01-2005 Created 01-15-2006 Renamed sta_adhoc.c to st_adhoc.c Notes: --*/ #include "precomp.h" #include "st_aplst.h" #include "st_adhoc.h" #include "st_scan.h" #include "st_send.h" #if DOT11_TRACE_ENABLED #include "St_adhoc.tmh" #endif // // The following is how Ad Hoc connection works: // 1. We have a list of beaconing Ad Hoc stations through active or passive scanning. // Go through the list, find all the stations that match our desired SSID // and BSSID list. // 2. For each station found in step 1, we do the following until the start request succeeds for the // a station. // a. Issue a join request using the station's BSSID and SSID. // b. If we get response, do a start request using the station's BSSID, SSID and ATIM. // 3. If step 2 fails, we start our own Ad Hoc network. // 4. Indicate connection start and connection complete. At this stage, no station is indicated // as associated. // 5. When a beacon frame or probe response frame is received from a Ad Hoc station, if it // has not been indicated as associated but it matches with our BSSID/SSID, indicate association // start and associate complete for the station. If the station has been indicated as associated // but its SSID/BSSID do not match with ours, indicate disassociation for the station. // 6. We have a timer routine that disassociates any station from which no beacon or probe response // frame is received for a specified period of time. It also removes the station from the list if // no beacon or probe response is received for another specified period of time. // NTSTATUS StaConnectAdHoc( _In_ PMP_EXTSTA_PORT pStation ) { NDIS_STATUS ndisStatus; // // Cannot connect when scan is in progress // if (STA_TEST_SCAN_FLAG(pStation, STA_EXTERNAL_SCAN_IN_PROGRESS)) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("External scan already in progress. Ignoring adhoc connect request\n")); return NDIS_STATUS_DOT11_MEDIA_IN_USE; } // // Check the AdHoc state // NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (pStation->AdHocStaInfo.AdHocState != STA_ADHOC_DISCONNECTED) { ndisStatus = NDIS_STATUS_INVALID_STATE; } else { ndisStatus = NDIS_STATUS_SUCCESS; pStation->AdHocStaInfo.AdHocState |= STA_ADHOC_CONNECTION_IN_PROGRESS; } NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); // // Schedule a work item to do Ad Hoc connect if we can proceed. // if (ndisStatus == NDIS_STATUS_SUCCESS) { NdisQueueIoWorkItem( pStation->AdHocStaInfo.ConnectWorkItem, StaConnectAdHocWorkItem, pStation ); } return ndisStatus; } NTSTATUS StaDisconnectAdHoc( _In_ PMP_EXTSTA_PORT pStation ) { DOT11_DISASSOCIATION_PARAMETERS disassocParam; BOOLEAN cancelled; NDIS_STATUS ndisStatus; // // Check the AdHoc state // NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (pStation->AdHocStaInfo.AdHocState != STA_ADHOC_CONNECTED) { ndisStatus = NDIS_STATUS_INVALID_STATE; } else { ndisStatus = NDIS_STATUS_SUCCESS; pStation->AdHocStaInfo.AdHocState |= STA_ADHOC_DISCONNECTION_IN_PROGRESS; // // Cancel the AdHoc watchdog timer. If we failed to cancel the timer, // wait till the timer counter goes to 0. // cancelled = NdisCancelTimerObject(pStation->AdHocStaInfo.WatchdogTimer); if (!cancelled) { while (pStation->AdHocStaInfo.TimerCounter != 0) { NdisStallExecution(50); // 50 us } } else { NdisInterlockedDecrement(&pStation->AdHocStaInfo.TimerCounter); } } NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (ndisStatus != NDIS_STATUS_SUCCESS) return ndisStatus; // // Send every station on the ad hoc network a de-auth message and clear their // association states. // StaClearStaListAssocState(pStation, TRUE); // // Stop beaconing and receiving data frames. // StaStopAdHocBeaconing(pStation); if (pStation->AdHocStaInfo.BSSDescription) { MP_FREE_MEMORY(pStation->AdHocStaInfo.BSSDescription); pStation->AdHocStaInfo.BSSDescription = NULL; } // // Indicate up DISASSOCIATION status // MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uReason = DOT11_DISASSOC_REASON_OS; NdisFillMemory(disassocParam.MacAddr, sizeof(DOT11_MAC_ADDRESS), 0xff); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_DISASSOCIATION, NULL, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); // Also notify hw about disconnected status VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), FALSE, NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); pStation->AdHocStaInfo.AdHocState = STA_ADHOC_DISCONNECTED; NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); return ndisStatus; } NDIS_STATUS StaInitializeAdHocStaInfo( _In_ PMP_EXTSTA_PORT pStation ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; NDIS_TIMER_CHARACTERISTICS timerChar; BOOLEAN lockAllocated = FALSE; do { pStation->AdHocStaInfo.fBeaconing = FALSE; pStation->AdHocStaInfo.BSSDescription = NULL; pStation->AdHocStaInfo.StaCount = 0; pStation->AdHocStaInfo.DeauthStaCount = 0; pStation->AdHocStaInfo.AdHocState = STA_ADHOC_DISCONNECTED; ndisStatus = MP_ALLOCATE_READ_WRITE_LOCK(&pStation->AdHocStaInfo.StaListLock, STA_GET_MP_PORT(pStation)->MiniportAdapterHandle); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate adhoc read/write lock\n")); break; } lockAllocated = TRUE; NdisInitializeListHead(&pStation->AdHocStaInfo.StaList); NdisAllocateSpinLock(&pStation->AdHocStaInfo.StaInfoLock); // // Allocate the work item (StaConnectAdHocWorkItem) // pStation->AdHocStaInfo.ConnectWorkItem = NdisAllocateIoWorkItem(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle); if(pStation->AdHocStaInfo.ConnectWorkItem == NULL) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate adhoc connect workitem\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } NdisInitializeEvent(&pStation->AdHocStaInfo.JoinCompletionEvent); NdisInitializeEvent(&pStation->AdHocStaInfo.StartBSSCompletionEvent); NdisInitializeEvent(&pStation->AdHocStaInfo.StopBSSCompletionEvent); 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 = EXTSTA_MEMORY_TAG; timerChar.TimerFunction = StaAdHocWatchdogTimerRoutine; timerChar.FunctionContext = pStation; ndisStatus = NdisAllocateTimerObject( STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &timerChar, &pStation->AdHocStaInfo.WatchdogTimer ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate adhoc watchdog timer\n")); break; } pStation->AdHocStaInfo.TimerCounter = 0; pStation->AdHocStaInfo.AsyncFuncCount = 0; } while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { if (pStation->AdHocStaInfo.WatchdogTimer) { NdisFreeTimerObject(pStation->AdHocStaInfo.WatchdogTimer); pStation->AdHocStaInfo.WatchdogTimer = NULL; } if(pStation->AdHocStaInfo.ConnectWorkItem) { NdisFreeIoWorkItem(pStation->AdHocStaInfo.ConnectWorkItem); pStation->AdHocStaInfo.ConnectWorkItem = NULL; } if (lockAllocated) { MP_FREE_READ_WRITE_LOCK(&pStation->AdHocStaInfo.StaListLock); } } return ndisStatus; } VOID StaFreeAdHocStaInfo( _In_ PMP_EXTSTA_PORT pStation ) { if (pStation->AdHocStaInfo.WatchdogTimer) { NdisFreeTimerObject(pStation->AdHocStaInfo.WatchdogTimer); pStation->AdHocStaInfo.WatchdogTimer = NULL; } if(pStation->AdHocStaInfo.ConnectWorkItem) { NdisFreeIoWorkItem(pStation->AdHocStaInfo.ConnectWorkItem); pStation->AdHocStaInfo.ConnectWorkItem = NULL; } MP_FREE_READ_WRITE_LOCK(&pStation->AdHocStaInfo.StaListLock); } NDIS_STATUS StaSaveAdHocStaInfo( _In_ PMP_EXTSTA_PORT pStation, _In_ PMP_RX_MPDU pFragment, _In_ PDOT11_BEACON_FRAME pDot11BeaconFrame, _In_ ULONG InfoElemBlobSize ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONGLONG HostTimeStamp; MP_RW_LOCK_STATE LockState; PSTA_ADHOC_STA_ENTRY StaEntry = NULL; PDOT11_MGMT_HEADER pMgmtPktHeader; PVOID pInfoElemBlob = NULL; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PLIST_ENTRY pHead = NULL, pEntry = NULL; UCHAR channel; pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment); NdisGetCurrentSystemTime((PLARGE_INTEGER)&HostTimeStamp); __try { // // Lock the entire list // MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); // // Search if we already have the entry for the station on the list. // pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); if (MP_COMPARE_MAC_ADDRESS(StaEntry->MacAddress, pMgmtPktHeader->SA)) break; pEntry = pEntry->Flink; } if (pEntry == pHead) { if (AdHocStaInfo->StaCount >= pStation->RegInfo->AdhocStationMaxCount) { // // We have reached the limit on the number of adhoc networks we would // maintain state for. Dont add new ones. When the adhoc watchdog // runs, it would reduce this number // ndisStatus = NDIS_STATUS_RESOURCES; StaEntry = NULL; __leave; } // // Create a new entry for this station. // MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &StaEntry, sizeof(STA_ADHOC_STA_ENTRY), EXTSTA_MEMORY_TAG); if (StaEntry == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } // // Initialize the new entry // StaEntry->AllocatedIEBlobSize = 0; StaEntry->InfoElemBlobPtr = NULL; StaEntry->InfoElemBlobSize = 0; StaEntry->PhyId = STA_DESIRED_PHY_MAX_COUNT; // set to an invalid Phy ID StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; NdisMoveMemory(StaEntry->MacAddress, pMgmtPktHeader->SA, sizeof(DOT11_MAC_ADDRESS)); } // // Update the information // if (StaEntry == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } NdisMoveMemory(StaEntry->Dot11BSSID, pMgmtPktHeader->BSSID, sizeof(DOT11_MAC_ADDRESS)); StaEntry->HostTimestamp = HostTimeStamp; StaEntry->BeaconTimestamp = pDot11BeaconFrame->Timestamp; StaEntry->BeaconInterval = pDot11BeaconFrame->BeaconInterval; StaEntry->Dot11Capability = pDot11BeaconFrame->Capability; StaEntry->ProbeRequestsSent = 0; // // Get channel number at which the frame was received. // if (Dot11GetChannelForDSPhy((PUCHAR)&pDot11BeaconFrame->InfoElements, InfoElemBlobSize, &channel) != NDIS_STATUS_SUCCESS) { channel = pFragment->Msdu->Channel; } if (channel != 0) { StaEntry->Channel = channel; } // // Increase the information blob size if necessary // if (StaEntry->AllocatedIEBlobSize < InfoElemBlobSize) { MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &pInfoElemBlob, InfoElemBlobSize, EXTSTA_MEMORY_TAG); if (pInfoElemBlob == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } // // Delete any old blob buffer // if (StaEntry->InfoElemBlobPtr) { MP_FREE_MEMORY(StaEntry->InfoElemBlobPtr); } StaEntry->InfoElemBlobPtr = pInfoElemBlob; StaEntry->AllocatedIEBlobSize = InfoElemBlobSize; } StaEntry->InfoElemBlobSize = InfoElemBlobSize; // // Update/Save the information element block // NdisMoveMemory(StaEntry->InfoElemBlobPtr, &pDot11BeaconFrame->InfoElements, InfoElemBlobSize); // // Add the new adhoc station to our list // if (pEntry == pHead) { InsertTailList(pHead, &StaEntry->Link); AdHocStaInfo->StaCount++; } // // Indicate the possible association/disassociation for this StaEntry // StaAdHocIndicateAssociation(pStation, StaEntry); } __finally { MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); if (ndisStatus != NDIS_STATUS_SUCCESS) { if (pEntry == pHead && StaEntry) { if (StaEntry->InfoElemBlobPtr) { MP_FREE_MEMORY(StaEntry->InfoElemBlobPtr); } MP_FREE_MEMORY(StaEntry); } } } return ndisStatus; } NDIS_STATUS StaResetAdHocStaInfo( _In_ PMP_EXTSTA_PORT pStation, _In_ BOOLEAN flushStaList ) { MP_RW_LOCK_STATE LockState; PSTA_ADHOC_STA_ENTRY StaEntry; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PLIST_ENTRY pEntry = NULL; BOOLEAN cancelled; BOOLEAN connected; BOOLEAN connecting; DOT11_DISASSOCIATION_PARAMETERS disassocParam; NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); connected = (BOOLEAN)(pStation->AdHocStaInfo.AdHocState == STA_ADHOC_CONNECTED); connecting = (BOOLEAN)(pStation->AdHocStaInfo.AdHocState & STA_ADHOC_CONNECTION_IN_PROGRESS); pStation->AdHocStaInfo.AdHocState |= STA_ADHOC_RESET_PENDING; // // If we got a reset while adhoc connect is pending (possible for NdisReset) // wait for the adhoc thread to finish // if (connecting) { NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); // // We loop waiting for the connect to finish // while ((pStation->AdHocStaInfo.AdHocState & STA_ADHOC_CONNECTION_IN_PROGRESS) != 0) { NdisMSleep(10000); } NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); } // // If we are currently connected, cancel the AdHoc watchdog timer. // If we failed to cancel the timer, wait till the timer counter goes to 0. // if (connected) { cancelled = NdisCancelTimerObject(AdHocStaInfo->WatchdogTimer); if (!cancelled) { while (AdHocStaInfo->TimerCounter != 0) { NdisStallExecution(50); // 50 us } } else { NdisInterlockedDecrement(&AdHocStaInfo->TimerCounter); } } NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); // // Free everything on the list if asked to do so. // if (flushStaList) { MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); while (!IsListEmpty(&AdHocStaInfo->StaList)) { pEntry = RemoveHeadList(&AdHocStaInfo->StaList); StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); if (StaEntry->InfoElemBlobPtr) { MP_FREE_MEMORY(StaEntry->InfoElemBlobPtr); } MP_FREE_MEMORY(StaEntry); } AdHocStaInfo->StaCount = 0; AdHocStaInfo->DeauthStaCount = 0; MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); } // // Stop beaconing // if (connected) { StaStopAdHocBeaconing(pStation); } // // Also notify hw about disconnected status // MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uReason = DOT11_DISASSOC_REASON_OS; NdisFillMemory(disassocParam.MacAddr, sizeof(DOT11_MAC_ADDRESS), 0xff); VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), FALSE, NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); // // Reset state // NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); pStation->AdHocStaInfo.AdHocState = STA_ADHOC_DISCONNECTED; NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); return NDIS_STATUS_SUCCESS; } void StaClearStaListAssocState( _In_ PMP_EXTSTA_PORT pStation, _In_ BOOLEAN SendDeauth ) { MP_RW_LOCK_STATE LockState; PSTA_ADHOC_STA_ENTRY StaEntry = NULL; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PLIST_ENTRY pHead = NULL, pEntry = NULL; UCHAR Buffer[sizeof(DOT11_MGMT_HEADER) + sizeof(DOT11_DEAUTH_FRAME)]; PDOT11_MGMT_HEADER MgmtPacket = (PDOT11_MGMT_HEADER)Buffer; PDOT11_DEAUTH_FRAME DeauthFrame; // // Initialize the de-auth message if we are to send a de-auth message // if (SendDeauth) { MgmtPacket->FrameControl.Version = 0x0; MgmtPacket->FrameControl.Type = DOT11_FRAME_TYPE_MANAGEMENT; MgmtPacket->FrameControl.Subtype = DOT11_MGMT_SUBTYPE_DEAUTHENTICATION; MgmtPacket->FrameControl.ToDS = 0x0; // Default value for Mgmt frames MgmtPacket->FrameControl.FromDS = 0x0; // Default value for Mgmt frames MgmtPacket->FrameControl.MoreFrag = 0x0; MgmtPacket->FrameControl.Retry = 0x0; MgmtPacket->FrameControl.PwrMgt = 0x0; MgmtPacket->FrameControl.MoreData = 0x0; MgmtPacket->FrameControl.WEP = 0x0; // no WEP MgmtPacket->FrameControl.Order = 0x0; // no order MgmtPacket->SequenceControl.usValue = 0; NdisMoveMemory(MgmtPacket->SA, VNic11QueryMACAddress(STA_GET_VNIC(pStation)), DOT11_ADDRESS_SIZE); NdisMoveMemory(MgmtPacket->BSSID, VNic11QueryCurrentBSSID(STA_GET_VNIC(pStation)), DOT11_ADDRESS_SIZE); DeauthFrame = (PDOT11_DEAUTH_FRAME)Add2Ptr(MgmtPacket, sizeof(DOT11_MGMT_HEADER)); DeauthFrame->ReasonCode = DOT11_MGMT_REASON_DEAUTH_LEAVE_SS; } MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; // // If we are to send de-auth messages, send one to each associated station. // if (SendDeauth && StaEntry->AssocState == dot11_assoc_state_auth_assoc) { NdisMoveMemory(MgmtPacket->DA, StaEntry->MacAddress, DOT11_ADDRESS_SIZE); BasePortSendInternalPacket(STA_GET_MP_PORT(pStation), Buffer, sizeof(Buffer)); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Sent deauth packet to Ad Hoc station: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; } AdHocStaInfo->DeauthStaCount = 0; MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); } BOOLEAN StaAcceptStation( _In_ PMP_EXTSTA_PORT pStation, _In_ PSTA_ADHOC_STA_ENTRY StaEntry ) { ULONG index; DOT11_PHY_TYPE PhyType; DOT11_RATE_SET rateSet = {0}; NDIS_STATUS ndisStatus; UCHAR SecIELength; PUCHAR SecIEData; RSN_IE_INFO RSNIEInfo; // // This function determines if we could accept a station on the same // ad hoc network as ours based on its attributes other than SSID/BSSID. // // // Check if the StaEntry is on the exclused MAC list // for (index = 0; index < pStation->Config.ExcludedMACAddressCount; index++) { if (NdisEqualMemory(StaEntry->MacAddress, pStation->Config.ExcludedMACAddressList[index], sizeof(DOT11_MAC_ADDRESS)) == 1) break; } if (index < pStation->Config.ExcludedMACAddressCount) return FALSE; // // Check if the StaEntry matches the desired PHY list. // PhyType = VNic11DeterminePHYType(STA_GET_VNIC(pStation), StaEntry->Dot11Capability, StaEntry->Channel); StaEntry->PhyId = StaGetPhyIdByType(pStation, PhyType); if (!StaMatchPhyId(pStation, StaEntry->PhyId)) return FALSE; // // Check if all basic data rates are supported. // ndisStatus = Dot11GetRateSetFromInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, TRUE, &rateSet); if (ndisStatus != NDIS_STATUS_SUCCESS) return FALSE; ndisStatus = VNic11ValidateOperationalRates(STA_GET_VNIC(pStation), StaEntry->PhyId, rateSet.ucRateSet, rateSet.uRateSetLength); if (ndisStatus != NDIS_STATUS_SUCCESS) return FALSE; // // Check for Privacy attribute. // if (StaEntry->Dot11Capability.Privacy && pStation->Config.UnicastCipherAlgorithm == DOT11_CIPHER_ALGO_NONE) return FALSE; // // Check RSNA IE if our auth algo is RSNA_PSK // if (pStation->Config.AuthAlgorithm == DOT11_AUTH_ALGO_RSNA_PSK) { ndisStatus = Dot11GetInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_RSN, &SecIELength, (PVOID)&SecIEData); if (ndisStatus != NDIS_STATUS_SUCCESS) return FALSE; ndisStatus = Dot11ParseRNSIE(SecIEData, RSNA_OUI_PREFIX, SecIELength, &RSNIEInfo); if (ndisStatus != NDIS_STATUS_SUCCESS) return FALSE; // // Check if the station is running RNSA with AKM and ciphers that meet our requirement. // if (!StaMatchRSNInfo(pStation, &RSNIEInfo)) return FALSE; // // Save station's group cipher // StaEntry->GroupCipher = Dot11GetGroupCipherFromRSNIEInfo(&RSNIEInfo); } return TRUE; } NDIS_STATUS StaAdhocJoinCompletionHandler( _In_ PMP_PORT Port, _In_ PVOID Data ) { PMP_EXTSTA_PORT pStation = MP_GET_STA_PORT(Port); // Set the join completion event pStation->AdHocStaInfo.JoinCompletionStatus = *((PNDIS_STATUS)Data); NdisSetEvent(&pStation->AdHocStaInfo.JoinCompletionEvent); // Release the context switch barrier VNic11ReleaseCtxSBarrier(STA_GET_VNIC(pStation)); return NDIS_STATUS_SUCCESS; } NDIS_STATUS StaAdhocJoinChannelSwitchCompletionHandler( _In_ PMP_PORT Port, _In_ PVOID Data ) { PMP_EXTSTA_PORT pStation = MP_GET_STA_PORT(Port); NDIS_STATUS ndisStatus = *((PNDIS_STATUS)Data); if (ndisStatus == NDIS_STATUS_SUCCESS) { VNic11AcquireCtxSBarrier(STA_GET_VNIC(pStation)); // Call Join on the H/W // // Hardware function handles timer synchronization with this // access point // ndisStatus = VNic11JoinBSS(STA_GET_VNIC(pStation), pStation->AdHocStaInfo.JoinBSSDescription, STA11_ADHOC_JOIN_TIMEOUT, StaAdhocJoinCompletionHandler ); if (ndisStatus != NDIS_STATUS_PENDING) { // Failed (Join cannot succeed synchronously) VNic11ReleaseCtxSBarrier(STA_GET_VNIC(pStation)); } else { // This translates to status success ndisStatus = NDIS_STATUS_SUCCESS; } } if (ndisStatus != NDIS_STATUS_SUCCESS) { pStation->AdHocStaInfo.JoinCompletionStatus = *((PNDIS_STATUS)Data); NdisSetEvent(&pStation->AdHocStaInfo.JoinCompletionEvent); } return NDIS_STATUS_SUCCESS; } NDIS_STATUS StaJoinAdHoc ( _In_ PMP_EXTSTA_PORT pStation, _In_ PSTA_ADHOC_STA_ENTRY StaEntry ) { PMP_BSS_DESCRIPTION BSSDescription = NULL; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; __try { // // Notify the H/W about connection start // StaAdhocIndicateConnectionStart(pStation, StaEntry->Dot11BSSID, TRUE); // // Allocate a BSS description structure (we allocate 3 bytes more for possible addition of // DS parameter IE, that contains channel number). // // Integer overflow if ((FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + StaEntry->InfoElemBlobSize) > (FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + StaEntry->InfoElemBlobSize + 3)) { ndisStatus = NDIS_STATUS_FAILURE; __leave; } MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &BSSDescription, FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + StaEntry->InfoElemBlobSize + 3, MP_MEMORY_TAG); if (BSSDescription == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } // // Initialize the BSS description structure from StaEntry // NdisMoveMemory(BSSDescription->BSSID, StaEntry->Dot11BSSID, sizeof(DOT11_MAC_ADDRESS)); BSSDescription->BSSType = dot11_BSS_type_independent; BSSDescription->BeaconPeriod = StaEntry->BeaconInterval; BSSDescription->Timestamp = StaEntry->BeaconTimestamp; BSSDescription->Capability.usValue = StaEntry->Dot11Capability.usValue; NdisMoveMemory(BSSDescription->IEBlobs, StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize); // Use the same buffers for beacon and probe responses BSSDescription->BeaconIEBlobOffset = 0; BSSDescription->BeaconIEBlobSize = StaEntry->InfoElemBlobSize; BSSDescription->ProbeIEBlobOffset = 0; BSSDescription->ProbeIEBlobSize = StaEntry->InfoElemBlobSize; BSSDescription->IEBlobsSize = StaEntry->InfoElemBlobSize; // Specify the Phy ID, channel to use BSSDescription->Channel = StaEntry->Channel; BSSDescription->PhyId = StaEntry->PhyId; // // Before we are doing the sync join, which could take a while, check if reset // is pending. If so, we quit. // NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (pStation->AdHocStaInfo.AdHocState & STA_ADHOC_RESET_PENDING) ndisStatus = NDIS_STATUS_REQUEST_ABORTED; NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; // // Reset an event for signalling the join completion. Then call hardware // interface function to perform join request. Unlike infrastructure, // we wait synchronously for the join to complete. // NdisResetEvent(&pStation->AdHocStaInfo.JoinCompletionEvent); pStation->AdHocStaInfo.JoinBSSDescription = BSSDescription; // Set the channel & PHY ID before we do the join ndisStatus = VNic11SetChannel(STA_GET_VNIC(pStation), BSSDescription->Channel, BSSDescription->PhyId, TRUE, StaAdhocJoinChannelSwitchCompletionHandler ); if (ndisStatus == NDIS_STATUS_PENDING) { // Hardware will start the channel switch and call us back // when the switch completes & then we would do a join // This is success for the channel switch attempt ndisStatus = NDIS_STATUS_SUCCESS; } else if (ndisStatus == NDIS_STATUS_SUCCESS) { // Start the Join ndisStatus = StaAdhocJoinChannelSwitchCompletionHandler(STA_GET_MP_PORT(pStation), &ndisStatus); } else { // Failure __leave; } // // Wait for the event that signals join completion // NdisWaitEvent(&pStation->AdHocStaInfo.JoinCompletionEvent, 0); ndisStatus = pStation->AdHocStaInfo.JoinCompletionStatus; } __finally { // Failed, status to the H/W StaAdhocIndicateConnectionCompletion(pStation, ndisStatus, TRUE); if (BSSDescription) { MP_FREE_MEMORY(BSSDescription); } } return ndisStatus; } NDIS_STATUS Sta11StartBSSCompleteCallback( _In_ PMP_PORT Port, _In_ PVOID Data ) { PMP_EXTSTA_PORT pStation = MP_GET_STA_PORT(Port); // Set the start completion event pStation->AdHocStaInfo.StartBSSCompletionStatus = *((PNDIS_STATUS)Data); NdisSetEvent(&pStation->AdHocStaInfo.StartBSSCompletionEvent); return NDIS_STATUS_SUCCESS; } NDIS_STATUS StaStartAdHoc( _In_ PMP_EXTSTA_PORT pStation, _In_opt_ PSTA_ADHOC_STA_ENTRY StaEntry, _In_reads_bytes_opt_(DOT11_ADDRESS_SIZE) DOT11_MAC_ADDRESS BSSID ) /*++ Routine Description: Start AdHoc mode The caller should guarantee serialization!!! Arguments: pStation - The pStation on which the Ad Hoc mode should be started StaEntry - One of the existing pStations in the Ad Hoc network, or NULL if it is a new network. BSSID - BSSID of the ad hoc network we are starting when StaEntry is NULL. Return Value: --*/ { PMP_BSS_DESCRIPTION BSSDescription = NULL; DOT11_RATE_SET rateSet = {0,0}; ULONG index; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PVNIC pNic = STA_GET_VNIC(pStation); UCHAR channel; PUCHAR tmpPtr; UCHAR size; USHORT ATIMWindow; DOT11_CAPABILITY dot11Capability = {0}; STA_FHSS_IE FHSSIE = {0}; BOOLEAN IEPresent; DOT11_SSID dot11SSID; PUCHAR infoBlobPtr; USHORT infoBlobSize; DOT11_PHY_TYPE PhyType; BOOLEAN set; __try { // // Notify the H/W about connection start // if (StaEntry) { StaAdhocIndicateConnectionStart(pStation, StaEntry->Dot11BSSID, TRUE); } else { StaAdhocIndicateConnectionStart(pStation, BSSID, TRUE); } // // Allocate a BSS description structure with maximum possible IE field. // MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &BSSDescription, FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + STA11_MAX_IE_BLOB_SIZE, MP_MEMORY_TAG); if (BSSDescription == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } NdisZeroMemory(BSSDescription, FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + STA11_MAX_IE_BLOB_SIZE); // // Initialize the BSS description structure from StaEntry or our own pStation information. // BSSDescription->BSSType = dot11_BSS_type_independent; BSSDescription->Timestamp = 0; if (StaEntry) { NdisMoveMemory(BSSDescription->BSSID, StaEntry->Dot11BSSID, sizeof(DOT11_MAC_ADDRESS)); BSSDescription->BeaconPeriod = StaEntry->BeaconInterval; BSSDescription->Timestamp = StaEntry->BeaconTimestamp; } else { NdisMoveMemory(BSSDescription->BSSID, BSSID, sizeof(DOT11_MAC_ADDRESS)); BSSDescription->BeaconPeriod = (USHORT) VNic11QueryBeaconPeriod(pNic); BSSDescription->Timestamp = 0; } NdisMoveMemory(BSSDescription->MacAddress, VNic11QueryMACAddress(pNic), sizeof(DOT11_MAC_ADDRESS)); // // Fill the capabilityInformation // dot11Capability.ESS = 0; dot11Capability.IBSS = 1; dot11Capability.CFPollable = 0; // CFPollable is always unavailable in AdHoc mode dot11Capability.CFPollRequest = 0; if (StaEntry) { dot11Capability.Privacy = StaEntry->Dot11Capability.Privacy; } else { dot11Capability.Privacy = (pStation->Config.UnicastCipherAlgorithm != DOT11_CIPHER_ALGO_NONE) ? 1 : 0; } PhyType = VNic11QueryCurrentPhyType(pNic); switch (PhyType) { case dot11_phy_type_erp: set = VNic11QueryShortSlotTimeOptionImplemented(pNic, FALSE); if (set) { set = VNic11QueryShortSlotTimeOptionEnabled(pNic, FALSE); } dot11Capability.ShortSlotTime = set ? 1 : 0; set = VNic11QueryDsssOfdmOptionImplemented(pNic, FALSE); if (set) { set = VNic11QueryDsssOfdmOptionEnabled(pNic, FALSE); } dot11Capability.DSSSOFDM = set ? 1 : 0; // fall through case dot11_phy_type_hrdsss: set = VNic11QueryShortPreambleOptionImplemented(pNic, FALSE); dot11Capability.ShortPreamble = set ? 1: 0; set = VNic11QueryPbccOptionImplemented(pNic, FALSE); dot11Capability.PBCC = set ? 1: 0; set = VNic11QueryChannelAgilityPresent(pNic, FALSE); if (set) { set = VNic11QueryChannelAgilityEnabled(pNic, FALSE); } dot11Capability.ChannelAgility = set ? 1 : 0; } BSSDescription->Capability.usValue = dot11Capability.usValue; // usValue is initialized to 0 // // Set the starting address and size of the beacon blob. // BSSDescription->BeaconIEBlobOffset = 0; infoBlobPtr = &BSSDescription->IEBlobs[BSSDescription->BeaconIEBlobOffset]; infoBlobSize = STA11_MAX_IE_BLOB_SIZE; // // Add SSID. // if (StaEntry) { ndisStatus = Dot11GetInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_SSID, &size, &tmpPtr); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; // extra check for prefast if (size > DOT11_SSID_MAX_LENGTH) { ndisStatus = NDIS_STATUS_INVALID_LENGTH; __leave; } dot11SSID.uSSIDLength = size; NdisMoveMemory(dot11SSID.ucSSID, tmpPtr, dot11SSID.uSSIDLength); } else { // // Use our desired SSID. // dot11SSID = pStation->Config.SSID; } ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_SSID, (UCHAR)(dot11SSID.uSSIDLength), dot11SSID.ucSSID); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; // // Add basic rate set. // if (StaEntry) { ndisStatus = Dot11GetRateSetFromInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, TRUE, &rateSet); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; } else { VNic11QueryBasicRateSet(STA_GET_VNIC(pStation), &rateSet, FALSE); for (index = 0; index < rateSet.uRateSetLength; index++) { rateSet.ucRateSet[index] |= 0x80; } } ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_SUPPORTED_RATES, (UCHAR)((rateSet.uRateSetLength > 8) ? 8 : rateSet.uRateSetLength), rateSet.ucRateSet); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; if (rateSet.uRateSetLength > (UCHAR)8) { ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_EXTD_SUPPORTED_RATES, (UCHAR)(rateSet.uRateSetLength - 8), rateSet.ucRateSet + 8); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; } // // Add PHY specific IEs // switch (PhyType) { case dot11_phy_type_erp: case dot11_phy_type_hrdsss: case dot11_phy_type_dsss: // // Attach DSSS IE // if (StaEntry) { ndisStatus = Dot11CopyInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_DS_PARAM_SET, &size, sizeof(channel), &channel); IEPresent = (ndisStatus == NDIS_STATUS_SUCCESS && size == sizeof(channel)) ? TRUE : FALSE; } else { channel = (UCHAR)VNic11QueryCurrentChannel(pNic, FALSE); IEPresent = TRUE; } if (IEPresent) { ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_DS_PARAM_SET, sizeof(channel), &channel); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; } break; case dot11_phy_type_fhss: // // Attach FHSS IE // if (StaEntry) { ndisStatus = Dot11CopyInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_FH_PARAM_SET, &size, sizeof(FHSSIE), &FHSSIE); IEPresent = (ndisStatus == NDIS_STATUS_SUCCESS && size == sizeof(FHSSIE)) ? TRUE: FALSE; } else { IEPresent = FALSE; } if (IEPresent) { ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_FH_PARAM_SET, sizeof(FHSSIE), (PVOID)&FHSSIE); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; } break; case dot11_phy_type_ofdm: break; case dot11_phy_type_irbaseband: break; default: break; } BSSDescription->PhyId = StaGetPhyIdByType(pStation, PhyType); // // Update ATIM window // if (StaEntry) { ndisStatus = Dot11CopyInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_IBSS_PARAM_SET, &size, sizeof(ATIMWindow), &ATIMWindow); if (ndisStatus != NDIS_STATUS_SUCCESS || size != sizeof(ATIMWindow)) { ATIMWindow = 0; } } else { ATIMWindow = 0; } ndisStatus = VNic11SetATIMWindow(pNic, (ULONG)ATIMWindow); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; // // Add it into the IE // ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_IBSS_PARAM_SET, sizeof(ATIMWindow), (PVOID)&ATIMWindow); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; // // If we are running RSNA_PSK, add RSN IE. // if (pStation->Config.AuthAlgorithm == DOT11_AUTH_ALGO_RSNA_PSK) { // // If we are joining an exsiting network, set our group cipher to the one used by // the existing network if our group cipher is not specified. // if (pStation->Config.MulticastCipherAlgorithmCount > 1) { if (StaEntry) { // // If we are joining an exsiting network, set our group cipher to the one used by // the existing network. // pStation->Config.MulticastCipherAlgorithm = StaEntry->GroupCipher; } else { // // If we are creating our own network, set our group cipher to the first one // in the enabled multicast cipher list. // pStation->Config.MulticastCipherAlgorithm = pStation->Config.MulticastCipherAlgorithmList[0]; } // // Tell hardware layer what group cipher we use. // VNic11SetCipher(STA_GET_VNIC(pStation), FALSE, pStation->Config.MulticastCipherAlgorithm); } ndisStatus = StaAttachAdHocRSNIE(pStation, &infoBlobPtr, &infoBlobSize); if (ndisStatus != NDIS_STATUS_SUCCESS) __leave; } // // Add any additional IEs set by IBSS parameter if we still have space. // if (pStation->Config.AdditionalIESize != 0 && pStation->Config.AdditionalIESize <= infoBlobSize) { NdisMoveMemory(infoBlobPtr, pStation->Config.AdditionalIEData, pStation->Config.AdditionalIESize); infoBlobPtr += pStation->Config.AdditionalIESize; infoBlobSize = infoBlobSize - ((USHORT)pStation->Config.AdditionalIESize); } BSSDescription->BeaconIEBlobSize = (ULONG)PtrOffset(BSSDescription->IEBlobs, infoBlobPtr); // // Use the same buffer for the probe response IE blob // BSSDescription->ProbeIEBlobOffset = BSSDescription->BeaconIEBlobOffset; BSSDescription->ProbeIEBlobSize = BSSDescription->BeaconIEBlobSize; BSSDescription->IEBlobsSize = BSSDescription->BeaconIEBlobSize; // save the BSS description in the adhoc info pStation->AdHocStaInfo.BSSDescription = BSSDescription; BSSDescription = NULL; // so that the pointer does not get freed // // Start beaconing and receiving data frames. // ndisStatus = StaStartAdHocBeaconing(pStation); ASSERT(NDIS_STATUS_PENDING != ndisStatus); if (ndisStatus == NDIS_STATUS_SUCCESS) { // // Set TX data rate and our active PhyId // VNic11SelectTXDataRate(pNic, &rateSet, 100); pStation->Config.ActivePhyId = StaGetPhyIdByType(pStation, PhyType); } else { // start beaconing failed. Free up the BSS description we allocated MP_FREE_MEMORY(pStation->AdHocStaInfo.BSSDescription); pStation->AdHocStaInfo.BSSDescription = NULL; } } __finally { if (BSSDescription) { MP_FREE_MEMORY(BSSDescription); } StaAdhocIndicateConnectionCompletion(pStation, ndisStatus, TRUE); } return ndisStatus; } NDIS_STATUS Sta11StopBSSCompleteCallback( _In_ PMP_PORT Port, _In_ PVOID Data ) { PMP_EXTSTA_PORT pStation = MP_GET_STA_PORT(Port); UNREFERENCED_PARAMETER(Data); // Set the stop completion event pStation->AdHocStaInfo.StopBSSCompletionStatus = *((PNDIS_STATUS)Data); NdisSetEvent(&pStation->AdHocStaInfo.StopBSSCompletionEvent); return NDIS_STATUS_SUCCESS; } NDIS_STATUS StaStartAdHocBeaconing( _In_ PMP_EXTSTA_PORT pStation ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PVNIC pVNic = STA_GET_VNIC(pStation); // we should not be already beaconing ASSERT(!pStation->AdHocStaInfo.fBeaconing); if (pStation->AdHocStaInfo.fBeaconing) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing is already on. Simply returning \n")); return NDIS_STATUS_SUCCESS; } // we should already have the BSS description ASSERT(pStation->AdHocStaInfo.BSSDescription); if (!pStation->AdHocStaInfo.BSSDescription) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("No BSS description present. Simply returning \n")); return NDIS_STATUS_SUCCESS; } NdisResetEvent(&pStation->AdHocStaInfo.StartBSSCompletionEvent); // remember we have an item pending with the VNIC InterlockedIncrement(&pStation->AdHocStaInfo.AsyncFuncCount); ndisStatus = VNic11StartBSS( pVNic, pStation->AdHocStaInfo.BSSDescription, Sta11StartBSSCompleteCallback ); if (ndisStatus == NDIS_STATUS_PENDING) { // // Wait for the event that signals start completion // NdisWaitEvent(&pStation->AdHocStaInfo.StartBSSCompletionEvent, 0); ndisStatus = pStation->AdHocStaInfo.StartBSSCompletionStatus; if (ndisStatus == NDIS_STATUS_RESET_IN_PROGRESS) { // The start BSS failed because of a reset. Convert to the // appropriate status that the caller understands ndisStatus = NDIS_STATUS_REQUEST_ABORTED; } } if (ndisStatus == NDIS_STATUS_SUCCESS) { // the beaconing was started pStation->AdHocStaInfo.fBeaconing = TRUE; MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing started \n")); } else { MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing failed to start %!x!. Not setting the flag\n", ndisStatus)); } // VNIC has completed our request. InterlockedDecrement(&pStation->AdHocStaInfo.AsyncFuncCount); return ndisStatus; } VOID StaStopAdHocBeaconing( _In_ PMP_EXTSTA_PORT pStation ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; if (pStation->AdHocStaInfo.fBeaconing) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing is on. Stopping it\n")); NdisResetEvent(&pStation->AdHocStaInfo.StartBSSCompletionEvent); // remember we have an item pending with the VNIC InterlockedIncrement(&pStation->AdHocStaInfo.AsyncFuncCount); ndisStatus = VNic11StopBSS(STA_GET_VNIC(pStation), Sta11StopBSSCompleteCallback); if (ndisStatus == NDIS_STATUS_PENDING) { // // Wait for the event that signals stop completion // NdisWaitEvent(&pStation->AdHocStaInfo.StopBSSCompletionEvent, 0); ndisStatus = pStation->AdHocStaInfo.StopBSSCompletionStatus; } // reset the flag if (NDIS_STATUS_SUCCESS == ndisStatus) { MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing stopped \n")); pStation->AdHocStaInfo.fBeaconing = FALSE; } else { // BUGBUG: Is not resetting the flag the right thing to do??? MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing failed to stop %!x!. Not resetting the flag\n", ndisStatus)); pStation->AdHocStaInfo.fBeaconing = FALSE; } // VNIC has completed our request. InterlockedDecrement(&pStation->AdHocStaInfo.AsyncFuncCount); } else { MpTrace(COMP_ASSOC, DBG_NORMAL, ("AdHoc beaconing is not on. Not doing anything\n")); } } NDIS_STATUS StaGetMatchingAdHocStaList( _In_ PMP_EXTSTA_PORT pStation, _Out_ PULONG StaCount, _Outptr_result_buffer_maybenull_(*StaCount) PSTA_ADHOC_STA_ENTRY **StaEntryArray ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PLIST_ENTRY pHead = NULL, pEntry = NULL; PSTA_ADHOC_STA_ENTRY StaEntry = NULL; MP_RW_LOCK_STATE LockState; UCHAR size; PUCHAR tmpPtr; ULONG index; PDOT11_SSID SSID; *StaEntryArray = NULL; *StaCount = 0; __try { // // Only need read access to the list // MP_ACQUIRE_READ_LOCK(&pStation->AdHocStaInfo.StaListLock, &LockState); if (pStation->AdHocStaInfo.StaCount == 0 || pStation->Config.IgnoreAllMACAddresses) __leave; MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, StaEntryArray, sizeof(PSTA_ADHOC_STA_ENTRY) * pStation->AdHocStaInfo.StaCount, MP_MEMORY_TAG); if ((*StaEntryArray) == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; __leave; } // // Go through the adhoc station list and find all the matching stations and // add them to the StaEntry array. // pHead = &pStation->AdHocStaInfo.StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; // // Check if the StaEntry matches one of the BSSID in the BSSID list. // if (!pStation->Config.AcceptAnyBSSID) { for (index = 0; index < pStation->Config.DesiredBSSIDCount; index++) { if (NdisEqualMemory(pStation->Config.DesiredBSSIDList[index], StaEntry->Dot11BSSID, sizeof(DOT11_MAC_ADDRESS)) == 1) break; } if (index == pStation->Config.DesiredBSSIDCount) continue; } // // Check if the StaEntry matches the desired SSID. // SSID = &pStation->Config.SSID; if (SSID->uSSIDLength > 0) { ndisStatus = Dot11GetInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_SSID, &size, &tmpPtr); if (ndisStatus != NDIS_STATUS_SUCCESS) continue; if (SSID->uSSIDLength != size || NdisEqualMemory(SSID->ucSSID, tmpPtr, size) == 0) continue; } // // Check for other attributes. // if (!StaAcceptStation(pStation, StaEntry)) continue; // // Found a matching station. Allocate memory for it. // if (sizeof(STA_ADHOC_STA_ENTRY) > (sizeof(STA_ADHOC_STA_ENTRY) + StaEntry->InfoElemBlobSize)) { ndisStatus = NDIS_STATUS_FAILURE; continue; } MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &tmpPtr, sizeof(STA_ADHOC_STA_ENTRY) + StaEntry->InfoElemBlobSize, MP_MEMORY_TAG); if (tmpPtr == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; continue; } // // Copy the information of the matching station. // (*StaEntryArray)[*StaCount] = (PSTA_ADHOC_STA_ENTRY)tmpPtr; NdisMoveMemory(tmpPtr, StaEntry, sizeof(STA_ADHOC_STA_ENTRY)); tmpPtr += sizeof(STA_ADHOC_STA_ENTRY); (*StaEntryArray)[*StaCount]->InfoElemBlobPtr = tmpPtr; NdisMoveMemory(tmpPtr, StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize); (*StaCount)++; } } __finally { MP_RELEASE_READ_LOCK(&pStation->AdHocStaInfo.StaListLock, &LockState); } return ndisStatus; } VOID StaConnectAdHocWorkItem( PVOID Context, NDIS_HANDLE NdisIoWorkItemHandle ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PMP_EXTSTA_PORT pStation; PVNIC pNic; ULONG index; ULONG StaCount = 0; PSTA_ADHOC_STA_ENTRY *StaEntryArray = NULL; PSTA_ADHOC_STA_ENTRY StaEntry = NULL; DOT11_MAC_ADDRESS newBSSID; ULONG PhyId; LARGE_INTEGER timeoutTime; UNREFERENCED_PARAMETER(NdisIoWorkItemHandle); pStation = (PMP_EXTSTA_PORT)Context; pNic = STA_GET_VNIC(pStation); __try { // // Delete all non-persistent WEP keys and clear the association state. // VNic11DeleteNonPersistentKey(pNic); StaClearStaListAssocState(pStation, FALSE); // // Since we need beacons & probe response for establishing the adhoc network, // update the packet filter on the VNIC. This is a combination of the packet // filter already set by the upper layer with the additional bits set // VNic11SetPacketFilter(pNic, (STA_GET_MP_PORT(pStation)->PacketFilter | (NDIS_PACKET_TYPE_802_11_DIRECTED_MGMT | NDIS_PACKET_TYPE_802_11_BROADCAST_MGMT) ) ); // // Search for an existing AdHoc network to connect to. If IBSSJoinOnly is set, // keep search until one is found or a reset is pending. // do { // // If this is not the first time we execute this loop, wait for a short while // to prevent us from spinning. // if (ndisStatus != NDIS_STATUS_SUCCESS) { NdisMSleep(100000); // 100 ms. } else { // // Lets force a periodic scan // NdisAcquireSpinLock(&(pStation->ConnectContext.Lock)); pStation->ScanContext.PeriodicScanCounter = STA_DEFAULT_SCAN_TICK_COUNT; NdisReleaseSpinLock(&(pStation->ConnectContext.Lock)); } // // Take a snapshot of the current AdHoc station list. We can't hold the station list // lock and access the list directly since connect operation is a lengthy process in // which we may call wait functions. // if (StaEntryArray) { for (index = 0; index < StaCount; index++) { MP_FREE_MEMORY(StaEntryArray[index]); } MP_FREE_MEMORY(StaEntryArray); StaEntryArray = NULL; } ndisStatus = StaGetMatchingAdHocStaList(pStation, &StaCount, &StaEntryArray); if (ndisStatus != NDIS_STATUS_SUCCESS || (NULL == StaEntryArray)) { ndisStatus = (ndisStatus != NDIS_STATUS_SUCCESS) ? ndisStatus : NDIS_STATUS_FAILURE; __leave; } // // Go through the matching station list and try to join the existing Ad Hoc network. // ndisStatus = STATUS_NOT_FOUND; for (index = 0; index < StaCount; index++) { StaEntry = StaEntryArray[index]; if (NULL == StaEntry) continue; // // Do a synchronize join request with the station's SSID and BSSID. // ndisStatus = StaJoinAdHoc(pStation, StaEntry); if (ndisStatus == NDIS_STATUS_REQUEST_ABORTED) break; else if (ndisStatus != NDIS_STATUS_SUCCESS) continue; // sucessfully joined adhoc, check for protection info in next beacon pStation->Config.CheckForProtectionInERP = TRUE; // // Start the distributed beacon for Ad Hoc // ndisStatus = StaStartAdHoc(pStation, StaEntry, NULL); if (ndisStatus == NDIS_STATUS_SUCCESS) break; } // // Check again if reset is pending. // if (ndisStatus != NDIS_STATUS_REQUEST_ABORTED) { NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); if (pStation->AdHocStaInfo.AdHocState & STA_ADHOC_RESET_PENDING) ndisStatus = NDIS_STATUS_REQUEST_ABORTED; NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); } // We would keep looping trying to setup the adhoc if we were required to // join and havent yet joined one. Else we move out and start our own adhoc } while (pStation->Config.IBSSJoinOnly && ndisStatus != NDIS_STATUS_SUCCESS && ndisStatus != NDIS_STATUS_REQUEST_ABORTED); if (ndisStatus == NDIS_STATUS_REQUEST_ABORTED) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("AdHoc connect: Aborted due to reset\n")); } // // No existing matching AdHoc network found, start our own. // if (ndisStatus != NDIS_STATUS_SUCCESS && ndisStatus != NDIS_STATUS_REQUEST_ABORTED) { // // start a new Adhoc cell if our beacon interval is longer than ATIM windows // and we have the desired SSID. // if (VNic11QueryBeaconPeriod(pNic) > VNic11QueryATIMWindow(pNic) && pStation->Config.SSID.uSSIDLength > 0) { // // If we have desired BSSID list, use the first BSSID from the list as the // BSSID of the new Ad Hoc network. Otherwise, generate a random BSSID. // if (!pStation->Config.AcceptAnyBSSID && pStation->Config.DesiredBSSIDCount > 0) NdisMoveMemory(newBSSID, pStation->Config.DesiredBSSIDList[0], sizeof(DOT11_MAC_ADDRESS)); else Dot11GenerateRandomBSSID((PVOID)VNic11QueryMACAddress(pNic), newBSSID); // // If our current phy type isn't in the desired phy list, set it to the first phy in // the list. // PhyId = VNic11QueryOperatingPhyId(pNic); if (!StaMatchPhyId(pStation, PhyId)) { PhyId = pStation->Config.DesiredPhyList[0]; ASSERT(PhyId != DOT11_PHY_ID_ANY); ndisStatus = VNic11SetOperatingPhyId(pNic, PhyId); } else { ndisStatus = NDIS_STATUS_SUCCESS; } // // Start a new Ad Hoc network // if (ndisStatus == NDIS_STATUS_SUCCESS) { ndisStatus = StaStartAdHoc(pStation, NULL, newBSSID); } } else __leave; } // // Indicate connection start to the OS. If the connection status is not successful, // use all-zeros as the BSSID in the connection start structure. // if (ndisStatus != NDIS_STATUS_SUCCESS) { StaAdhocIndicateConnectionStart(pStation, NULL, FALSE); } else { StaAdhocIndicateConnectionStart(pStation, *VNic11QueryCurrentBSSID(pNic), FALSE); } // // Indicate connection complete to the OS // StaAdhocIndicateConnectionCompletion(pStation, ndisStatus, FALSE); } __finally { if (StaEntryArray) { for (index = 0; index < StaCount; index++) { if (StaEntryArray[index] != NULL) { MP_FREE_MEMORY(StaEntryArray[index]); } } MP_FREE_MEMORY(StaEntryArray); } NdisAcquireSpinLock(&pStation->AdHocStaInfo.StaInfoLock); // // Check if reset is pending one last time. // if (ndisStatus == NDIS_STATUS_SUCCESS && (pStation->AdHocStaInfo.AdHocState & STA_ADHOC_RESET_PENDING)) { ndisStatus = NDIS_STATUS_REQUEST_ABORTED; } // // If connection is successful, start a timer watching for disconnected stations. // if (ndisStatus == NDIS_STATUS_SUCCESS) { NdisInterlockedIncrement(&pStation->AdHocStaInfo.TimerCounter); timeoutTime.QuadPart = Int32x32To64((LONG)2000, -10000); NdisSetTimerObject(pStation->AdHocStaInfo.WatchdogTimer, timeoutTime, 0, NULL); pStation->AdHocStaInfo.AdHocState = STA_ADHOC_CONNECTED; // // Here we dont need to forward the connection status to the VNIC, it will // change itself to be disconnected // } else { pStation->AdHocStaInfo.AdHocState = STA_ADHOC_DISCONNECTED; } NdisReleaseSpinLock(&pStation->AdHocStaInfo.StaInfoLock); } } VOID StaAdhocIndicateConnectionStart( _In_ PMP_EXTSTA_PORT pStation, _In_reads_bytes_opt_(DOT11_ADDRESS_SIZE) DOT11_MAC_ADDRESS BSSID, _In_ BOOLEAN Internal ) { DOT11_CONNECTION_START_PARAMETERS connStart; // // If the connection status is not successful, // use all-zeros as the BSSID in the connection start structure. // MP_ASSIGN_NDIS_OBJECT_HEADER(connStart.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_CONNECTION_START_PARAMETERS_REVISION_1, sizeof(DOT11_CONNECTION_START_PARAMETERS)); connStart.BSSType = dot11_BSS_type_independent; if (BSSID != NULL) { NdisMoveMemory(connStart.AdhocBSSID, BSSID, sizeof(DOT11_MAC_ADDRESS) ); } else { NdisZeroMemory(connStart.AdhocBSSID, sizeof(DOT11_MAC_ADDRESS)); } connStart.AdhocSSID = pStation->Config.SSID; if (!Internal) { StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_CONNECTION_START, NULL, &connStart, sizeof(DOT11_CONNECTION_START_PARAMETERS)); } else { // // Forward the connection status to the hardware // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, // Start with true NDIS_STATUS_DOT11_CONNECTION_START, &connStart, sizeof(DOT11_CONNECTION_START_PARAMETERS) ); } } VOID StaAdhocIndicateConnectionCompletion( _In_ PMP_EXTSTA_PORT pStation, _In_ ULONG CompletionStatus, _In_ BOOLEAN Internal ) { DOT11_CONNECTION_COMPLETION_PARAMETERS connComp; MP_ASSIGN_NDIS_OBJECT_HEADER(connComp.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_CONNECTION_COMPLETION_PARAMETERS_REVISION_1, sizeof(DOT11_CONNECTION_COMPLETION_PARAMETERS) ); switch (CompletionStatus) { case NDIS_STATUS_SUCCESS: connComp.uStatus = DOT11_CONNECTION_STATUS_SUCCESS; break; case NDIS_STATUS_REQUEST_ABORTED: connComp.uStatus = DOT11_CONNECTION_STATUS_CANCELLED; break; default: connComp.uStatus = DOT11_CONNECTION_STATUS_FAILURE; } if (Internal) { // // Forward the connection status to the hardware // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), (CompletionStatus == NDIS_STATUS_SUCCESS) ? TRUE : FALSE, NDIS_STATUS_DOT11_CONNECTION_COMPLETION, &connComp, sizeof(DOT11_CONNECTION_COMPLETION_PARAMETERS) ); } else { // // And to the OS // StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_CONNECTION_COMPLETION, NULL, &connComp, sizeof(DOT11_CONNECTION_COMPLETION_PARAMETERS) ); } } void StaAdHocIndicateAssociation( _In_ PMP_EXTSTA_PORT pStation, _In_ PSTA_ADHOC_STA_ENTRY StaEntry ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; UCHAR size; PUCHAR tmpPtr; DOT11_ASSOCIATION_START_PARAMETERS assocStart; PDOT11_ASSOCIATION_COMPLETION_PARAMETERS assocComp; ULONG assocCompSize; DOT11_DISASSOCIATION_PARAMETERS disassocParam = {0}; DOT11_BEACON_FRAME UNALIGNED *beaconFrame; BOOLEAN match; BOOLEAN connected; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; // // If we are not in the connected state, return. // NdisAcquireSpinLock(&AdHocStaInfo->StaInfoLock); connected = (BOOLEAN)(AdHocStaInfo->AdHocState == STA_ADHOC_CONNECTED); NdisReleaseSpinLock(&AdHocStaInfo->StaInfoLock); if (!connected) return; // // Check BSSID // match = (BOOLEAN)(NdisEqualMemory(VNic11QueryCurrentBSSID(STA_GET_VNIC(pStation)), StaEntry->Dot11BSSID, sizeof(DOT11_MAC_ADDRESS)) == 1); // // Check SSID // if (match) { ndisStatus = Dot11GetInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, DOT11_INFO_ELEMENT_ID_SSID, &size, &tmpPtr); match = (BOOLEAN)(ndisStatus == NDIS_STATUS_SUCCESS && pStation->Config.SSID.uSSIDLength == size && NdisEqualMemory(pStation->Config.SSID.ucSSID, tmpPtr, size) == 1); } // // If the station was associated, but now its SSID or BSSID is changed, indicate disassociation. // Likewise, if the station was not associated, but its SSID and BSSID match with our current // BSSID and SSID, indicate association. // if (StaEntry->AssocState == dot11_assoc_state_auth_assoc && !match) { // // Indicate DISASSOCIATION // MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uReason = DOT11_ASSOC_STATUS_PEER_DISASSOCIATED_START | DOT11_MGMT_REASON_DISASSO_LEAVE_SS; NdisMoveMemory(disassocParam.MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_DISASSOCIATION, NULL, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); // // This station is no longer assocated. // StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; // // Delete key mapping key and per-STA key associated with the leaving station. // VNic11DeleteNonPersistentMappingKey(STA_GET_VNIC(pStation), StaEntry->MacAddress); VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, // Even if we may not have peers, our status is connected NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station disassociated due to mismatch SSID/BSSID: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } else if (StaEntry->AssocState == dot11_assoc_state_unauth_unassoc && match && StaAcceptStation(pStation, StaEntry)) { // // Allocate enough memory for ASSOCIATION_COMPLETE indication. If allocation fails, // we skip this beaconing station. // // Integer overflow if ((FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + StaEntry->InfoElemBlobSize) > (FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + StaEntry->InfoElemBlobSize + sizeof(ULONG))) { ndisStatus = NDIS_STATUS_FAILURE; return; } assocCompSize = sizeof(DOT11_ASSOCIATION_COMPLETION_PARAMETERS) + FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + StaEntry->InfoElemBlobSize + // for beacon sizeof(ULONG); // for single entry PHY list MP_ALLOCATE_MEMORY(STA_GET_MP_PORT(pStation)->MiniportAdapterHandle, &assocComp, assocCompSize, MP_MEMORY_TAG); if (assocComp == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; return; } // // Indicate ASSOCIATION_START // MP_ASSIGN_NDIS_OBJECT_HEADER(assocStart.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_ASSOCIATION_START_PARAMETERS_REVISION_1, sizeof(DOT11_ASSOCIATION_START_PARAMETERS)); assocStart.uIHVDataOffset = 0; assocStart.uIHVDataSize = 0; assocStart.SSID = pStation->Config.SSID; NdisMoveMemory(assocStart.MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_ASSOCIATION_START, NULL, &assocStart, sizeof(DOT11_ASSOCIATION_START_PARAMETERS)); // // Indicate association start to the HW // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, NDIS_STATUS_DOT11_ASSOCIATION_START, &assocStart, sizeof(DOT11_ASSOCIATION_START_PARAMETERS) ); // // Indicate ASSOCIATION_COMPLETE // MP_ASSIGN_NDIS_OBJECT_HEADER(assocComp->Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_ASSOCIATION_COMPLETION_PARAMETERS_REVISION_1, sizeof(DOT11_ASSOCIATION_COMPLETION_PARAMETERS)); NdisMoveMemory(assocComp->MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); assocComp->uStatus = 0; assocComp->bReAssocReq = FALSE; assocComp->bReAssocResp = FALSE; assocComp->uAssocReqOffset = 0; assocComp->uAssocReqSize = 0; assocComp->uAssocRespOffset = 0; assocComp->uAssocRespSize = 0; // // Append the beacon information of this beaconing station. // beaconFrame = (DOT11_BEACON_FRAME UNALIGNED *) Add2Ptr(assocComp, sizeof(DOT11_ASSOCIATION_COMPLETION_PARAMETERS)); beaconFrame->Timestamp = StaEntry->BeaconTimestamp; beaconFrame->BeaconInterval = StaEntry->BeaconInterval; beaconFrame->Capability.usValue = StaEntry->Dot11Capability.usValue; NdisMoveMemory((PVOID)&beaconFrame->InfoElements, StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize); assocComp->uBeaconOffset = sizeof(DOT11_ASSOCIATION_COMPLETION_PARAMETERS); assocComp->uBeaconSize = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + StaEntry->InfoElemBlobSize; assocComp->uIHVDataOffset = 0; assocComp->uIHVDataSize = 0; // // Set the auth and cipher algorithm. // assocComp->AuthAlgo = pStation->Config.AuthAlgorithm; assocComp->UnicastCipher = pStation->Config.UnicastCipherAlgorithm; assocComp->MulticastCipher = pStation->Config.MulticastCipherAlgorithm; // // Set the PHY list. It just contains our active phy id. // assocComp->uActivePhyListOffset = sizeof(DOT11_ASSOCIATION_COMPLETION_PARAMETERS) + FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + StaEntry->InfoElemBlobSize; assocComp->uActivePhyListSize = sizeof(ULONG); *((ULONG UNALIGNED *)Add2Ptr(assocComp, assocComp->uActivePhyListOffset)) = pStation->Config.ActivePhyId; assocComp->bFourAddressSupported = FALSE; assocComp->bPortAuthorized = FALSE; assocComp->DSInfo = DOT11_DS_UNKNOWN; assocComp->uEncapTableOffset = 0; assocComp->uEncapTableSize = 0; // // Before informing the OS about the association, inform the HW // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, NDIS_STATUS_DOT11_ASSOCIATION_COMPLETION, assocComp, assocCompSize ); // // Inform the OS // StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_ASSOCIATION_COMPLETION, NULL, assocComp, assocCompSize); // // Free the preallocated ASSOCIATION_COMPLETE indication structure. // MP_FREE_MEMORY(assocComp); // // This station is assocated. // StaEntry->AssocState = dot11_assoc_state_auth_assoc; MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station associated: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } } void StaProbeInactiveStation( _In_ PMP_EXTSTA_PORT pStation, _In_ PSTA_ADHOC_STA_ENTRY StaEntry ) { char buffer[256]; // big enough for a probe request message. PDOT11_MGMT_HEADER MgmtPacket = (PDOT11_MGMT_HEADER)buffer; NDIS_STATUS ndisStatus; PUCHAR infoBlobPtr; USHORT infoBlobSize; DOT11_RATE_SET rateSet = {0}; MgmtPacket->FrameControl.Version = 0x0; MgmtPacket->FrameControl.Type = DOT11_FRAME_TYPE_MANAGEMENT; MgmtPacket->FrameControl.Subtype = DOT11_MGMT_SUBTYPE_PROBE_REQUEST; MgmtPacket->FrameControl.ToDS = 0x0; // Default value for Mgmt frames MgmtPacket->FrameControl.FromDS = 0x0; // Default value for Mgmt frames MgmtPacket->FrameControl.MoreFrag = 0x0; MgmtPacket->FrameControl.Retry = 0x0; MgmtPacket->FrameControl.PwrMgt = 0x0; MgmtPacket->FrameControl.MoreData = 0x0; MgmtPacket->FrameControl.WEP = 0x0; // no WEP MgmtPacket->FrameControl.Order = 0x0; // no order MgmtPacket->SequenceControl.usValue = 0; NdisMoveMemory(MgmtPacket->DA, StaEntry->MacAddress, DOT11_ADDRESS_SIZE); NdisMoveMemory(MgmtPacket->SA, VNic11QueryMACAddress(STA_GET_VNIC(pStation)), DOT11_ADDRESS_SIZE); NdisMoveMemory(MgmtPacket->BSSID, VNic11QueryCurrentBSSID(STA_GET_VNIC(pStation)), DOT11_ADDRESS_SIZE); // // Add SSID to the probe request. // infoBlobPtr = Add2Ptr(MgmtPacket, DOT11_MGMT_HEADER_SIZE); infoBlobSize = sizeof(buffer) - DOT11_MGMT_HEADER_SIZE; ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_SSID, (UCHAR)pStation->Config.SSID.uSSIDLength, pStation->Config.SSID.ucSSID); ASSERT(ndisStatus == NDIS_STATUS_SUCCESS); if (ndisStatus != NDIS_STATUS_SUCCESS) return; // // Add supported rates to the probe request. // ndisStatus = Dot11GetRateSetFromInfoEle(StaEntry->InfoElemBlobPtr, StaEntry->InfoElemBlobSize, TRUE, &rateSet); ASSERT(ndisStatus == NDIS_STATUS_SUCCESS); if (ndisStatus != NDIS_STATUS_SUCCESS) return; ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_SUPPORTED_RATES, (UCHAR)((rateSet.uRateSetLength > 8) ? 8 : rateSet.uRateSetLength), rateSet.ucRateSet); ASSERT(ndisStatus == NDIS_STATUS_SUCCESS); if (ndisStatus != NDIS_STATUS_SUCCESS) return; if (rateSet.uRateSetLength > (UCHAR)8) { ndisStatus = Dot11AttachElement(&infoBlobPtr, &infoBlobSize, DOT11_INFO_ELEMENT_ID_EXTD_SUPPORTED_RATES, (UCHAR)(rateSet.uRateSetLength - 8), rateSet.ucRateSet + 8); ASSERT(ndisStatus == NDIS_STATUS_SUCCESS); if (ndisStatus != NDIS_STATUS_SUCCESS) return; } BasePortSendInternalPacket(STA_GET_MP_PORT(pStation), (PUCHAR)MgmtPacket, sizeof(buffer) - infoBlobSize); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Sent direct probe request to inactive Ad Hoc station: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } VOID StaAdHocWatchdogTimerRoutine( _In_ PVOID SystemSpecific1, _In_ PVOID FunctionContext, _In_ PVOID SystemSpecific2, _In_ PVOID SystemSpecific3 ) { PMP_EXTSTA_PORT pStation = (PMP_EXTSTA_PORT )FunctionContext; ULONGLONG currentTime; ULONGLONG disassocTime; ULONGLONG removeTime; DOT11_DISASSOCIATION_PARAMETERS disassocParam; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PSTA_ADHOC_STA_ENTRY StaEntry; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; MP_RW_LOCK_STATE LockState; BOOLEAN StopTimer; ULONG index; LARGE_INTEGER fireUpTime; UNREFERENCED_PARAMETER(SystemSpecific1); UNREFERENCED_PARAMETER(SystemSpecific2); UNREFERENCED_PARAMETER(SystemSpecific3); // // If we are not in the connected state, return. // NdisAcquireSpinLock(&AdHocStaInfo->StaInfoLock); StopTimer = (BOOLEAN)(AdHocStaInfo->AdHocState != STA_ADHOC_CONNECTED); NdisReleaseSpinLock(&AdHocStaInfo->StaInfoLock); if (StopTimer) { NdisInterlockedDecrement(&AdHocStaInfo->TimerCounter); return; } __try { MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); // // Calculate the various times. For Ad Hoc, since only one station in the entire network // will transmit beacon frame during a beacon interval, the UnreachableDetectionThreshold // multiplied by number of stations in the network is used as the actual threshold. // NdisGetCurrentSystemTime((PLARGE_INTEGER)¤tTime); disassocTime = pStation->Config.UnreachableDetectionThreshold; disassocTime *= (AdHocStaInfo->StaCount + 1); // // We enforce a range. // if (disassocTime < STA_ADHOC_MIN_UNREACHABLE_THRESHOLD) disassocTime = STA_ADHOC_MIN_UNREACHABLE_THRESHOLD; if (disassocTime > STA_ADHOC_MAX_UNREACHABLE_THRESHOLD) disassocTime = STA_ADHOC_MAX_UNREACHABLE_THRESHOLD; disassocTime *= 10000; removeTime = pStation->RegInfo->BSSEntryExpireTime; // // Go through the Ad Hoc station list. If we have not received a beacon or probe response from // an associated station for more than disassocTime, we disassociat the station. If we have not // received a beacon or probe response from any station for more than removeTime, we remove the // station from the list. // pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; // // Disassociate the station if it appears on the exclusion list. // if (StaEntry->AssocState == dot11_assoc_state_auth_assoc) { for (index = 0; index < pStation->Config.ExcludedMACAddressCount; index++) { if (NdisEqualMemory(StaEntry->MacAddress, pStation->Config.ExcludedMACAddressList[index], sizeof(DOT11_MAC_ADDRESS)) == 1) break; } if (index < pStation->Config.ExcludedMACAddressCount) { // // Indicate DISASSOCIATION // MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uIHVDataOffset = 0; disassocParam.uIHVDataSize = 0; disassocParam.uReason = DOT11_DISASSOC_REASON_OS; NdisMoveMemory(disassocParam.MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_DISASSOCIATION, NULL, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); // // This station is no longer assocated. // StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; // // Delete key mapping key and per-STA key associated with the leaving station. // VNic11DeleteNonPersistentMappingKey(STA_GET_VNIC(pStation), StaEntry->MacAddress); // // Inform the hardware // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, // Even if we may not have peers, our status is connected NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station disassociated due to exclusion: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } } // // Disassociate the station if we have not received a beacon or probe response from // from it for more than disassocTime. // if (StaEntry->AssocState == dot11_assoc_state_auth_assoc && StaEntry->HostTimestamp + disassocTime < currentTime) { if (StaEntry->ProbeRequestsSent++ < STA_PROBE_REQUEST_LIMIT) { StaProbeInactiveStation(pStation, StaEntry); continue; } // // Indicate DISASSOCIATION // MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uIHVDataOffset = 0; disassocParam.uIHVDataSize = 0; disassocParam.uReason = DOT11_DISASSOC_REASON_PEER_UNREACHABLE; NdisMoveMemory(disassocParam.MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_DISASSOCIATION, NULL, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); // // This station is no longer assocated. // StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; // // Delete key mapping key and per-STA key associated with the leaving station. // VNic11DeleteNonPersistentMappingKey(STA_GET_VNIC(pStation), StaEntry->MacAddress); // // Inform the hardware // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, // Even if we may not have peers, our status is connected NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station disassociated due to inactivity: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } // // If we just received de-auth from the station, it's in a special state. Change it to // dot11_assoc_state_unauth_unassoc after it reaches its waiting period. This prevents // us from re-associating a station in the situation where the station sends a de-auth // frame, then sends a few beacon before finally quits. // if (StaEntry->AssocState == dot11_assoc_state_zero) { StaEntry->DeauthWaitingTick++; if (StaEntry->DeauthWaitingTick > STA_DEAUTH_WAITING_THRESHOLD) { StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; ASSERT(AdHocStaInfo->DeauthStaCount >= 1); AdHocStaInfo->DeauthStaCount--; } } // // Remove the station from the list if we have not received a beacon or probe response from // from it for more than removeTime. // if (StaEntry->HostTimestamp + removeTime < currentTime && StaEntry->AssocState == dot11_assoc_state_unauth_unassoc) { ASSERT(AdHocStaInfo->StaCount >= 1); RemoveEntryList(&StaEntry->Link); AdHocStaInfo->StaCount--; MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station removed: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); if (StaEntry->InfoElemBlobPtr) { MP_FREE_MEMORY(StaEntry->InfoElemBlobPtr); } MP_FREE_MEMORY(StaEntry); } } } __finally { MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); } // // Set the timer again. // fireUpTime.QuadPart = Int32x32To64((LONG)2000, -10000); NdisSetTimerObject(pStation->AdHocStaInfo.WatchdogTimer, fireUpTime, 0, NULL); } VOID StaAdhocProcessMgmtPacket( _In_ PMP_EXTSTA_PORT pStation, _In_ PDOT11_MGMT_HEADER MgmtPacket, _In_ ULONG PacketLength ) { BOOLEAN connected; PDOT11_AUTH_FRAME AuthFrame; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PSTA_ADHOC_STA_ENTRY StaEntry; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; MP_RW_LOCK_STATE LockState; DOT11_DISASSOCIATION_PARAMETERS disassocParam; // // If we are not in the connected state, return. // NdisAcquireSpinLock(&AdHocStaInfo->StaInfoLock); connected = (BOOLEAN)(AdHocStaInfo->AdHocState == STA_ADHOC_CONNECTED); NdisReleaseSpinLock(&AdHocStaInfo->StaInfoLock); if (!connected) return; // // We only handle authentication and de-authentication requests. // ASSERT(MgmtPacket->FrameControl.Type == DOT11_FRAME_TYPE_MANAGEMENT); switch (MgmtPacket->FrameControl.Subtype) { case DOT11_MGMT_SUBTYPE_AUTHENTICATION: // // We only process open system authentication request. When we receive such a request, // if the sender's association state is dot11_assoc_state_auth_assoc, we respond with // a success authentication packet. // // // Check frame length. // if (PacketLength < sizeof(DOT11_MGMT_HEADER) + sizeof(DOT11_AUTH_FRAME)) break; // // Check BSSID and DA // if (!MP_COMPARE_MAC_ADDRESS(MgmtPacket->BSSID, VNic11QueryCurrentBSSID(STA_GET_VNIC(pStation))) || !MP_COMPARE_MAC_ADDRESS(MgmtPacket->DA, VNic11QueryMACAddress(STA_GET_VNIC(pStation)))) { break; } // // Get auth frame, make sure it's open system auth request. // AuthFrame = (PDOT11_AUTH_FRAME)Add2Ptr(MgmtPacket, sizeof(DOT11_MGMT_HEADER)); if (AuthFrame->usAlgorithmNumber != DOT11_AUTH_OPEN_SYSTEM || AuthFrame->usXid != 1) break; // // Go through the StaEntry list to find the sender. // MP_ACQUIRE_READ_LOCK(&AdHocStaInfo->StaListLock, &LockState); pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; if (MP_COMPARE_MAC_ADDRESS(MgmtPacket->SA, StaEntry->MacAddress)) { // // We found the sender on the list. If the sender's association state // is dot11_assoc_state_auth_assoc, we send a response. // if (StaEntry->AssocState == dot11_assoc_state_auth_assoc) { // // Reuse the received frame to format the response. // MgmtPacket->SequenceControl.usValue = 0; NdisMoveMemory(MgmtPacket->SA, MgmtPacket->DA, sizeof(DOT11_MAC_ADDRESS)); NdisMoveMemory(MgmtPacket->DA, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); AuthFrame->usXid = 2; AuthFrame->usStatusCode = DOT11_FRAME_STATUS_SUCCESSFUL; BasePortSendInternalPacket(STA_GET_MP_PORT(pStation), (PUCHAR)MgmtPacket, sizeof(DOT11_MGMT_HEADER) + sizeof(DOT11_AUTH_FRAME)); } break; } } MP_RELEASE_READ_LOCK(&AdHocStaInfo->StaListLock, &LockState); break; case DOT11_MGMT_SUBTYPE_DEAUTHENTICATION: // // When we receive a deauthentication request, if the sender's association state is // dot11_assoc_state_auth_assoc, we disassociate the sender and change its association // state to dot11_assoc_state_zero. // // // Check frame length. // if (PacketLength < sizeof(DOT11_MGMT_HEADER) + sizeof(DOT11_DEAUTH_FRAME)) break; // // Check BSSID and DA // if (!MP_COMPARE_MAC_ADDRESS(MgmtPacket->BSSID, VNic11QueryCurrentBSSID(STA_GET_VNIC(pStation))) || !MP_COMPARE_MAC_ADDRESS(MgmtPacket->DA, VNic11QueryMACAddress(STA_GET_VNIC(pStation)))) { break; } // // Go through the StaEntry list to find the sender. // MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; if (MP_COMPARE_MAC_ADDRESS(MgmtPacket->SA, StaEntry->MacAddress)) { // // We found the sender on the list. If the sender's association state // is dot11_assoc_state_auth_assoc, we change it to dot11_assoc_state_zero // and indicate disassociation. // if (StaEntry->AssocState == dot11_assoc_state_auth_assoc) { MP_ASSIGN_NDIS_OBJECT_HEADER(disassocParam.Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_DISASSOCIATION_PARAMETERS_REVISION_1, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); disassocParam.uReason = DOT11_ASSOC_STATUS_PEER_DISASSOCIATED_START | DOT11_MGMT_REASON_DISASSO_LEAVE_SS; NdisMoveMemory(disassocParam.MacAddr, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); StaIndicateDot11Status(pStation, NDIS_STATUS_DOT11_DISASSOCIATION, NULL, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS)); // // Delete key mapping key and per-STA key associated with the leaving station. // VNic11DeleteNonPersistentMappingKey(STA_GET_VNIC(pStation), StaEntry->MacAddress); // // Inform the hardware // VNic11NotifyConnectionStatus( STA_GET_VNIC(pStation), TRUE, // Even if we may not have peers, our status is connected NDIS_STATUS_DOT11_DISASSOCIATION, &disassocParam, sizeof(DOT11_DISASSOCIATION_PARAMETERS) ); // // This station is no longer assocated. We assign dot11_assoc_state_zero // as its association state so that if we receive a beacon from it right away, // we would not re-associate it. // StaEntry->AssocState = dot11_assoc_state_zero; StaEntry->DeauthWaitingTick = 0; ASSERT(AdHocStaInfo->DeauthStaCount < AdHocStaInfo->StaCount); AdHocStaInfo->DeauthStaCount++; MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Ad Hoc station disassociated due to receiving deauth packet: %02X-%02X-%02X-%02X-%02X-%02X\n", StaEntry->MacAddress[0], StaEntry->MacAddress[1], StaEntry->MacAddress[2], StaEntry->MacAddress[3], StaEntry->MacAddress[4], StaEntry->MacAddress[5])); } break; } } MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); break; default: // // All other management packets are ignored. // break; } } NDIS_STATUS StaEnumerateAssociationInfoAdHoc( _In_ PMP_EXTSTA_PORT pStation, _Inout_updates_bytes_(TotalLength) PDOT11_ASSOCIATION_INFO_LIST pAssocInfoList, _In_ ULONG TotalLength ) { PSTA_ADHOC_STA_ENTRY StaEntry = NULL; PDOT11_ASSOCIATION_INFO_EX pAssocInfo = NULL; ULONG EntrySize; ULONG RemainingBytes = 0; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONG StaCount = 0; PSTA_ADHOC_STA_ENTRY *StaEntryArray = NULL; ULONG index; pAssocInfo = &(pAssocInfoList->dot11AssocInfo[0]); RemainingBytes = TotalLength - FIELD_OFFSET(DOT11_ASSOCIATION_INFO_LIST, dot11AssocInfo); do { // // Find adhoc nodes that match our settings // ndisStatus = StaGetMatchingAdHocStaList(pStation, &StaCount, &StaEntryArray); if ((ndisStatus != NDIS_STATUS_SUCCESS) || (NULL == StaEntryArray)) { // No adhoc stations found or failed when creating the list break; } for (index = 0; index < StaCount; index++) { StaEntry = StaEntryArray[index]; EntrySize = sizeof(DOT11_ASSOCIATION_INFO_EX); // Only storing assoc info if (RemainingBytes >= EntrySize) { // Store the entry NdisZeroMemory(pAssocInfo, sizeof(DOT11_ASSOCIATION_INFO_EX)); NdisMoveMemory(pAssocInfo->PeerMacAddress, StaEntry->MacAddress, sizeof(DOT11_MAC_ADDRESS)); NdisMoveMemory(pAssocInfo->BSSID, StaEntry->Dot11BSSID, sizeof(DOT11_MAC_ADDRESS)); pAssocInfo->usCapabilityInformation = StaEntry->Dot11Capability.usValue; pAssocInfo->usListenInterval = pStation->Config.ListenInterval; pAssocInfo->dot11AssociationState = StaEntry->AssocState; if (pAssocInfo->dot11AssociationState == dot11_assoc_state_zero) pAssocInfo->dot11AssociationState = dot11_assoc_state_unauth_unassoc; MpTrace(COMP_OID, DBG_LOUD, ("Assoc State For %02X-%02X-%02X-%02X-%02X-%02X is %d\n", pAssocInfo->PeerMacAddress[0], pAssocInfo->PeerMacAddress[1], pAssocInfo->PeerMacAddress[2], pAssocInfo->PeerMacAddress[3], pAssocInfo->PeerMacAddress[4], pAssocInfo->PeerMacAddress[5], pAssocInfo->dot11AssociationState)); // TODO: Supported rates // // We do not keep per station statistics // pAssocInfoList->uNumOfEntries++; pAssocInfoList->uTotalNumOfEntries++; RemainingBytes -= EntrySize; pAssocInfo++; } else { // Not enough space to store this entry pAssocInfoList->uTotalNumOfEntries++; ndisStatus = NDIS_STATUS_BUFFER_OVERFLOW; RemainingBytes = 0; // // We continue walking through the list to determine the total // space required for this OID // } } } while (FALSE); if (StaEntryArray) { for (index = 0; index < StaCount; index++) { MP_FREE_MEMORY(StaEntryArray[index]); } MP_FREE_MEMORY(StaEntryArray); } return ndisStatus; } void StaAdHocReceiveDirectData( _In_ PMP_EXTSTA_PORT pStation, _In_ PDOT11_DATA_SHORT_HEADER pDataHdr ) { BOOLEAN connected; PSTA_ADHOC_STA_INFO AdHocStaInfo = &pStation->AdHocStaInfo; PSTA_ADHOC_STA_ENTRY StaEntry; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; MP_RW_LOCK_STATE LockState; // // If we are not in the connected state, return. // NdisAcquireSpinLock(&AdHocStaInfo->StaInfoLock); connected = (BOOLEAN)(AdHocStaInfo->AdHocState == STA_ADHOC_CONNECTED); NdisReleaseSpinLock(&AdHocStaInfo->StaInfoLock); if (!connected) return; // // Find if the station that sent this data frame also just sent us de-auth frame, // if so, the station must have tried to re-connect to the ad hoc network. In this // case, change its associate state to dot11_assoc_state_unauth_unassoc. // __try { MP_ACQUIRE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); if (AdHocStaInfo->DeauthStaCount == 0) __leave; pHead = &AdHocStaInfo->StaList; pEntry = pHead->Flink; while (pEntry != pHead) { StaEntry = CONTAINING_RECORD(pEntry, STA_ADHOC_STA_ENTRY, Link); pEntry = pEntry->Flink; if (MP_COMPARE_MAC_ADDRESS(pDataHdr->Address2, StaEntry->MacAddress) && StaEntry->AssocState == dot11_assoc_state_zero) { StaEntry->AssocState = dot11_assoc_state_unauth_unassoc; AdHocStaInfo->DeauthStaCount--; break; } } } __finally { MP_RELEASE_WRITE_LOCK(&AdHocStaInfo->StaListLock, &LockState); } }
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