Sample Code

Windows Driver Samples/ Native Wi-Fi Miniport Sample Driver/ C++/ extap/ ap_action.c/

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:
    ap_action.c

Abstract:
    Implements ExtAP actions such as start, stop
    
Revision History:
      When        What
    ----------    ----------------------------------------------
    10-01-2007    Created

Notes:

--*/
#include "precomp.h"
    
#if DOT11_TRACE_ENABLED
#include "ap_action.tmh"
#endif

//
// ported from StaAttachAdHocRSNIE
//
_At_(*pIESize, _Pre_ _In_range_(>=, sizeof(DOT11_INFO_ELEMENT) +
        sizeof(USHORT) +
        sizeof(ULONG) + 
        sizeof(USHORT) + sizeof(ULONG) +
        sizeof(USHORT) + sizeof(ULONG) +
        sizeof(USHORT)))
_At_(*ppCurrentIE, _Writes_and_advances_ptr_(*pIESize))
NDIS_STATUS
ApAttachRSNIE(
    _In_ PMP_EXTAP_PORT ApPort,
    _Inout_ PUCHAR *ppCurrentIE,
    _Inout_ PUSHORT pIESize        
    )
{
    USHORT      size;
    PVNIC vnic = AP_GET_VNIC(ApPort);

    ASSERT(AP_GET_AUTH_ALGO(ApPort) == DOT11_AUTH_ALGO_RSNA_PSK);

    //
    // Our RSN IE will contain 1 group cipher, 1 pairwise cipher, 1 AKM suite, and capability.
    //
    size = sizeof(DOT11_INFO_ELEMENT) +                 // IE ID and length
           sizeof(USHORT) +                             // version
           sizeof(ULONG) +                              // group cipher
           sizeof(USHORT) + sizeof(ULONG) +             // pairwise cipher
           sizeof(USHORT) + sizeof(ULONG) +             // AKM suite
           sizeof(USHORT);                              // capability.

    //
    // Set IE ID and length
    //
    ((DOT11_INFO_ELEMENT UNALIGNED *)(*ppCurrentIE))->ElementID = DOT11_INFO_ELEMENT_ID_RSN;
    ((DOT11_INFO_ELEMENT UNALIGNED *)(*ppCurrentIE))->Length = (UCHAR)(size - sizeof(DOT11_INFO_ELEMENT));
    *ppCurrentIE += sizeof(DOT11_INFO_ELEMENT);

    //
    // Set version
    //
    *((USHORT UNALIGNED *)(*ppCurrentIE)) = 1;
    *ppCurrentIE += sizeof(USHORT);

    //
    // Set group cipher
    //
    *((ULONG UNALIGNED *)(*ppCurrentIE)) = Dot11GetRSNOUIFromCipher(RSNA_OUI_PREFIX, AP_GET_MULTICAST_CIPHER_ALGO(ApPort));
    *ppCurrentIE += sizeof(ULONG);

    //
    // Set pairwise cipher
    //
    *((USHORT UNALIGNED *)(*ppCurrentIE)) = 1;
    *ppCurrentIE += sizeof(USHORT);
    *((ULONG UNALIGNED *)(*ppCurrentIE)) = Dot11GetRSNOUIFromCipher(RSNA_OUI_PREFIX, AP_GET_UNICAST_CIPHER_ALGO(ApPort));
    *ppCurrentIE += sizeof(ULONG);

    //
    // Set AKM suite
    //
    *((USHORT UNALIGNED *)(*ppCurrentIE)) = 1;
    *ppCurrentIE += sizeof(USHORT);
    *((ULONG UNALIGNED *)(*ppCurrentIE)) = Dot11GetRSNOUIFromAuthAlgo(AP_GET_AUTH_ALGO(ApPort));
    *ppCurrentIE += sizeof(ULONG);

    //
    // Set capability. Get the capability from hardware layer.
    //
    *((USHORT UNALIGNED *)(*ppCurrentIE)) = VNic11QueryRSNCapabilityField(vnic);
    *ppCurrentIE += sizeof(USHORT);

    //
    // Update remaining IE size.
    //
    *pIESize = *pIESize - size;

    return NDIS_STATUS_SUCCESS;
}

