Sample Code

Windows Driver Samples/ Native Wi-Fi Miniport Sample Driver/ C++/ driver/ helper_port_bsslist.c/

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:
    helper_port_bsslist.c

Abstract:
    Implements BSS list management functionality for the helper port
    
Revision History:
      When        What
    ----------    ----------------------------------------------
    09-04-2007    Created

Notes:

--*/

#include "precomp.h"
#include "port_defs.h"
#include "base_port_intf.h"
#include "helper_port_defs.h"
#include "helper_port_intf.h"
#include "helper_port_bsslist.h"
#include "vnic_intf.h"
#include "glb_utils.h"

#if DOT11_TRACE_ENABLED
#include "helper_port_bsslist.tmh"
#endif


NDIS_STATUS
HelperPortInitializeBSSList(
    _In_  PMP_HELPER_PORT         HelperPort
    )
{
    PMP_BSS_LIST                BSSList = &(HelperPort->BSSList);
    NDIS_STATUS                 ndisStatus;
    
    ndisStatus = MP_ALLOCATE_READ_WRITE_LOCK(&(BSSList->ListLock), HELPPORT_GET_MP_PORT(HelperPort)->MiniportAdapterHandle);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        return ndisStatus;
   
}

    BSSList->MaxNumOfBSSEntries = HelperPort->RegInfo->BSSEntryMaxCount;
    BSSList->NumOfBSSEntries = 0;
    NdisInitializeListHead(&BSSList->List);

    return NDIS_STATUS_SUCCESS;
}

VOID
HelperPortTerminateBSSList(
    _In_  PMP_HELPER_PORT         HelperPort
    )
{
    PMP_BSS_LIST                BSSList = &(HelperPort->BSSList);

    MPASSERT(IsListEmpty(&(BSSList->List)));
    
    MP_FREE_READ_WRITE_LOCK(&(BSSList->ListLock));
}

PMP_BSS_LIST
HelperPortQueryAndRefBSSList(
    _In_  PMP_PORT                Port,
    _In_  PMP_PORT                RequestingPort,
    _Out_ PMP_RW_LOCK_STATE       LockState
    )
{
    PMP_HELPER_PORT     HelperPort = MP_GET_HELPPORT(Port);

    UNREFERENCED_PARAMETER(RequestingPort);

    // Acquire read lock on the BSS list
    MP_ACQUIRE_READ_LOCK(&(HelperPort->BSSList.ListLock), LockState);

    return &(HelperPort->BSSList);
}

VOID
HelperPortReleaseBSSListRef(
    _In_  PMP_PORT                Port,
    _In_  PMP_BSS_LIST            BSSList,
    _Out_  PMP_RW_LOCK_STATE       LockState
    )
{
    UNREFERENCED_PARAMETER(Port);

    // Release the read ref
    MP_RELEASE_READ_LOCK(&(BSSList->ListLock), LockState);
}

