NDIS_STATUS HelperPortReceiveMgmtPacket( __in PMP_HELPER_PORT HelperPort, __in PMP_RX_MPDU pNicFragment, __in USHORT FragmentSize ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_MGMT_HEADER pMgmtPktHeader; // This is a management packet, reject if size isnt right if (FragmentSize < sizeof(DOT11_MGMT_HEADER)) { return NDIS_STATUS_NOT_ACCEPTED; } pMgmtPktHeader = MP_RX_MPDU_DATA(pNicFragment); switch(pMgmtPktHeader->FrameControl.Subtype) { case DOT11_MGMT_SUBTYPE_BEACON: case DOT11_MGMT_SUBTYPE_PROBE_RESPONSE: HelperPortReceiveBeacon( HelperPort, pNicFragment, FragmentSize ); break; default: break; } return ndisStatus;
VOID HelperPortReceiveBeacon( __in PMP_HELPER_PORT HelperPort, __in PMP_RX_MPDU pFragment, __in ULONG TotalLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PUCHAR pPacketBuffer; PDOT11_BEACON_FRAME pDot11BeaconFrame; ULONG uOffsetOfInfoElemBlob = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + sizeof(DOT11_MGMT_HEADER); ULONG uInfoElemBlobSize = 0; pPacketBuffer = MP_RX_MPDU_DATA(pFragment); do { // // Drop if its doesnt contain atleast the // fixed size portion (DOT11_BEACON_FRAME) // if (uOffsetOfInfoElemBlob > TotalLength) { break; } // Get/Validate beacon is okay pDot11BeaconFrame = (PDOT11_BEACON_FRAME)(pPacketBuffer + sizeof(DOT11_MGMT_HEADER)); ndisStatus = HelperPortValidateBeacon(pDot11BeaconFrame); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // Validate information elements blob ndisStatus = Dot11GetInfoBlobSize( pPacketBuffer, TotalLength, uOffsetOfInfoElemBlob, &uInfoElemBlobSize ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // Save information from this beacon into our BSS list ndisStatus = HelperPortSaveBSSInformation( HelperPort, pFragment, pDot11BeaconFrame, (uInfoElemBlobSize + FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements)) // Info elements + header ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } } while (FALSE);
NDIS_STATUS HelperPortReceiveEventHandler( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __in ULONG ReceiveFlags ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_MAC_HEADER packetHeader; PMP_RX_MPDU rxFragment; USHORT fragmentSize; PMP_RX_MSDU currentPacket = PacketList; UNREFERENCED_PARAMETER(ReceiveFlags); // Process each of the packets internally while (currentPacket != NULL) { // We only accept 1 fragment rxFragment = MP_RX_MSDU_MPDU_AT(currentPacket, 0); packetHeader = MP_RX_MPDU_DATA(rxFragment); fragmentSize = (USHORT)MP_RX_MPDU_LENGTH(rxFragment); switch(packetHeader->FrameControl.Type) { case DOT11_FRAME_TYPE_MANAGEMENT: // // Process management packet // ndisStatus = HelperPortReceiveMgmtPacket( MP_GET_HELPPORT(Port), rxFragment, fragmentSize ); break; default: break; } // // Set the status. This determines if this packet should // be forwarded up or not // MP_RX_MSDU_STATUS(currentPacket) = ndisStatus; // Next packet currentPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); } return NDIS_STATUS_SUCCESS;
NDIS_STATUS BasePortTranslateRxPacketsToRxNBLs( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __out PNET_BUFFER_LIST* NetBufferLists ) { PNET_BUFFER_LIST outputNetBufferList = NULL; PNET_BUFFER_LIST currentNetBufferList, prevNetBufferList = NULL; USHORT fragmentIndex = 0; PMP_RX_MSDU currentPacket = PacketList, nextPacket; PMP_RX_MPDU currentFragment; NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_EXTSTA_RECV_CONTEXT osRecvContext; // This is same for ExtAP & ExtSTA PMDL currentMdl, prevMdl = NULL, mdlChain = NULL; ULONG totalLength = 0; *NetBufferLists = NULL; // Convert each PACKET and FRAGMENT to OS structures while (currentPacket != NULL) { nextPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); // Go through the FRAGMENTs in this PACKET & create an MDL chain mdlChain = NULL; totalLength = 0; for (fragmentIndex = 0; fragmentIndex < MP_RX_MSDU_MPDU_COUNT(currentPacket); fragmentIndex++) { currentFragment = MP_RX_MSDU_MPDU_AT(currentPacket, fragmentIndex); totalLength += MP_RX_MPDU_LENGTH(currentFragment); // Populate the MDL with Fragment contents currentMdl = NdisAllocateMdl(Port->MiniportAdapterHandle, MP_RX_MPDU_DATA(currentFragment), MP_RX_MPDU_LENGTH(currentFragment) ); if (currentMdl == NULL) { MpTrace(COMP_RECV, DBG_SERIOUS, ("Failed to allocate MDL for a MP_RX_MPDU data\n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } // Add this to the MDL chain if (mdlChain == NULL) { // Add this to the head mdlChain = currentMdl; } else { NDIS_MDL_LINKAGE(prevMdl) = currentMdl; } prevMdl = currentMdl; } if (ndisStatus != NDIS_STATUS_SUCCESS) { while (mdlChain != NULL) { currentMdl = mdlChain; mdlChain = NDIS_MDL_LINKAGE(currentMdl); // MDL was allocated NdisFreeMdl(currentMdl); } break; } // Allocate the NET_BUFFER_LIST and the NET_BUFFER currentNetBufferList = NdisAllocateNetBufferAndNetBufferList( Port->RxNetBufferListPool, 0, 0, mdlChain, 0, totalLength ); if (currentNetBufferList == NULL) { MpTrace(COMP_SEND, DBG_SERIOUS, ("Failed to allocate NET_BUFFER_LIST for MP_RX_MSDU \n")); ndisStatus = NDIS_STATUS_RESOURCES; break; } // Populate the RX_PACKET MP_NBL_WRAPPED_RX_MSDU(currentNetBufferList) = currentPacket; MP_NBL_SOURCE_PORT(currentNetBufferList) = Port; if (outputNetBufferList == NULL) { outputNetBufferList = currentNetBufferList; } else { NET_BUFFER_LIST_NEXT_NBL(prevNetBufferList) = currentNetBufferList; } // The Next PACKET's NBL would be added after the current PACKET's NBL prevNetBufferList = currentNetBufferList; osRecvContext = MP_RX_MSDU_RECV_CONTEXT(currentPacket); MP_ASSIGN_NDIS_OBJECT_HEADER(osRecvContext->Header, NDIS_OBJECT_TYPE_DEFAULT, DOT11_EXTSTA_RECV_CONTEXT_REVISION_1, sizeof(DOT11_EXTSTA_RECV_CONTEXT)); MP_SET_RECEIVE_CONTEXT(currentNetBufferList, osRecvContext); currentPacket = nextPacket; } if (ndisStatus != NDIS_STATUS_SUCCESS) { if (outputNetBufferList != NULL) { BasePortFreeTranslatedRxNBLs(Port, outputNetBufferList); outputNetBufferList = NULL; } } *NetBufferLists = outputNetBufferList; return ndisStatus; }
BOOLEAN BasePortFilterFragment( __in PMP_PORT Port, __in PMP_RX_MSDU Packet ) { PUCHAR pktbuf = MP_RX_MPDU_DATA(MP_RX_MSDU_MPDU_AT(Packet, 0)); UCHAR type = (pktbuf[0] & 0x0f) >> 2; BOOLEAN bAddrMatch = MP_COMPARE_MAC_ADDRESS(pktbuf + 4, VNic11QueryMACAddress(PORT_GET_VNIC(Port))); BOOLEAN bIsBroadcast = DOT11_IS_BROADCAST(&pktbuf[4]); BOOLEAN bIsMulticast = DOT11_IS_MULTICAST(&pktbuf[4]); switch(type) { case DOT11_FRAME_TYPE_MANAGEMENT: if (bAddrMatch && (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_DIRECTED_MGMT)) return TRUE; if (bIsBroadcast && (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_BROADCAST_MGMT)) return TRUE; if (bIsMulticast && (Port->PacketFilter & (NDIS_PACKET_TYPE_802_11_MULTICAST_MGMT | NDIS_PACKET_TYPE_802_11_ALL_MULTICAST_MGMT))) return TRUE; if (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_PROMISCUOUS_MGMT) return TRUE; break; case DOT11_FRAME_TYPE_CONTROL: if (bAddrMatch && (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_DIRECTED_CTRL)) return TRUE; if (bIsBroadcast && (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_BROADCAST_CTRL)) return TRUE; if (Port->PacketFilter & NDIS_PACKET_TYPE_802_11_PROMISCUOUS_CTRL) return TRUE; // // Note: no multicast control frame. // break; case DOT11_FRAME_TYPE_DATA: if (bAddrMatch && (Port->PacketFilter & NDIS_PACKET_TYPE_DIRECTED)) return TRUE; if (bIsBroadcast && (Port->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)) return TRUE; if (bIsMulticast&& (Port->PacketFilter & (NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_ALL_MULTICAST))) return TRUE; if (Port->PacketFilter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_802_11_RAW_DATA)) return TRUE; break; default: // // Reserved packet should always be filtered // return FALSE; } return FALSE; }
NDIS_STATUS Ap11ReceiveHandler( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __in ULONG ReceiveFlags ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PAP_ASSOC_MGR assocMgr = AP_GET_ASSOC_MGR(MP_GET_AP_PORT(Port)); PDOT11_MGMT_HEADER mgmtPktHeader; PMP_RX_MPDU rxFragment; USHORT fragmentSize; PMP_RX_MSDU currentPacket; PMAC_HASH_ENTRY macEntry; PAP_STA_ENTRY staEntry; DOT11_ASSOCIATION_STATE assocState; DOT11_FRAME_CLASS frameClass; MP_RW_LOCK_STATE lockState; // // The following boolean is used to improve the performance w.r.t. lock // BOOLEAN holdReadLock = FALSE; UNREFERENCED_PARAMETER(ReceiveFlags); // // Reference AP port first // ApRefPort(MP_GET_AP_PORT(Port)); do { // // Only process packets when AP is started // if (ApGetState(MP_GET_AP_PORT(Port)) != AP_STATE_STARTED) { ndisStatus = NDIS_STATUS_INVALID_STATE; break; } // // Process each of the packets internally // for (currentPacket = PacketList; currentPacket != NULL; currentPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket) ) { // // We only accept 1 fragment // rxFragment = MP_RX_MSDU_MPDU_AT(currentPacket, 0); fragmentSize = (USHORT)MP_RX_MPDU_LENGTH(rxFragment); if (fragmentSize < DOT11_MGMT_HEADER_SIZE) { continue; } mgmtPktHeader = MP_RX_MPDU_DATA(rxFragment); // // TODO: ignore packets that are not in this BSSID? // if (!MP_COMPARE_MAC_ADDRESS(mgmtPktHeader->BSSID, assocMgr->Bssid)) { continue; } // // Check whether ExtAP needs to process the packet // // If ExtAP will process the packet, a write lock will be acquired later. // The association state of the send station is validated when the packet // is processed. // // Otherwise, we need to hold a read lock on the // Mac table to check the association state of the sending station. // We don't hold a write lock because we can tolerate // inconsistency in statistics to achieve better performance. // if (ApNeedToProcessPacket( mgmtPktHeader, fragmentSize )) { // // Process the management packet // // // 1. Release the read lock if it is held because a write lock may be acquired // in the process of the management packet // 2. Process the management packet // This improves the performance if we receive a bunch of data packets. // if (holdReadLock) { MP_RELEASE_READ_LOCK(&assocMgr->MacHashTableLock, &lockState); holdReadLock = FALSE; } // // Don't pass the packet up if it is not valid // ndisStatus = ApProcessPacket( MP_GET_AP_PORT(Port), mgmtPktHeader, fragmentSize ); } else { // // Need to know the association state of the sending station // // // Acquire read lock if we don't hold it // if (!holdReadLock) { MP_ACQUIRE_READ_LOCK(&assocMgr->MacHashTableLock, &lockState); holdReadLock = TRUE; } // // Lookup the station entry from Mac table if it exists // macEntry = LookupMacHashTable( &assocMgr->MacHashTable, &mgmtPktHeader->SA ); // // Get the station association state // if (macEntry != NULL) { staEntry = CONTAINING_RECORD(macEntry, AP_STA_ENTRY, MacHashEntry); assocState = ApGetStaAssocState(staEntry); // // Reset station inactive time. // No need to check the association state. // Ignore the returned original value. // ApResetStaInactiveTime(staEntry); } else { assocState = dot11_assoc_state_unauth_unassoc; } // // Get the frame class // frameClass = Dot11GetFrameClass(&mgmtPktHeader->FrameControl); switch(frameClass) { case DOT11_FRAME_CLASS_1: // // Class 1 frames are always allowed // break; case DOT11_FRAME_CLASS_2: // // Class 2 frames are allowed if the station is authenticated // if (dot11_assoc_state_unauth_unassoc == assocState) { ndisStatus = NDIS_STATUS_INVALID_STATE; } break; case DOT11_FRAME_CLASS_3: // // Class 3 frames are allowed if the station is associated // if (assocState != dot11_assoc_state_auth_assoc) { ndisStatus = NDIS_STATUS_INVALID_STATE; } break; default: ndisStatus = NDIS_STATUS_INVALID_STATE; } // // Validate data packet // if (NDIS_STATUS_SUCCESS == ndisStatus && DOT11_FRAME_TYPE_DATA == mgmtPktHeader->FrameControl.Type) { ndisStatus = ApValidateDataPacket( MP_GET_AP_PORT(Port), rxFragment, fragmentSize ); } } // // Mark the status for the current packet and reset ndis status // MP_TX_MSDU_STATUS(currentPacket) = ndisStatus; ndisStatus = NDIS_STATUS_SUCCESS; } // // Release the read lock // if (holdReadLock) { MP_RELEASE_READ_LOCK(&assocMgr->MacHashTableLock, &lockState); } } while (FALSE); // // Dereference AP port // ApDerefPort(MP_GET_AP_PORT(Port)); return ndisStatus; }
/** * Validate data packet. * Will check encryption in the validation. */ NDIS_STATUS ApValidateDataPacket( __in PMP_EXTAP_PORT ApPort, __in PMP_RX_MPDU Fragment, __in USHORT FragmentSize ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_PRIVACY_EXEMPTION_LIST privacyExemptionList = AP_GET_ASSOC_MGR(ApPort)->PrivacyExemptionList; USHORT etherType; USHORT packetType; PDOT11_PRIVACY_EXEMPTION privacyExemption; ULONG index; BOOLEAN isUnicast; USHORT sequenceNumber; PDOT11_DATA_SHORT_HEADER fragmentHdr = (PDOT11_DATA_SHORT_HEADER)MP_RX_MPDU_DATA(Fragment); BOOLEAN checkExcludeUnencrypted = TRUE; do { // // We don't check the fragmented data frame that is not the first fragment. // if (FragmentSize < DOT11_DATA_SHORT_HEADER_SIZE) { ndisStatus = NDIS_STATUS_NOT_ACCEPTED; break; } RtlCopyMemory( &sequenceNumber, &fragmentHdr->SequenceControl, 2 ); if ((sequenceNumber & 0x0f) != 0) { break; } // // Data frame must also contain 802.2 LLC and 802.2 SNAP (8 bytes total) // if (FragmentSize < DOT11_DATA_SHORT_HEADER_SIZE + sizeof(IEEE_8022_LLC_SNAP)) { ndisStatus = NDIS_STATUS_NOT_ACCEPTED; break; } // // Go through the privacy exemption list to see if we can accept the data frame. // if (privacyExemptionList && privacyExemptionList->uNumOfEntries > 0) { // // Find the EtherType and PacketType of the frame // etherType = ((PIEEE_8022_LLC_SNAP)Add2Ptr(fragmentHdr, DOT11_DATA_SHORT_HEADER_SIZE))->sh_etype; isUnicast = (BOOLEAN)DOT11_IS_UNICAST(fragmentHdr->Address1); packetType = isUnicast ? DOT11_EXEMPT_UNICAST : DOT11_EXEMPT_MULTICAST; // // Check the disposition of the frame. // privacyExemption = privacyExemptionList->PrivacyExemptionEntries; for (index = 0; index < privacyExemptionList->uNumOfEntries; index++, privacyExemption++) { // // Skip if EtherType does not match // if (privacyExemption->usEtherType != etherType) { continue; } // // Skip if PacketType does not match // if (privacyExemption->usExemptionPacketType != packetType && privacyExemption->usExemptionPacketType != DOT11_EXEMPT_BOTH) { continue; } if (privacyExemption->usExemptionActionType == DOT11_EXEMPT_ALWAYS) { // // In this case, we drop the frame if it was originally // encrypted. // if (MP_TEST_FLAG(Fragment->Msdu->Flags, MP_RX_MSDU_FLAG_ENCRYPTED)) { ndisStatus = NDIS_STATUS_NOT_ACCEPTED; } // // No need to check exclude unencrypted // checkExcludeUnencrypted = FALSE; break; } else if (privacyExemption->usExemptionActionType == DOT11_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE) { // // In this case, we reject the frame if it was originally NOT encrypted but // we have the key mapping key for this frame. // if (!MP_TEST_FLAG(Fragment->Msdu->Flags, MP_RX_MSDU_FLAG_ENCRYPTED) && isUnicast && VNic11IsKeyMappingKeyAvailable(AP_GET_VNIC(ApPort), fragmentHdr->Address2) ) { ndisStatus = NDIS_STATUS_NOT_ACCEPTED; } // // No need to check exclude unencrypted // checkExcludeUnencrypted = FALSE; break; } else { // // The privacy exemption does not apply to this frame. // break; } } } // // If the privacy exemption list does not apply to the frame, check ExcludeUnencrypted. // if ExcludeUnencrypted is set and this frame was not oringially an encrypted frame, // dropped it. // if (checkExcludeUnencrypted) { if (AP_GET_ASSOC_MGR(ApPort)->ExcludeUnencrypted && !MP_TEST_FLAG(Fragment->Msdu->Flags, MP_RX_MSDU_FLAG_ENCRYPTED)) { ndisStatus = NDIS_STATUS_NOT_ACCEPTED; } } } while (FALSE); return ndisStatus; }
VOID StaReceiveBeacon( _In_ PMP_EXTSTA_PORT pStation, _In_ PMP_RX_MPDU pFragment, _In_ ULONG TotalLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PUCHAR pPacketBuffer; PDOT11_BEACON_FRAME pDot11BeaconFrame; ULONG uOffsetOfInfoElemBlob = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements) + sizeof(DOT11_MGMT_HEADER); ULONG uInfoElemBlobSize = 0; pPacketBuffer = MP_RX_MPDU_DATA(pFragment); do { // // Drop if its doesnt contain atleast the // fixed size portion (DOT11_BEACON_FRAME) // if (uOffsetOfInfoElemBlob > TotalLength) { break; } pDot11BeaconFrame = (PDOT11_BEACON_FRAME)(pPacketBuffer + sizeof(DOT11_MGMT_HEADER)); // Validate information elements blob ndisStatus = Dot11GetInfoBlobSize( pPacketBuffer, TotalLength, uOffsetOfInfoElemBlob, &uInfoElemBlobSize ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } if (pDot11BeaconFrame->Capability.IBSS) { ndisStatus = StaSaveAdHocStaInfo( pStation, pFragment, pDot11BeaconFrame, uInfoElemBlobSize ); } ndisStatus = StaProcessBeaconForConfigInfo( pStation, pFragment, (PUCHAR)&pDot11BeaconFrame->InfoElements, TotalLength ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } } while (FALSE); }
NDIS_STATUS HelperPortSaveBSSInformation( __in PMP_HELPER_PORT HelperPort, __in PMP_RX_MPDU pFragment, __in PDOT11_BEACON_FRAME pDot11BeaconFrame, __in ULONG BeaconDataLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; MP_RW_LOCK_STATE LockState; PMP_BSS_ENTRY pBSSEntry = NULL; PDOT11_MGMT_HEADER pMgmtPktHeader; PMP_BSS_LIST pDiscoveredBSSList = &(HelperPort->BSSList); pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment); // // In most cases, we would be updating information about this // AP in our list. For this reason, we only acquire read lock // for most cases // MP_ACQUIRE_READ_LOCK(&(HelperPort->BSSList.ListLock), &LockState); // // See if this entry already exists in the list // pBSSEntry = HelperPortFindBSSEntry( pDiscoveredBSSList, pMgmtPktHeader->SA ); if (pBSSEntry == NULL) { // // Entry does not exist, we are adding information about a new BSS // MP_RELEASE_READ_LOCK(&(HelperPort->BSSList.ListLock), &LockState); ndisStatus = HelperPortInsertBSSEntry( HelperPort, pFragment, pDot11BeaconFrame, BeaconDataLength ); } else { // // Entry already exists, we are just updating // ndisStatus = HelperPortUpdateBSSEntry( HelperPort, pBSSEntry, pFragment, pDot11BeaconFrame, BeaconDataLength ); // Read lock still held MP_RELEASE_READ_LOCK(&(HelperPort->BSSList.ListLock), &LockState); } return ndisStatus;
// BSS list lock acquired & called at Dispatch NDIS_STATUS HelperPortUpdateBSSEntry( __in PMP_HELPER_PORT HelperPort, __in PMP_BSS_ENTRY pBSSEntry, __in PMP_RX_MPDU pFragment, __in PDOT11_BEACON_FRAME pDot11BeaconPRFrame, __in ULONG BeaconPRDataLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_MGMT_HEADER pMgmtPktHeader; ULONGLONG ullHostTimeStamp; PVOID pSavedBeaconPRBuffer = NULL; ULONG uOffsetOfInfoElemBlob = FIELD_OFFSET(DOT11_BEACON_FRAME, InfoElements); UCHAR channel; DOT11_PHY_TYPE PhyType; pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment); NdisGetCurrentSystemTime((PLARGE_INTEGER)&ullHostTimeStamp); do { // // Modifying data in the AP entry // NdisDprAcquireSpinLock(&(pBSSEntry->Lock)); if (pDot11BeaconPRFrame->Capability.IBSS) { pBSSEntry->Dot11BSSType = dot11_BSS_type_independent; } else { pBSSEntry->Dot11BSSType = dot11_BSS_type_infrastructure; } // // Adhoc station can leave adhoc cell and create a new cell. SoftAPs // can move. This means the BSSID can change // NdisMoveMemory( pBSSEntry->Dot11BSSID, pMgmtPktHeader->BSSID, sizeof(DOT11_MAC_ADDRESS) ); pBSSEntry->HostTimestamp = ullHostTimeStamp; pBSSEntry->BeaconTimestamp = pDot11BeaconPRFrame->Timestamp; pBSSEntry->BeaconInterval = pDot11BeaconPRFrame->BeaconInterval; pBSSEntry->Dot11Capability = pDot11BeaconPRFrame->Capability; pBSSEntry->RSSI = pFragment->Msdu->RecvContext.lRSSI; pBSSEntry->LinkQuality = pFragment->Msdu->LinkQuality; pBSSEntry->ChannelCenterFrequency = pFragment->Msdu->RecvContext.uChCenterFrequency; // // If signal strength was below our threshold, catch that // if (pBSSEntry->LinkQuality < HelperPort->RegInfo->RSSILinkQualityThreshold) { pBSSEntry->LowQualityCount++; } else { pBSSEntry->LowQualityCount = 0; } #if 0 if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc) { MpTrace(COMP_ASSOC, DBG_LOUD, ("Received beacon from associated AP: %02X-%02X-%02X-%02X-%02X-%02X\n", pMgmtPktHeader->SA[0], pMgmtPktHeader->SA[1], pMgmtPktHeader->SA[2], pMgmtPktHeader->SA[3], pMgmtPktHeader->SA[4], pMgmtPktHeader->SA[5])); } #endif // // Get channel number at which the frame was received. // if (Dot11GetChannelForDSPhy(Add2Ptr(pDot11BeaconPRFrame, uOffsetOfInfoElemBlob), BeaconPRDataLength - uOffsetOfInfoElemBlob, &channel) != NDIS_STATUS_SUCCESS) { channel = pFragment->Msdu->Channel; } if (channel != 0) { pBSSEntry->Channel = channel; } // // Get PhyType and PhyId // PhyType = VNic11DeterminePHYType(HELPPORT_GET_VNIC(HelperPort), pBSSEntry->Dot11Capability, pBSSEntry->Channel); if (pBSSEntry->Dot11PhyType != PhyType) { pBSSEntry->Dot11PhyType = PhyType; pBSSEntry->PhyId = BasePortGetPhyIdFromType(HELPPORT_GET_MP_PORT(HelperPort), PhyType); } if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_BEACON) { // // Increase the beacon frame size if necessary // if (pBSSEntry->MaxBeaconFrameSize < BeaconPRDataLength) { MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, &pSavedBeaconPRBuffer, BeaconPRDataLength, PORT_MEMORY_TAG ); if (pSavedBeaconPRBuffer == NULL) { // // Unable to allocate memory for information elements. // If this is a new AP entry, we wont be adding it to the list. // For existing entries, we end up ignoring the new IE blob // ndisStatus = NDIS_STATUS_RESOURCES; NdisDprReleaseSpinLock(&(pBSSEntry->Lock)); break; } // // Delete any old blob buffer // if (pBSSEntry->pDot11BeaconFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame); } pBSSEntry->pDot11BeaconFrame = pSavedBeaconPRBuffer; pBSSEntry->MaxBeaconFrameSize = BeaconPRDataLength; } // Update the beacon pBSSEntry->BeaconFrameSize = BeaconPRDataLength; // Also save this as the IE blob pointer pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob; pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11BeaconFrame + uOffsetOfInfoElemBlob; // // Update/Save the beacon information element block // NdisMoveMemory( pBSSEntry->pDot11BeaconFrame, pDot11BeaconPRFrame, BeaconPRDataLength ); } if (pMgmtPktHeader->FrameControl.Subtype == DOT11_MGMT_SUBTYPE_PROBE_RESPONSE) { // // Increase the probe response frame size if necessary // if (pBSSEntry->MaxProbeFrameSize < BeaconPRDataLength) { MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, &pSavedBeaconPRBuffer, BeaconPRDataLength, PORT_MEMORY_TAG ); if (pSavedBeaconPRBuffer == NULL) { // // Unable to allocate memory for information elements. // If this is a new AP entry, we wont be adding it to the list. // For existing entries, we end up ignoring the new IE blob // ndisStatus = NDIS_STATUS_RESOURCES; NdisDprReleaseSpinLock(&(pBSSEntry->Lock)); break; } // // Delete any old blob buffer // if (pBSSEntry->pDot11ProbeFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame); } pBSSEntry->pDot11ProbeFrame = pSavedBeaconPRBuffer; pBSSEntry->MaxProbeFrameSize = BeaconPRDataLength; } pBSSEntry->ProbeFrameSize = BeaconPRDataLength; // Also save this as the IE blob pointer pBSSEntry->InfoElemBlobSize = BeaconPRDataLength - uOffsetOfInfoElemBlob; pBSSEntry->pDot11InfoElemBlob = (PUCHAR)pBSSEntry->pDot11ProbeFrame + uOffsetOfInfoElemBlob; // // Update/Save the beacon information element block // NdisMoveMemory( pBSSEntry->pDot11ProbeFrame, pDot11BeaconPRFrame, BeaconPRDataLength ); } #if 0 if (pBSSEntry->AssocState == dot11_assoc_state_auth_assoc) { MpTrace(COMP_SCAN, DBG_LOUD, ("Received %d for AP %02X-%02X-%02X-%02X-%02X-%02X \n", pMgmtPktHeader->FrameControl.Subtype, pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5])); } #endif // // Done with our modification of the AP entry // NdisDprReleaseSpinLock(&(pBSSEntry->Lock)); } while (FALSE); return ndisStatus;
NDIS_STATUS HelperPortInsertBSSEntry( __in PMP_HELPER_PORT HelperPort, __in PMP_RX_MPDU pFragment, __in PDOT11_BEACON_FRAME pDot11BeaconFrame, __in ULONG BeaconDataLength ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; ULONGLONG ullHostTimeStamp; MP_RW_LOCK_STATE LockState; PMP_BSS_ENTRY pBSSEntry = NULL; PDOT11_MGMT_HEADER pMgmtPktHeader; BOOLEAN bNewAp = FALSE; PMP_BSS_LIST pDiscoveredBSSList = &(HelperPort->BSSList); pMgmtPktHeader = (PDOT11_MGMT_HEADER)MP_RX_MPDU_DATA(pFragment); NdisGetCurrentSystemTime((PLARGE_INTEGER)&ullHostTimeStamp); // // We acquire the write lock as we are adding entries to the list // MP_ACQUIRE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); do { // // Check again if this entry already exists in the list. This is to handle // if the AP was added since we first checked (possible if the // flush routine was running) // pBSSEntry = HelperPortFindBSSEntry( pDiscoveredBSSList, pMgmtPktHeader->SA ); if (pBSSEntry == NULL) { bNewAp = TRUE; // New AP // // We havent found this AP yet, we would add it to the list // if (pDiscoveredBSSList->NumOfBSSEntries >= pDiscoveredBSSList->MaxNumOfBSSEntries) { // // We need to replace an entry thats in the list // pBSSEntry = HelperPortExpireBSSEntry( pDiscoveredBSSList, HelperPort->RegInfo->BSSEntryExpireTime, ullHostTimeStamp ); if (pBSSEntry != NULL) { // // Add initial in-use refcount // pBSSEntry->RefCount = 1; } // // Dont zero out the AP entry so that we can // reuse the info element blob // } else { // // Create a new entry for this AP // MP_ALLOCATE_MEMORY(HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle, &pBSSEntry, sizeof(MP_BSS_ENTRY), PORT_MEMORY_TAG ); if (pBSSEntry != NULL) { // // Initialize the new entry // NdisZeroMemory(pBSSEntry, sizeof(MP_BSS_ENTRY)); pBSSEntry->RefCount = 1; // Add initial in-use refcount NdisAllocateSpinLock(&(pBSSEntry->Lock)); } } if (pBSSEntry == NULL) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("Not enough space to add AP: %02X-%02X-%02X-%02X-%02X-%02X\n", pMgmtPktHeader->SA[0], pMgmtPktHeader->SA[1], pMgmtPktHeader->SA[2], pMgmtPktHeader->SA[3], pMgmtPktHeader->SA[4], pMgmtPktHeader->SA[5])); ndisStatus = NDIS_STATUS_RESOURCES; break; } // // This Entry is not yet in the list // // We will be updating the beacon & probe response frames pBSSEntry->BeaconFrameSize = 0; pBSSEntry->ProbeFrameSize = 0; pBSSEntry->AssocCost = 0; NdisMoveMemory( pBSSEntry->Dot11BSSID, pMgmtPktHeader->BSSID, sizeof(DOT11_MAC_ADDRESS) ); NdisMoveMemory( pBSSEntry->MacAddress, pMgmtPktHeader->SA, sizeof(DOT11_MAC_ADDRESS) ); } // Update the information in this BSS entry (either new or reused entry) ndisStatus = HelperPortUpdateBSSEntry( HelperPort, pBSSEntry, pFragment, pDot11BeaconFrame, BeaconDataLength ); if (ndisStatus != NDIS_STATUS_SUCCESS) { break; } // // Add the new BSS to our list // if (bNewAp) { MpTrace(COMP_SCAN, DBG_LOUD, ("AP %02X-%02X-%02X-%02X-%02X-%02X at channel: %d (%d)\n", pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5], pBSSEntry->Channel, pFragment->Msdu->Channel)); HelperPortAddBSSEntry(pDiscoveredBSSList, pBSSEntry); } // // Note: If any code is added below here, remember to remove entry // from the list // } while (FALSE); MP_RELEASE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Free the new entry we may have created if ((bNewAp) && (pBSSEntry != NULL)) { if (pBSSEntry->pDot11BeaconFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame); pBSSEntry->pDot11BeaconFrame = NULL; pBSSEntry->BeaconFrameSize = 0; pBSSEntry->MaxBeaconFrameSize= 0; } if (pBSSEntry->pDot11ProbeFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame); pBSSEntry->pDot11ProbeFrame = NULL; pBSSEntry->ProbeFrameSize = 0; pBSSEntry->MaxProbeFrameSize= 0; } pBSSEntry->pDot11InfoElemBlob = NULL; pBSSEntry->InfoElemBlobSize = 0; MP_FREE_MEMORY(pBSSEntry); } } return ndisStatus;