NDIS_STATUS
ConstructAPIEBlob(
    _In_ PMP_EXTAP_PORT ApPort,
    PUCHAR ieBlobPtr,
    BOOLEAN bResponseIE,
    USHORT *pIEBlobSize,
    USHORT *pbytesWritten
)
{
    PUCHAR ieBlobStart = ieBlobPtr;
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
    DOT11_PHY_TYPE phyType;
    UCHAR channel;
    PVNIC vnic = AP_GET_VNIC(ApPort);
    PVOID pAdditionalIEData = NULL;
    ULONG uAdditionalIESize;
    BOOLEAN isPreferredChannel;

    *pbytesWritten = 0;
    
    do
    {
        //
        // Add SSID.
        //

        ndisStatus = Dot11AttachElement(
                        &ieBlobPtr,
                        pIEBlobSize,
                        DOT11_INFO_ELEMENT_ID_SSID,
                        (UCHAR)(AP_GET_SSID(ApPort).uSSIDLength),
                        AP_GET_SSID(ApPort).ucSSID
                        );
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): Failed to attach SSID IE. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
            break;
        }

        //
        // Add basic rate set.
        //

        ndisStatus = Dot11AttachElement(
                        &ieBlobPtr,
                        pIEBlobSize,
                        DOT11_INFO_ELEMENT_ID_SUPPORTED_RATES,
                        (UCHAR)((AP_GET_OPERATIONAL_RATE_SET(ApPort).uRateSetLength > 8) ? 8 : AP_GET_OPERATIONAL_RATE_SET(ApPort).uRateSetLength),
                        AP_GET_OPERATIONAL_RATE_SET(ApPort).ucRateSet
                        );
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): Failed to attach rate set IE. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
            break;
        }

        if (AP_GET_OPERATIONAL_RATE_SET(ApPort).uRateSetLength > (UCHAR)8) 
        {
            ndisStatus = Dot11AttachElement(
                            &ieBlobPtr,
                            pIEBlobSize,
                            DOT11_INFO_ELEMENT_ID_EXTD_SUPPORTED_RATES,
                            (UCHAR)(AP_GET_OPERATIONAL_RATE_SET(ApPort).uRateSetLength - 8),
                            AP_GET_OPERATIONAL_RATE_SET(ApPort).ucRateSet + 8
                            );
            
            if (ndisStatus != NDIS_STATUS_SUCCESS)
            {
                MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): Failed to attach rate set IE. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
                break;
            }
        }

        //
        // Add PHY specific IEs
        //

        phyType = VNic11QueryCurrentPhyType(vnic);
        channel = (UCHAR)VNic11QueryPreferredChannel(vnic, &isPreferredChannel);

        if (!isPreferredChannel)
        {
            channel = 11;

        }
        
        switch (phyType)
        {
            case dot11_phy_type_erp:
            case dot11_phy_type_hrdsss:
            case dot11_phy_type_dsss:

                //
                // Attach DSSS IE
                //
                
                ndisStatus = Dot11AttachElement(
                                &ieBlobPtr,
                                pIEBlobSize,
                                DOT11_INFO_ELEMENT_ID_DS_PARAM_SET,
                                sizeof(channel),
                                &channel
                                );
                
                if (ndisStatus != NDIS_STATUS_SUCCESS)
                {
                    MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): Failed to attach DSSS IE. Status = 0x%08x.", 
                                        AP_GET_PORT_NUMBER(ApPort),
                                        ndisStatus));
                    break;
                }

                break;

            case dot11_phy_type_fhss:

                //
                // Attach FHSS IE
                //
#if 0                
                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(&ieBlobPtr,
                                                    pIEBlobSize,
                                                    DOT11_INFO_ELEMENT_ID_FH_PARAM_SET,
                                                    sizeof(FHSSIE),
                                                    (PVOID)&FHSSIE);
                    if (ndisStatus != NDIS_STATUS_SUCCESS)
                        __leave;
                }
      
#endif
                break;
            case dot11_phy_type_ofdm:
                break;

            case dot11_phy_type_irbaseband:
                break;

            default:
                break;
        }

#if 0
        //
        // 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)) 
            {
                ndisStatus = VNic11SetATIMWindow(vnic, (ULONG)ATIMWindow);
                if (ndisStatus != NDIS_STATUS_SUCCESS)
                    __leave;
            }
        }