NDIS_STATUS
HelperPortFlushBSSList(
    _In_ PMP_PORT                 Port
    )
{
    MP_RW_LOCK_STATE          LockState;
    PLIST_ENTRY         pListEntry;
    PMP_BSS_ENTRY      pBSSEntry = NULL;
    LONG                APRefCount;
    LIST_ENTRY          TempList;
    PMP_HELPER_PORT     HelperPort = MP_GET_HELPPORT(Port);
    PMP_BSS_LIST       pDiscoveredBSSList = &(HelperPort->BSSList);

    //
    // Entries that are currently in use (eg for connection)
    // we cannot flush and instead would put in the temporary queue
    //
    InitializeListHead(&TempList);
    
    MP_ACQUIRE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState);
        
    while (!IsListEmpty(&(pDiscoveredBSSList->List)))
    {
        pListEntry = RemoveHeadList(&(pDiscoveredBSSList->List));
        pBSSEntry = CONTAINING_RECORD(pListEntry, MP_BSS_ENTRY, Link);

        APRefCount = NdisInterlockedDecrement(&(pBSSEntry->RefCount));
        if (APRefCount == 0)
        {        
            NdisAcquireSpinLock(&(pBSSEntry->Lock));
            MPASSERT(pBSSEntry->pAssocRequest == NULL);
            MPASSERT(pBSSEntry->pAssocResponse == 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;            
            NdisReleaseSpinLock(&(pBSSEntry->Lock));
            
            MP_FREE_MEMORY(pBSSEntry);        
        }
        else
        {
            // Restore refcount and save for adding back to list
            NdisInterlockedIncrement(&(pBSSEntry->RefCount));
            InsertTailList(&TempList, pListEntry);
        }
    }
    pDiscoveredBSSList->NumOfBSSEntries = 0;

    //
    // Restore entries that are in use
    //
    while (!IsListEmpty(&TempList))
    {
        pListEntry = RemoveHeadList(&TempList);

        InsertTailList(&(pDiscoveredBSSList->List), pListEntry);
        pDiscoveredBSSList->NumOfBSSEntries++;
    }

    // Since our scan list is flushed, also clear the last scan time
    HelperPort->ScanContext.LastScanTime = 0;
    
    MP_RELEASE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState);

    return NDIS_STATUS_SUCCESS;
}


#if DBG
NDIS_STATUS
HelperPortCheckForExtraRef(
    _In_ PMP_HELPER_PORT         HelperPort
    )
{
    MP_RW_LOCK_STATE          LockState;
    PLIST_ENTRY         pListEntry;
    PMP_BSS_ENTRY      pBSSEntry = NULL;
    PMP_BSS_LIST       pDiscoveredBSSList = &(HelperPort->BSSList);
    LIST_ENTRY          TempList;

    //
    // Entries that are currently in use (eg for connection)
    // we cannot flush and instead would put in the temporary queue
    //
    InitializeListHead(&TempList);
    
    MP_ACQUIRE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState);
        
    while (!IsListEmpty(&(pDiscoveredBSSList->List)))
    {
        pListEntry = RemoveHeadList(&(pDiscoveredBSSList->List));
        pBSSEntry = CONTAINING_RECORD(pListEntry, MP_BSS_ENTRY, Link);

        //
        // Check that the BSS entry does not have an extra ref count
        //
        MPASSERT(pBSSEntry->RefCount <= 1);
        InsertTailList(&TempList, pListEntry);
    }
    pDiscoveredBSSList->NumOfBSSEntries = 0;

    //
    // Restore entries that are in use
    //
    while (!IsListEmpty(&TempList))
    {
        pListEntry = RemoveHeadList(&TempList);

        InsertTailList(&(pDiscoveredBSSList->List), pListEntry);
        pDiscoveredBSSList->NumOfBSSEntries++;
    }
    
    MP_RELEASE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState);

    return NDIS_STATUS_SUCCESS;
}
#endif

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
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);
}




__inline NDIS_STATUS HelperPortValidateBeacon(
    _In_  PDOT11_BEACON_FRAME     pDot11BeaconFrame
    )
{
    UNREFERENCED_PARAMETER(pDot11BeaconFrame);
    return NDIS_STATUS_SUCCESS;
}


// Write lock acquired
__inline VOID
HelperPortAddBSSEntry(
    _In_  PMP_BSS_LIST           pBSSList,
    _In_  PMP_BSS_ENTRY          pBSSEntry
    )
{
    InsertTailList(&(pBSSList->List), &(pBSSEntry->Link));
    pBSSList->NumOfBSSEntries++;
}

// Write lock acquired
__inline VOID
HelperPortRemoveBSSEntry(
    _In_  PMP_BSS_LIST           pBSSList,
    _In_  PMP_BSS_ENTRY          pBSSEntry
    )
{
    RemoveEntryList(&(pBSSEntry->Link));
    pBSSList->NumOfBSSEntries--;
}