#endif

        //
        // If we are running RSNA_PSK, add RSN IE.
        //
        if (DOT11_AUTH_ALGO_RSNA_PSK == AP_GET_AUTH_ALGO(ApPort))
        {
            //
            // Tell hardware layer what group cipher we use.
            //
            VNic11SetCipher(vnic, FALSE, AP_GET_MULTICAST_CIPHER_ALGO(ApPort));

            ndisStatus = ApAttachRSNIE(
                 ApPort, 
                 &ieBlobPtr,
                 pIEBlobSize
                 );
            if (ndisStatus != NDIS_STATUS_SUCCESS)
                break;
        }

        //
        // Add any additional IEs if we still have space.
        // No need to hold a lock on the AP configuration because OIDs are serialized.
        //
        if (! bResponseIE)
        {
            // include additional beacon IE
            pAdditionalIEData = AP_GET_BEACON_IE(ApPort);
            uAdditionalIESize = AP_GET_BEACON_IE_SIZE(ApPort);
        }
        else
        {
            // include probe response IE
            pAdditionalIEData = AP_GET_PROBE_RESPONSE_IE(ApPort);
            uAdditionalIESize = AP_GET_PROBE_RESPONSE_IE_SIZE(ApPort);
        }

        if (pAdditionalIEData != NULL && 
            uAdditionalIESize != 0 &&
            uAdditionalIESize <= *pIEBlobSize
            )
        {
            NdisMoveMemory(
                ieBlobPtr, 
                pAdditionalIEData,
                uAdditionalIESize
                );
            ieBlobPtr += uAdditionalIESize;
            *pIEBlobSize = *pIEBlobSize - ((USHORT)uAdditionalIESize);
        }

        *pbytesWritten = (USHORT)PtrOffset(ieBlobStart, ieBlobPtr);
    } while (FALSE);

    return ndisStatus;
}

/** Start AP */
NDIS_STATUS
StartExtAp(
    _In_ PMP_EXTAP_PORT ApPort
    )
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
    PVNIC vnic = AP_GET_VNIC(ApPort);
    PMP_BSS_DESCRIPTION bssDescription = NULL;
//    DOT11_CAPABILITY dot11Capability = {0};
//    BOOLEAN set;
//    DOT11_PHY_TYPE phyType;
    PUCHAR ieBlobPtr;
    USHORT ieBlobSize, blobBytesWritten = 0;
    PUCHAR ieBlobPtr2;
//    PUCHAR tmpPtr;
//    UCHAR size;
//    DOT11_RATE_SET rateSet;
//    ULONG index;
    UCHAR channel;
//    USHORT ATIMWindow;
//    STA_FHSS_IE FHSSIE = {0};
//    BOOLEAN iePresent;
    BOOLEAN notifyCompletion = FALSE;           // need to notify VNIC that the connection is complete
    BOOLEAN CtxSBarrierAcquired = FALSE;
    BOOLEAN preferredChannelSet;
    
    MPASSERT(ApGetState(ApPort) == AP_STATE_STOPPED);
    do 
    {
        //
        // Set AP start to starting
        //
        ApSetState(ApPort, AP_STATE_STARTING);
        

        //
        // start association manager
        //
        ndisStatus = ApStartAssocMgr(AP_GET_ASSOC_MGR(ApPort));

        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_OID, DBG_SERIOUS, ("Port(%u): Failed to start association manager. Status = 0x%08x.", 
                                AP_GET_PORT_NUMBER(ApPort), ndisStatus));
            break;
        }

        //
        // Allocate a BSS description structure with maximum possible IE field.
        //

        MP_ALLOCATE_MEMORY(
            AP_GET_MP_HANDLE(ApPort),
            &bssDescription, 
            FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + AP11_MAX_IE_BLOB_SIZE * 2,
            EXTAP_MEMORY_TAG
            );
        
        if (NULL == bssDescription)
        {
            MpTrace(COMP_OID, DBG_SERIOUS, ("Port(%u): Failed to allocate %d bytes for BSS description.",
                                AP_GET_PORT_NUMBER(ApPort),
                                FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + AP11_MAX_IE_BLOB_SIZE * 2));
            ndisStatus = NDIS_STATUS_RESOURCES;
            break;
        }
        NdisZeroMemory(bssDescription, FIELD_OFFSET(MP_BSS_DESCRIPTION, IEBlobs) + AP11_MAX_IE_BLOB_SIZE * 2);

        //
        // Initialize the BSS description structure
        //

        bssDescription->BSSType = dot11_BSS_type_infrastructure;
        bssDescription->Timestamp = 0;

        //
        // set BSSID
        //
        NdisMoveMemory(
            bssDescription->BSSID, 
            AP_GET_BSSID(ApPort), 
            sizeof(DOT11_MAC_ADDRESS)
            );

        NdisMoveMemory(
            bssDescription->MacAddress, 
            VNic11QueryMACAddress(vnic), 
            sizeof(DOT11_MAC_ADDRESS)
            );

        //
        // set beacon period
        //
        bssDescription->BeaconPeriod = (USHORT)AP_GET_CONFIG(ApPort)->BeaconPeriod;
        
        //
        // Fill the capabilityInformation 
        // 

        bssDescription->Capability.usValue = AP_GET_CAPABILITY_INFO(ApPort).usValue;

        //
        // Set the starting address and size of the beacon IE blobs
        //
        bssDescription->BeaconIEBlobOffset = 0;
       
        ieBlobPtr = &bssDescription->IEBlobs[bssDescription->BeaconIEBlobOffset];
        ieBlobSize = AP11_MAX_IE_BLOB_SIZE;

        ndisStatus = ConstructAPIEBlob(ApPort, ieBlobPtr, FALSE, &ieBlobSize, &blobBytesWritten);

        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): ConstructAPIEBlob for Beacon failed. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
            break;
        }
        
        bssDescription->BeaconIEBlobSize = blobBytesWritten;

        //
        // save a copy of the IE blob
        //
        MP_ALLOCATE_MEMORY(
            AP_GET_MP_HANDLE(ApPort),
            &ieBlobPtr2, 
            blobBytesWritten,
            EXTAP_MEMORY_TAG
            );
        if (ieBlobPtr2 != NULL)
        {
            NdisMoveMemory(
                ieBlobPtr2,
                ieBlobPtr,
                blobBytesWritten
                );
            CfgSaveBeaconIe(
                AP_GET_CONFIG(ApPort),
                ieBlobPtr2,
                blobBytesWritten
                );
        }

        //
        // Set the starting address and size of the probe response IE blobs
        //
        bssDescription->ProbeIEBlobOffset = bssDescription->BeaconIEBlobSize;
       
        ieBlobPtr = &bssDescription->IEBlobs[bssDescription->ProbeIEBlobOffset];
        ieBlobSize = AP11_MAX_IE_BLOB_SIZE;

        ndisStatus = ConstructAPIEBlob(ApPort, ieBlobPtr, TRUE, &ieBlobSize, &blobBytesWritten);
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): ConstructAPIEBlob for Probe Response failed. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
            break;
        }
        
        bssDescription->ProbeIEBlobSize = blobBytesWritten;
        bssDescription->IEBlobsSize = bssDescription->ProbeIEBlobSize + bssDescription->BeaconIEBlobSize;

        //
        // Notify VNIC that we need hardware access 
        //
        VNic11NotifyConnectionStatus(
            vnic,
            TRUE,                   // connected
            NDIS_STATUS_DOT11_CONNECTION_START,
            NULL,                   // status buffer
            0                       // status buffer size
            );

        //
        // Need to notify VNIC that connection is complete
        //
        notifyCompletion = TRUE;
        
        //
        // Set the AP channel
        //
        channel = (UCHAR)VNic11QueryPreferredChannel(vnic, &preferredChannelSet);

        // Set the default channel of AP to 11, this is fine because AP is only supported on 802.11b/g
        if (!preferredChannelSet)
        {
            channel = 11;

        }
        NdisResetEvent(&AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionEvent);
        // TODO: Need to get the PHY also
        ndisStatus = VNic11SetChannel(vnic, channel, 0, TRUE, Ap11SetChannelCompleteCallback);
        if (ndisStatus == NDIS_STATUS_PENDING)
        {
            //
            // Wait for the event that signals start completion
            //
            NdisWaitEvent(&AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionEvent, 0);

            ndisStatus = AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionStatus;
        }

        if (NDIS_STATUS_SUCCESS != ndisStatus)
        {
            MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): Set channel failed. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
            break;
        }

        // let the OS know the channel we are working on
        ApIndicateFrequencyAdoped(ApPort);

        VNic11AcquireCtxSBarrier(vnic);
        CtxSBarrierAcquired = TRUE;
        
        //
        // Start beaconing and receiving data frames.
        //
        NdisResetEvent(&AP_GET_ASSOC_MGR(ApPort)->StartBSSCompletionEvent);

        ndisStatus = VNic11StartBSS(vnic, bssDescription, Ap11StartBSSCompleteCallback);
        if (ndisStatus == NDIS_STATUS_PENDING)
        {
            //
            // Wait for the event that signals start completion
            //
            NdisWaitEvent(&AP_GET_ASSOC_MGR(ApPort)->StartBSSCompletionEvent, 0);

            ndisStatus = AP_GET_ASSOC_MGR(ApPort)->StartBSSCompletionStatus;
        }

        if (NDIS_STATUS_SUCCESS == ndisStatus)
        {
            //
            // Set TX data rate and our active PhyId
            //
            VNic11SelectTXDataRate(vnic, &(AP_GET_OPERATIONAL_RATE_SET(ApPort)), 100);
            // TODO: get active Phy ID
        }
    } while (FALSE);
    
    if (bssDescription != NULL)
    {
        MP_FREE_MEMORY(bssDescription);
    }

    if (CtxSBarrierAcquired)
    {
        VNic11ReleaseCtxSBarrier(vnic);
    }
    
    if (notifyCompletion)
    {
        //
        // Notify VNIC that we don't need hardware access any more
        //
        VNic11NotifyConnectionStatus(
            vnic,
            (ndisStatus == NDIS_STATUS_SUCCESS) ? TRUE : FALSE,
            NDIS_STATUS_DOT11_CONNECTION_COMPLETION,
            NULL,                   // status buffer
            0                       // status buffer size
            );
    }
        
    if (NDIS_STATUS_SUCCESS == ndisStatus)
    {
        // 
        // AP is started
        //
        ApSetState(ApPort, AP_STATE_STARTED);
        
        MpTrace(COMP_OID, DBG_NORMAL, 
                ("Port(%u): AP successfully started.", AP_GET_PORT_NUMBER(ApPort)));

        // 
        // Set the base port to OP mode
        //
        AP_GET_MP_PORT(ApPort)->CurrentOpState = OP_STATE;
    }
    else
    {
        // 
        // Stop association manager
        //
        ApStopAssocMgr(AP_GET_ASSOC_MGR(ApPort));

        MpTrace(COMP_OID, DBG_NORMAL, 
                ("Port(%u): AP failed to start. Status = 0x%08x.", AP_GET_PORT_NUMBER(ApPort), ndisStatus));

        // 
        // AP is not started
        //
        ApSetState(ApPort, AP_STATE_STOPPED);
    }
    
    return ndisStatus;
}

NDIS_STATUS
Ap11StartBSSCompleteCallback(
    _In_ PMP_PORT Port,
    _In_ PVOID Data
    )
{
    PMP_EXTAP_PORT apPort = MP_GET_AP_PORT(Port);

    // Set the start completion event
    AP_GET_ASSOC_MGR(apPort)->StartBSSCompletionStatus = *((PNDIS_STATUS)Data);
    NdisSetEvent(&AP_GET_ASSOC_MGR(apPort)->StartBSSCompletionEvent);

    return NDIS_STATUS_SUCCESS;
}

NDIS_STATUS
Ap11SetChannelCompleteCallback(
    _In_ PMP_PORT Port,
    _In_ PVOID Data
    )
{
    PMP_EXTAP_PORT apPort = MP_GET_AP_PORT(Port);
    
    // Set the set channel completion event
    AP_GET_ASSOC_MGR(apPort)->SetChannelCompletionStatus = *((PNDIS_STATUS)Data);
    NdisSetEvent(&AP_GET_ASSOC_MGR(apPort)->SetChannelCompletionEvent);

    return NDIS_STATUS_SUCCESS;
}


/** Stop AP */
NDIS_STATUS
StopExtAp(
    _In_ PMP_EXTAP_PORT ApPort
    )
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;

    MPASSERT(ApGetState(ApPort) == AP_STATE_STARTED);
    
    // 
    // Set AP state to stopping so that no packets will be processed
    //

    ApSetState(ApPort, AP_STATE_STOPPING);

    //
    // stop beacon
    //
    ndisStatus = StopExtApBss(ApPort);

    // 
    // Wait for AP reference count to reach 1
    //
    while (ApPort->RefCount > 1)
    {
        NdisMSleep(10000);
    }
    
    //
    // stop association manager
    //
    ApStopAssocMgr(&ApPort->AssocMgr);

    //
    // Wait for DPCs to complete
    // This ensures all timeout callbacks return
    //
    KeFlushQueuedDpcs();
    
    ApSetState(ApPort, AP_STATE_STOPPED);
    
    MpTrace(COMP_OID, DBG_NORMAL, 
            ("Port(%u): AP successfully stopped.", AP_GET_PORT_NUMBER(ApPort)));

    // 
    // Set the base port to INIT mode
    //
    AP_GET_MP_PORT(ApPort)->CurrentOpState = INIT_STATE;
    
    return ndisStatus;
}


/** Stop Ext AP BSS */
NDIS_STATUS
StopExtApBss(
    _In_ PMP_EXTAP_PORT ApPort
    )
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
    PVNIC vnic = AP_GET_VNIC(ApPort);

    NdisResetEvent(&AP_GET_ASSOC_MGR(ApPort)->StopBSSCompletionEvent);

    ndisStatus = VNic11StopBSS(vnic, Ap11StopBSSCompleteCallback);
    if (ndisStatus == NDIS_STATUS_PENDING)
    {
        //
        // Wait for the event that signals stop completion
        //
        NdisWaitEvent(&AP_GET_ASSOC_MGR(ApPort)->StopBSSCompletionEvent, 0);
        ndisStatus = NDIS_STATUS_SUCCESS;
    }    

    return ndisStatus;
}


NDIS_STATUS
Ap11StopBSSCompleteCallback(
    _In_ PMP_PORT Port,
    _In_ PVOID Data
    )
{
    PMP_EXTAP_PORT apPort = MP_GET_AP_PORT(Port);

    UNREFERENCED_PARAMETER(Data);
    
    // Set the stop completion event
    NdisSetEvent(&AP_GET_ASSOC_MGR(apPort)->StopBSSCompletionEvent);

    return NDIS_STATUS_SUCCESS;
}


/** Restart AP */
NDIS_STATUS
RestartExtAp(
    _In_ PMP_EXTAP_PORT ApPort
    )
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;

    ndisStatus = ApRestartAssocMgr(AP_GET_ASSOC_MGR(ApPort));

    return ndisStatus;
}

/** Pause AP */
NDIS_STATUS
PauseExtAp(
    _In_ PMP_EXTAP_PORT ApPort
    )
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;

    ndisStatus = ApPauseAssocMgr(AP_GET_ASSOC_MGR(ApPort));

    return ndisStatus;
}

VOID
Ap11Notify(
    _In_  PMP_PORT        Port,
    PVOID               Notif
)
{
    NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_EXTAP_PORT ApPort = MP_GET_AP_PORT(Port);
    PNOTIFICATION_DATA_HEADER pHdr = (PNOTIFICATION_DATA_HEADER)Notif;
    PUCHAR beaconIEBlobPtr = NULL, probeIEBlobPtr = NULL;
    USHORT beaconIEBlobSizeAllocated = 0, beaconIEBlobSize = 0;
    USHORT probeIEBlobSizeAllocated = 0, probeIEBlobSize = 0;
    UCHAR channel;
    PVNIC vnic = AP_GET_VNIC(ApPort);
    BOOLEAN isPreferredChannel;
    BOOLEAN bBeaconIESet = FALSE;

    // if AP is not running, we needn't do anything
    if (ApGetState(ApPort) != AP_STATE_STARTED)
    {
        return;
    }

    // BUGBUG:Synchronize this function with AP start/stop
    switch (pHdr->Type)
    {
        case NotificationOpChannel:
        {
            if (VNic11QueryPreferredChannel(vnic, &isPreferredChannel) == VNic11QueryCurrentChannel(vnic, FALSE))
            {
                // No need to do anything here
                MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): AP is already running on preferred channel.",
                                    AP_GET_PORT_NUMBER(ApPort)));
                
                break;
            }

            //
            // Update the beacon in the hardware
            //
            MP_ALLOCATE_MEMORY(
                AP_GET_MP_HANDLE(ApPort),
                &beaconIEBlobPtr, 
                AP11_MAX_IE_BLOB_SIZE,
                EXTAP_MEMORY_TAG
                );
            
            if (NULL == beaconIEBlobPtr)
            {
                MpTrace(COMP_OID, DBG_SERIOUS, ("Port(%u): Failed to allocate %d bytes for beacon IEs.",
                                    AP_GET_PORT_NUMBER(ApPort),
                                    AP11_MAX_IE_BLOB_SIZE));
                break;
            }
            
            NdisZeroMemory(beaconIEBlobPtr, AP11_MAX_IE_BLOB_SIZE);

            beaconIEBlobSizeAllocated = AP11_MAX_IE_BLOB_SIZE;
            ndisStatus = ConstructAPIEBlob(ApPort, beaconIEBlobPtr, FALSE, &beaconIEBlobSizeAllocated, &beaconIEBlobSize);
            if (NDIS_STATUS_SUCCESS != ndisStatus)
            {
               MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): ConstructAPIEBlob for beacon failed. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
               break;
            }

            //
            // Update the probe response in the hardware
            //
            MP_ALLOCATE_MEMORY(
                 AP_GET_MP_HANDLE(ApPort),
                 &probeIEBlobPtr, 
                 AP11_MAX_IE_BLOB_SIZE,
                 EXTAP_MEMORY_TAG
                 );
             
            if (NULL == probeIEBlobPtr)
            {
                MpTrace(COMP_OID, DBG_SERIOUS, ("Port(%u): Failed to allocate %d bytes for probe response IEs.",
                                     AP_GET_PORT_NUMBER(ApPort),
                                     AP11_MAX_IE_BLOB_SIZE));
                break;
            }
             
            NdisZeroMemory(probeIEBlobPtr, AP11_MAX_IE_BLOB_SIZE);
            
            probeIEBlobSizeAllocated = AP11_MAX_IE_BLOB_SIZE;
            ndisStatus = ConstructAPIEBlob(ApPort, probeIEBlobPtr, TRUE, &probeIEBlobSizeAllocated, &probeIEBlobSize);
            if (NDIS_STATUS_SUCCESS != ndisStatus)
            {
                MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): ConstructAPIEBlob for probe response failed. Status = 0x%08x.", 
                                     AP_GET_PORT_NUMBER(ApPort),
                                     ndisStatus));
                break;
            }

            // 
            // Disassociate all stations before shifting channel
            //
            AmDisassociatePeerRequest(
                AP_GET_ASSOC_MGR(ApPort), 
                &Dot11BroadcastAddress, 
                DOT11_MGMT_REASON_UPSPEC_REASON             // TODO: a better reason code
                );

            // Set beacon IE
            ndisStatus = VNic11SetBeaconIE(Port->VNic, beaconIEBlobPtr, beaconIEBlobSize);
            if (NDIS_STATUS_SUCCESS != ndisStatus)
            {
                MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): VNic11SetBeaconIE failed. Status = 0x%08x.", 
                                    AP_GET_PORT_NUMBER(ApPort),
                                    ndisStatus));
                break;
            }
            bBeaconIESet = TRUE;

            // Set probe response IE
            ndisStatus = VNic11SetProbeResponseIE(Port->VNic, probeIEBlobPtr, probeIEBlobSize);
            if (NDIS_STATUS_SUCCESS != ndisStatus)
            {
                MpTrace(COMP_OID, DBG_NORMAL, ("Port(%u): VNic11SetProbeResponseIE failed. Status = 0x%08x.", 
                                     AP_GET_PORT_NUMBER(ApPort),
                                     ndisStatus));
                break;
            }
            
            channel = (UCHAR)VNic11QueryPreferredChannel(vnic, &isPreferredChannel);
                
            NdisResetEvent(&AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionEvent);

            ndisStatus = VNic11SetChannel(vnic, channel, 0, TRUE, Ap11SetChannelCompleteCallback);
            if (ndisStatus == NDIS_STATUS_PENDING)
            {
                //
                // Wait for the event that signals start completion
                //
                NdisWaitEvent(&AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionEvent, 0);

                ndisStatus = AP_GET_ASSOC_MGR(ApPort)->SetChannelCompletionStatus;
            }

            if (NDIS_STATUS_SUCCESS != ndisStatus)
            {
                break;
            }

            // let the OS know the channel we are working on
            ApIndicateFrequencyAdoped(ApPort);
        
        }
        break;

        default:
            break;
    };

    if (beaconIEBlobPtr != NULL)
    {
        if (TRUE == bBeaconIESet)
        {
            // save the beacon IE for assoc completion params
            CfgSaveBeaconIe(&ApPort->Config, beaconIEBlobPtr, beaconIEBlobSize);
        }
        else
        {
            MP_FREE_MEMORY(beaconIEBlobPtr);
        }
    }

    if (probeIEBlobPtr != NULL)
    {
        MP_FREE_MEMORY(probeIEBlobPtr);
    }
    
}

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