// Read Lock must be held
PMP_BSS_ENTRY
HelperPortFindBSSEntry(
    _In_  PMP_BSS_LIST           pBSSList,
    _In_  const unsigned char *   srcAddress
    )
{
    PLIST_ENTRY         pHead = NULL, pEntry = NULL;
    PMP_BSS_ENTRY      pBSSEntry = NULL;
    BOOLEAN             bFound = FALSE;

    pHead = &(pBSSList->List);
    pEntry = pHead->Flink;
    while(pEntry != pHead) 
    {
        pBSSEntry = CONTAINING_RECORD(pEntry, MP_BSS_ENTRY, Link);
        pEntry = pEntry->Flink;

        NdisAcquireSpinLock(&(pBSSEntry->Lock));
        if (MP_COMPARE_MAC_ADDRESS(pBSSEntry->MacAddress, srcAddress)) 
        {
            NdisReleaseSpinLock(&(pBSSEntry->Lock));
            bFound = TRUE;
            break;
        }
        NdisReleaseSpinLock(&(pBSSEntry->Lock));
    }

    return ((bFound)? pBSSEntry: NULL);

}

// Write lock on the list must be held
// Returns an entry that can be expired. The caller frees it
PMP_BSS_ENTRY
HelperPortExpireBSSEntry(
    _In_  PMP_BSS_LIST           pBSSList,
    _In_  ULONGLONG               ullMaxActiveTime,
    _In_  ULONGLONG               ullExpireTimeStamp
    )
{
    PLIST_ENTRY         pHead = NULL, pEntry = NULL;
    PMP_BSS_ENTRY      pBSSEntry = NULL;
    BOOLEAN             bFound = FALSE;

    //
    // We can expire an entry that has been around for longer 
    // than this time
    //
    if (ullMaxActiveTime <= ullExpireTimeStamp)
        ullExpireTimeStamp -= ullMaxActiveTime;

    pHead = &(pBSSList->List);
    pEntry = pHead->Flink;
    while(pEntry != pHead) 
    {
        pBSSEntry = CONTAINING_RECORD(pEntry, MP_BSS_ENTRY, Link);
        pEntry = pEntry->Flink;

        NdisAcquireSpinLock(&(pBSSEntry->Lock));

        //
        // If the entry is older than we expected and its not in
        // use, we can expire it
        //
        if (pBSSEntry->HostTimestamp < ullExpireTimeStamp)
        {
            if (NdisInterlockedDecrement(&(pBSSEntry->RefCount)) == 0)
            {
                MpTrace(COMP_SCAN, DBG_LOUD, ("Expiring AP: %02X-%02X-%02X-%02X-%02X-%02X\n", 
                    pBSSEntry->Dot11BSSID[0], pBSSEntry->Dot11BSSID[1], pBSSEntry->Dot11BSSID[2], 
                    pBSSEntry->Dot11BSSID[3], pBSSEntry->Dot11BSSID[4], pBSSEntry->Dot11BSSID[5]));

                MPASSERT(pBSSEntry->pAssocRequest == NULL);
                MPASSERT(pBSSEntry->pAssocResponse == NULL);
                
                //
                // This is the entry we can expire. Remove it from the list.
                //
                NdisReleaseSpinLock(&(pBSSEntry->Lock));
                HelperPortRemoveBSSEntry(pBSSList, pBSSEntry);
                
                bFound = TRUE;
                break;
            }
            else
            {
                // Someone is using the entry, we cannot remove/delete this. Add back
                // a ref and we will delete later on

                // This is subobtimal. Ideally the last person to decrement
                // refcount should delete the entry and not us. Modify to remove
                // the entry from the list, decrement its refcount and only free
                // the memory if the refcount has gone to zero
                NdisInterlockedIncrement(&(pBSSEntry->RefCount));
            }
        }
        NdisReleaseSpinLock(&(pBSSEntry->Lock));
    }

    if (bFound != TRUE)
    {
        pBSSEntry = NULL;
    }
    
    return pBSSEntry;
}


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;
}

// 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 
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;
}


Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS