Sample Code

windows driver samples/ Native Wi-Fi Miniport Sample Driver/ C++/ driver/ helper_port_main.c/

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:
    helper_port_main.c

Abstract:
    Implements the interfaces 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 "vnic_intf.h"
#include "helper_port_main.h"
#include "helper_port_bsslist.h"
#include "helper_port_scan.h"
#include "glb_utils.h"

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


MP_REG_ENTRY HelperRegTable[] = {
    {
        NDIS_STRING_CONST("BSSEntryMaxCount"), 
        NdisParameterInteger,
        0,      // This is the structure passed in
        FIELD_OFFSET(MP_HELPER_REG_INFO, BSSEntryMaxCount),
        sizeof(ULONG),
        MP_BSS_ENTRY_MAX_ENTRIES_DEFAULT,
        MP_BSS_ENTRY_MAX_ENTRIES_MIN,
        MP_BSS_ENTRY_MAX_ENTRIES_MAX 
    },

    {
        NDIS_STRING_CONST("BSSEntryExpireTime"), 
        NdisParameterInteger,
        0,      // This is the structure passed in
        FIELD_OFFSET(MP_HELPER_REG_INFO, BSSEntryExpireTime),
        sizeof(ULONG),
        MP_BSS_ENTRY_EXPIRE_TIME_DEFAULT,
        MP_BSS_ENTRY_EXPIRE_TIME_MIN,
        MP_BSS_ENTRY_EXPIRE_TIME_MAX    
    },

    {
        NDIS_STRING_CONST("RSSILinkQualityThreshold"), 
        NdisParameterInteger,
        0,      // This is the structure passed in
        FIELD_OFFSET(MP_HELPER_REG_INFO, RSSILinkQualityThreshold),
        sizeof(ULONG),
        MP_POOR_LINK_QUALITY_THRESHOLD_DEFAULT,
        MP_POOR_LINK_QUALITY_THRESHOLD_MIN,
        MP_POOR_LINK_QUALITY_THRESHOLD_MAX 
    },

    {
        NDIS_STRING_CONST("ActiveScanChannelCount"), 
        NdisParameterInteger,
        0,      // This is the structure passed in
        FIELD_OFFSET(MP_HELPER_REG_INFO, ActiveScanChannelCount),
        sizeof(ULONG),
        MP_SCAN_SET_CHANNEL_COUNT_ACTIVE_DEFAULT,
        MP_SCAN_SET_CHANNEL_COUNT_ACTIVE_MIN,
        MP_SCAN_SET_CHANNEL_COUNT_ACTIVE_MAX
    },

    {
        NDIS_STRING_CONST("PassiveScanChannelCount"), 
        NdisParameterInteger,
        0,
        FIELD_OFFSET(MP_HELPER_REG_INFO, PassiveScanChannelCount),
        sizeof(ULONG),
        MP_SCAN_SET_CHANNEL_COUNT_PASSIVE_DEFAULT,
        MP_SCAN_SET_CHANNEL_COUNT_PASSIVE_MIN,
        MP_SCAN_SET_CHANNEL_COUNT_PASSIVE_MAX
    },

    {
        NDIS_STRING_CONST("ScanRescheduleTime"), 
        NdisParameterInteger,
        0,
        FIELD_OFFSET(MP_HELPER_REG_INFO, ScanRescheduleTime),
        sizeof(ULONG),
        MP_SCAN_RESCHEDULE_TIME_MS_DEFAULT,
        MP_SCAN_RESCHEDULE_TIME_MS_MIN,
        MP_SCAN_RESCHEDULE_TIME_MS_MAX 
    },


    {
        NDIS_STRING_CONST("InterScanTime"), 
        NdisParameterInteger,
        0,
        FIELD_OFFSET(MP_HELPER_REG_INFO, InterScanTime),
        sizeof(ULONG),
        MP_INTER_SCAN_TIME_DEFAULT,
        MP_INTER_SCAN_TIME_MIN,
        MP_INTER_SCAN_TIME_MAX 
    }
    
};

#define HELPER_NUM_REG_PARAMS       (((ULONG)sizeof (HelperRegTable)) / ((ULONG)sizeof(MP_REG_ENTRY)))


NDIS_STATUS
HelperPortLoadRegistryInformation(
    _In_        NDIS_HANDLE             MiniportAdapterHandle,
    _In_opt_    NDIS_HANDLE             ConfigurationHandle,
    _Out_       PVOID*                  RegistryInformation
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_REG_INFO         helperRegInfo = NULL;

    *RegistryInformation = NULL;
    do
    {
        //
        // Allocate memory for the registry info
        //
        MP_ALLOCATE_MEMORY(MiniportAdapterHandle, &helperRegInfo, sizeof(MP_HELPER_REG_INFO), PORT_MEMORY_TAG);
        if (helperRegInfo == NULL)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate %d bytes for MP_HELPER_REG_INFO\n",
                                 sizeof(MP_HELPER_REG_INFO)));
            ndisStatus = NDIS_STATUS_RESOURCES;
            break;
        }

        NdisZeroMemory(helperRegInfo, sizeof(MP_HELPER_REG_INFO));

        //
        // read registry values 
        //
        MpReadRegistry((PVOID)helperRegInfo, ConfigurationHandle, HelperRegTable, HELPER_NUM_REG_PARAMS);

        *RegistryInformation = helperRegInfo;
    } while (FALSE);

    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        // Free the buffer
        HelperPortFreeRegistryInformation(helperRegInfo);
        helperRegInfo = NULL;
    }
    
    return ndisStatus;
}

VOID
HelperPortFreeRegistryInformation(
    _In_opt_  PVOID              RegistryInformation
    )
{
    if (RegistryInformation != NULL)
    {
        MP_FREE_MEMORY(RegistryInformation);
    }
}

NDIS_STATUS
HelperPortAllocatePort(
    _In_  NDIS_HANDLE             MiniportAdapterHandle,
    _In_  PADAPTER                Adapter,
    _In_  PMP_PORT                Port
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             newHelperPort = NULL;

    UNREFERENCED_PARAMETER(Adapter);

    do
    {
        // Allocate the helper port specific structure
        MP_ALLOCATE_MEMORY(MiniportAdapterHandle, &newHelperPort, sizeof(MP_HELPER_PORT), PORT_MEMORY_TAG);
        if (newHelperPort == NULL)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate %d bytes for helper port\n",
                                 sizeof(MP_HELPER_PORT)));
            ndisStatus = NDIS_STATUS_RESOURCES;
            break;
        }

        // Clear everything
        NdisZeroMemory(newHelperPort, sizeof(MP_HELPER_PORT));

        // Save pointer to the parent port & vice versa
        Port->ChildPort = newHelperPort;
        newHelperPort->ParentPort = Port;

    } while (FALSE);

    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        if (Port != NULL)
        {
            HelperPortFreePort(Port);
        }
    }

    return ndisStatus;

}


VOID
HelperPortFreePort(
    _In_  PMP_PORT                Port
    )
{
    PMP_HELPER_PORT             helperPort = NULL;

    if (Port->ChildPort != NULL)
    {
        // Delete the helper port structure associated with this port
        helperPort = Port->ChildPort;
        MP_FREE_MEMORY(helperPort);
    }                
}


NDIS_STATUS
HelperPortInitializePort(
    _In_  PMP_PORT                Port,
    _In_  PVOID                   RegistryInformation
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    BOOLEAN                     freeBSSList = FALSE, freeScanContext = FALSE;

    do
    {
        // Save the registry value
        helperPort->RegInfo = (PMP_HELPER_REG_INFO)RegistryInformation;
    
        ndisStatus = HelperPortInitializeBSSList(helperPort);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        freeBSSList = TRUE;

        ndisStatus = HelperPortInitializeScanContext(helperPort);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        freeScanContext = TRUE;

        helperPort->DevicePowerState = NdisDeviceStateD0;
        
        // Setup the default handler functions
        Port->ReceiveEventHandler = HelperPortReceiveEventHandler;

    }while (FALSE);
    
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        if (freeScanContext)
        {
            HelperPortTerminateScanContext(helperPort);
        }
        
        if (freeBSSList)
        {
            HelperPortTerminateBSSList(helperPort);
        }
    }
    
    return ndisStatus;
}

VOID
HelperPortTerminatePort(
    _In_  PMP_PORT                Port
    )
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);

    HelperPortTerminateScanContext(helperPort);

#if DBG
    HelperPortCheckForExtraRef(helperPort);
#endif

    HelperPortFlushBSSList(Port);

    // Cleanup the BSS list
    HelperPortTerminateBSSList(helperPort);
}


NDIS_STATUS
HelperPortRequestExclusiveAccess(
    _In_  PMP_HELPER_PORT       HelperPort,
    _In_  PORT11_GENERIC_CALLBACK_FUNC CallbackFunction,
    _In_  PVOID                 Context,
    _In_  BOOLEAN               PnPOperation
    )
{
    NDIS_STATUS                 ndisStatus;

    NdisInterlockedIncrement(&HelperPort->Tracking_ExclusiveAccessAcquireCount);
    ndisStatus = VNic11ReqExAccess(HELPPORT_GET_VNIC(HelperPort), 
                     CallbackFunction, 
                     Context,
                     PnPOperation
                     );
    if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING))
    {
        // Request failed
        
        // Update the exclusive release access for ref debugging
        NdisInterlockedIncrement(&HelperPort->Tracking_ExclusiveAccessReleaseCount);    
    }

    return ndisStatus;
}

VOID
HelperPortReleaseExclusiveAccess(
    _In_  PMP_HELPER_PORT       HelperPort
    )
{
    // We have exclusive access
    NdisInterlockedDecrement(&HelperPort->Debug_ExclusiveAccessCount);

    NdisInterlockedIncrement(&HelperPort->Tracking_ExclusiveAccessReleaseCount);    
    VNic11ReleaseExAccess(HELPPORT_GET_VNIC(HelperPort));
}


VOID
HelperPortExclusiveAccessGranted(
    _In_  PMP_HELPER_PORT       HelperPort
    )
{
    // We have exclusive access
    NdisInterlockedIncrement(&HelperPort->Debug_ExclusiveAccessCount);

    NdisInterlockedIncrement(&HelperPort->Tracking_ExclusiveAccessGrantCount);    
}

VOID
HelperPortDelegateExclusiveAccess(
    _In_  PMP_HELPER_PORT       HelperPort,
    _In_  PMP_PORT              PortToActivate
    )
{
    // If we have multiple exclusive accesses, we cannot delegate
    MPASSERT(HelperPort->Debug_ExclusiveAccessCount == 1);
    
    Hvl11ActivatePort(HELPPORT_GET_MP_PORT(HelperPort)->Adapter->Hvl, PORT_GET_VNIC(PortToActivate));
}

NDIS_STATUS 
HelperPortPauseMiniport(
    _In_        PMP_HELPER_PORT                 HelperPort,
    _In_        BOOLEAN                         IsInternal,
    _In_opt_    PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PADAPTER                    adapter = HELPPORT_GET_MP_PORT(HelperPort)->Adapter;
    ULONG                       i;

    MpEntry;
    UNREFERENCED_PARAMETER(MiniportPauseParameters);

//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("==> Helper Port Pause\n"));        

    HELPPORT_GET_MP_PORT(HelperPort)->PauseCount++;
    
    if (HELPPORT_GET_MP_PORT(HelperPort)->PauseCount > 1)
    {
        // We are already paused, no need to do anything

        MpExit;
//        MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("<== Helper Port Pause\n"));        

        return NDIS_STATUS_SUCCESS;
    }
        
    // Set the pausing flag on the adapter
    MP_ACQUIRE_ADAPTER_LOCK(adapter, FALSE);
    MP_SET_ADAPTER_STATUS(adapter, MP_ADAPTER_PAUSING);
    MP_RELEASE_ADAPTER_LOCK(adapter, FALSE);

    for (i = 0; i < adapter->NumberOfPorts; i++)
    {
        // Ask the HVL to active the specific port. This is
        // a synchronous private API call into the HVL
        HelperPortDelegateExclusiveAccess(HelperPort, adapter->PortList[i]);

        // Ask the port to pause
        ndisStatus = Port11PausePort(adapter->PortList[i], IsInternal);
        
        MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
    }

    // Reobtain active context
    HelperPortDelegateExclusiveAccess(HelperPort, HELPPORT_GET_MP_PORT(HelperPort));

    //
    // Wait for the port list refcount in the adapter to go down to 0
    //
    MP_WAIT_FOR_PORTLIST_REFCOUNT(adapter);

    // Set the paused flag on us
    MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE);
    MP_SET_PORT_STATUS(HELPPORT_GET_MP_PORT(HelperPort), MP_PORT_PAUSED);
    MP_RELEASE_ADAPTER_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE);

    //
    // Let the VNic know we have paused
    //
    ndisStatus = VNic11Pause(HELPPORT_GET_VNIC(HelperPort));
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);

    //
    // Pause the hardware last
    //
    ndisStatus = Hw11Pause(adapter->Hw);
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);

    // stop timed context switches
    Hvl11BlockTimedCtxS(adapter->Hvl);

    // Set paused & clear the pausing flag
    MP_ACQUIRE_ADAPTER_LOCK(adapter, FALSE);
    MP_SET_ADAPTER_STATUS(adapter, MP_ADAPTER_PAUSED);
    MP_CLEAR_ADAPTER_STATUS(adapter, MP_ADAPTER_PAUSING);
    MP_RELEASE_ADAPTER_LOCK(adapter, FALSE);

    MpExit;
//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("<== Helper Port Pause\n"));        

    return ndisStatus;
}

NDIS_STATUS
HelperPortPauseMPExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_MINIPORT_PAUSE_PARAMETERS pauseParameters = (PMP_MINIPORT_PAUSE_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    
    ndisStatus = HelperPortPauseMiniport(helperPort, 
                        (pauseParameters->NdisParameters == NULL)? TRUE : FALSE, 
                        pauseParameters->NdisParameters
                        );

    NdisSetEvent(&pauseParameters->CompleteEvent);

    return ndisStatus;
}

NDIS_STATUS 
HelperPortHandleMiniportPause(
    _In_  PMP_PORT                Port,
    _In_opt_  PNDIS_MINIPORT_PAUSE_PARAMETERS     MiniportPauseParameters
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_MINIPORT_PAUSE_PARAMETERS    pauseParameters;

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Pause Started\n"));
    
    // Populate the parameters to pass to the handler
    NdisZeroMemory(&pauseParameters, sizeof(MP_MINIPORT_PAUSE_PARAMETERS));
    pauseParameters.NdisParameters = MiniportPauseParameters;
    NdisInitializeEvent(&pauseParameters.CompleteEvent);
    NdisResetEvent(&pauseParameters.CompleteEvent);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    // get exclusive access
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort,
                     HelperPortPauseMPExAccessCallback, 
                     &pauseParameters,
                     TRUE
                     );

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortPauseMPExAccessCallback(Port, &pauseParameters);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        // Will be processed asynchronously
        ndisStatus = NDIS_STATUS_SUCCESS;
    }

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the pause to complete
        NdisWaitEvent(&pauseParameters.CompleteEvent, 0);
            
        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);
    }
    else    // Exclusive access request failed
    {
        // Update the exclusive release access for ref debugging
        NdisInterlockedIncrement(&helperPort->Tracking_ExclusiveAccessReleaseCount);    
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Miniport Pause failed with status 0x%08x\n", ndisStatus));        
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Pause Finished\n"));
    
    return ndisStatus;
}


NDIS_STATUS 
HelperPortRestartMiniport(
    _In_        PMP_HELPER_PORT                     HelperPort,
    _In_        BOOLEAN                             IsInternal,
    _In_opt_    PNDIS_MINIPORT_RESTART_PARAMETERS   MiniportRestartParameters
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PADAPTER                    adapter = HelperPort->ParentPort->Adapter;
    ULONG                       i;

    MpEntry;
//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("==> Helper Port Restart\n"));        

    UNREFERENCED_PARAMETER(MiniportRestartParameters);

    HELPPORT_GET_MP_PORT(HelperPort)->PauseCount--;
    if (HELPPORT_GET_MP_PORT(HelperPort)->PauseCount > 0)
    {
        // We have multiple pauses pending. We wont restart
        // yet

        MpExit;
//        MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("<== Helper Port Restart\n"));        

        // We still return success to the restart request
        return NDIS_STATUS_SUCCESS;
    }

    //
    // Restart the hardware first
    //
    Hw11Restart(adapter->Hw);

    //
    // Let the VNic know we have restarted, so that ports can
    // start using us as soon as we restart them
    //
    ndisStatus = VNic11Restart(HELPPORT_GET_VNIC(HelperPort));
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);

    // Clear the paused flag on us
    MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE);
    MP_CLEAR_PORT_STATUS(HELPPORT_GET_MP_PORT(HelperPort), MP_PORT_PAUSED);
    MP_RELEASE_ADAPTER_LOCK(HELPPORT_GET_MP_PORT(HelperPort), FALSE);
    
    // Now restart all the other port
    for (i = 0; i < adapter->NumberOfPorts; i++)
    {
        // Ask the HVL to active the specific port. This is
        // a synchronous private API call into the HVL
        Hvl11ActivatePort(adapter->Hvl, PORT_GET_VNIC(adapter->PortList[i]));

        // Ask the port to restart. We dont active each individual
        // context yet        
        ndisStatus = Port11RestartPort(adapter->PortList[i], IsInternal);
        
        MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
    }

    // Reobtain active context
    Hvl11ActivatePort(adapter->Hvl, HELPPORT_GET_VNIC(HelperPort));

    // re-enable timed context switches
    Hvl11UnblockTimedCtxS(adapter->Hvl);

    // Clear the paused flag on the adapter
    MP_ACQUIRE_ADAPTER_LOCK(adapter, FALSE);
    MP_CLEAR_ADAPTER_STATUS(adapter, MP_ADAPTER_PAUSED);
    MP_RELEASE_ADAPTER_LOCK(adapter, FALSE);

//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("<== Helper Port Restart\n"));        

    MpExit;
    
    return ndisStatus;
}


NDIS_STATUS
HelperPortRestartMPExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_MINIPORT_RESTART_PARAMETERS restartParameters = (PMP_MINIPORT_RESTART_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    
    ndisStatus = HelperPortRestartMiniport(helperPort, 
                        (restartParameters->NdisParameters == NULL)? TRUE : FALSE, 
                        restartParameters->NdisParameters
                        );

    NdisSetEvent(&restartParameters->CompleteEvent);

    return ndisStatus;
}

NDIS_STATUS 
HelperPortHandleMiniportRestart(
    _In_  PMP_PORT                Port,
    _In_opt_  PNDIS_MINIPORT_RESTART_PARAMETERS   MiniportRestartParameters
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_MINIPORT_RESTART_PARAMETERS    restartParameters;

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Restart Started\n"));

    // Populate the parameters to pass to the handler
    NdisZeroMemory(&restartParameters, sizeof(MP_MINIPORT_RESTART_PARAMETERS));
    restartParameters.NdisParameters = MiniportRestartParameters;
    NdisInitializeEvent(&restartParameters.CompleteEvent);
    NdisResetEvent(&restartParameters.CompleteEvent);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    // get exclusive access
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
                     HelperPortRestartMPExAccessCallback, 
                     &restartParameters,
                     TRUE
                     );

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortRestartMPExAccessCallback(Port, &restartParameters);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        // Will be processed asynchronously
        ndisStatus = NDIS_STATUS_SUCCESS;
    }

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the restart to complete
        NdisWaitEvent(&restartParameters.CompleteEvent, 0);
        
        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);
    }
    else    // Exclusive access request failed
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Miniport Restart failed with status 0x%08x\n", ndisStatus));        
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Restart Finished\n"));

    return ndisStatus;    
}


NDIS_STATUS 
HelperPortPausePort(
    _In_  PMP_HELPER_PORT         HelperPort,
    _In_  PMP_PORT                PortToPause    
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;

    MpEntry;

    // Ask the HVL to active the specific port. This is
    // a synchronous private API call into the HVL
    HelperPortDelegateExclusiveAccess(HelperPort, PortToPause);

    // Ask the port to pause
    ndisStatus = Port11PausePort(PortToPause, TRUE);
    
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);

    // Reobtain active context
    HelperPortDelegateExclusiveAccess(HelperPort, HELPPORT_GET_MP_PORT(HelperPort));
    
    MpExit;

    return ndisStatus;
}


NDIS_STATUS
HelperPortPausePortExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;    
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_PORT_PAUSE_PARAMETERS   pauseParameters = (PMP_PORT_PAUSE_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    
    ndisStatus = HelperPortPausePort(MP_GET_HELPPORT(Port), pauseParameters->PortToPause);

    NdisSetEvent(&pauseParameters->CompleteEvent);

    return ndisStatus;
}


NDIS_STATUS 
HelperPortHandlePortPause(
    _In_  PMP_PORT                Port,
    _In_  PMP_PORT                PortToPause
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_PORT_PAUSE_PARAMETERS    pauseParameters;

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Port Pause Started\n"));

    // Populate the parameters to pass to the handler
    NdisZeroMemory(&pauseParameters, sizeof(MP_PORT_PAUSE_PARAMETERS));
    pauseParameters.PortToPause = PortToPause;
    NdisInitializeEvent(&pauseParameters.CompleteEvent);
    NdisResetEvent(&pauseParameters.CompleteEvent);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    // get exclusive access
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
        HelperPortPausePortExAccessCallback, 
        &pauseParameters,
        TRUE
        );
    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortPausePortExAccessCallback(Port, &pauseParameters);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        // Will be processed asynchronously
        ndisStatus = NDIS_STATUS_SUCCESS;
    }

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the pause to complete
        NdisWaitEvent(&pauseParameters.CompleteEvent, 0);

        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);
    }
    else    // Exclusive access request failed
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Port Pause failed with status 0x%08x\n", ndisStatus));        
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Port Pause Finished\n"));

    return ndisStatus;    
}



NDIS_STATUS 
HelperPortRestartPort(
    _In_  PMP_HELPER_PORT         HelperPort,
    _In_  PMP_PORT                PortToRestart
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(HelperPort);
    MpEntry;

    // Ask the port to restart. We dont active the
    // context yet        
    ndisStatus = Port11RestartPort(PortToRestart, TRUE);
    
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
    
    MpExit;
    
    return ndisStatus;
}

NDIS_STATUS
HelperPortRestartPortExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;    
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_PORT_RESTART_PARAMETERS restartParameters = (PMP_PORT_RESTART_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    
    ndisStatus = HelperPortRestartPort(MP_GET_HELPPORT(Port), restartParameters->PortToRestart);

    NdisSetEvent(&restartParameters->CompleteEvent);

    return ndisStatus;
}

NDIS_STATUS 
HelperPortHandlePortRestart(
    _In_  PMP_PORT                Port,
    _In_  PMP_PORT                PortToRestart
    )
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_PORT_RESTART_PARAMETERS  restartParameters;
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Port Restart Started\n"));

    // Populate the parameters to pass to the handler
    NdisZeroMemory(&restartParameters, sizeof(MP_PORT_RESTART_PARAMETERS));
    restartParameters.PortToRestart = PortToRestart;
    NdisInitializeEvent(&restartParameters.CompleteEvent);
    NdisResetEvent(&restartParameters.CompleteEvent);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    // get exclusive access
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
        HelperPortRestartPortExAccessCallback, 
        &restartParameters,
        TRUE
        );
    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortRestartPortExAccessCallback(Port, &restartParameters);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        // Will be processed asynchronously
        ndisStatus = NDIS_STATUS_SUCCESS;
    }

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the restart to complete
        NdisWaitEvent(&restartParameters.CompleteEvent, 0);

        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);
    }
    else    // Exclusive access request failed
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Port Restart failed with status 0x%08x\n", ndisStatus));
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Port Restart Finished\n"));

    return ndisStatus;    
}


NDIS_STATUS
HelperPortPortTerminateExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_TERMINATE_PORT_PARAMETERS terminateParams = (PMP_TERMINATE_PORT_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);

    // Ask the HVL to active the specific port. This is
    // a synchronous private API call into the HVL
    HelperPortDelegateExclusiveAccess(helperPort, terminateParams->PortToTerminate);

    // Invoke port terminate
    Port11TerminatePort(terminateParams->PortToTerminate, TRUE);

    // Reobtain active context
    HelperPortDelegateExclusiveAccess(helperPort, HELPPORT_GET_MP_PORT(helperPort));

    NdisSetEvent(&terminateParams->CompleteEvent);

    return NDIS_STATUS_SUCCESS;
}


VOID
HelperPortHandlePortTerminate(
    _In_ PMP_PORT                 Port,
    _In_ PMP_PORT                 PortToTerminate
    )
{
    NDIS_STATUS                 ndisStatus;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_TERMINATE_PORT_PARAMETERS    terminateParams;
    
    NdisZeroMemory(&terminateParams, sizeof(MP_TERMINATE_PORT_PARAMETERS));
    terminateParams.PortToTerminate = PortToTerminate;
    NdisInitializeEvent(&terminateParams.CompleteEvent);
    NdisResetEvent(&terminateParams.CompleteEvent);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it. Note that
    // this is acquired after we call HwNdisReset
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));        
        
    // Now queue the exclusive access operation
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
        HelperPortPortTerminateExAccessCallback, 
        &terminateParams,
        TRUE
        );
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS || ndisStatus == NDIS_STATUS_PENDING);

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortPortTerminateExAccessCallback(Port, &terminateParams);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        ndisStatus = NDIS_STATUS_SUCCESS;
    }

    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the terminate to complete
        NdisWaitEvent(&terminateParams.CompleteEvent, 0);

        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);    
    }
    else    // Exclusive access request failed
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Port Terminate failed with status 0x%08x\n", ndisStatus));
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));
    
}


NDIS_STATUS 
HelperPortNdisReset(
    _In_  PMP_HELPER_PORT         HelperPort,
    _In_  PBOOLEAN                AddressingReset
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS, globalStatus = NDIS_STATUS_SUCCESS;
    PADAPTER                    adapter = HelperPort->ParentPort->Adapter;
    ULONG                       i;

    MpEntry;

    // Even if reset fails anywhere, we complete the full process
    
//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("==> Helper Port Reset\n"));        

    for (i = 0; i < adapter->NumberOfPorts; i++)
    {
        // Ask the HVL to active the specific port. This is
        // a synchronous private API call into the HVL
        HelperPortDelegateExclusiveAccess(HelperPort, adapter->PortList[i]);

        // Notify the port of reset start
        ndisStatus = Port11NdisResetStart(adapter->PortList[i]);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            globalStatus = ndisStatus;
        }
    }

    // Reobtain active context
    HelperPortDelegateExclusiveAccess(HelperPort, HELPPORT_GET_MP_PORT(HelperPort));

    //
    // Reset the hardware to cleanup stuff
    //
    Hw11NdisResetStep2(adapter->Hw);

    //
    // Restore HW state
    //
    ndisStatus = Hw11NdisResetStep3(adapter->Hw, AddressingReset);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        globalStatus = ndisStatus;
    }

    //
    // Now "un-reset" all the ports
    //
    for (i = 0; i < adapter->NumberOfPorts; i++)
    {
        // Notify the port of reset finish
        ndisStatus = Port11NdisResetEnd(adapter->PortList[i]);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            globalStatus = ndisStatus;
        }
    }
    
    MpExit;
//    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("<== Helper Port Reset\n"));        

    return globalStatus;
}

NDIS_STATUS
HelperPortResetExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_NDIS_RESET_PARAMETERS   resetParams = (PMP_NDIS_RESET_PARAMETERS) Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    
    resetParams->ResetStatus = HelperPortNdisReset(helperPort, resetParams->AddressingReset);

    NdisSetEvent(&resetParams->CompleteEvent);

    return NDIS_STATUS_SUCCESS;
}

NDIS_STATUS
HelperPortHandleMiniportReset(
    _In_  PMP_PORT                Port,
    _Inout_ PBOOLEAN              AddressingReset
    )
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PADAPTER                    adapter = Port->Adapter;
    MP_NDIS_RESET_PARAMETERS    resetParams;
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Reset Started\n"));
    
    NdisZeroMemory(&resetParams, sizeof(MP_NDIS_RESET_PARAMETERS));
    resetParams.AddressingReset = AddressingReset;
    NdisInitializeEvent(&resetParams.CompleteEvent);
    NdisResetEvent(&resetParams.CompleteEvent);
    
    // The first thing we do on a miniport reset is reset the
    // hardware. This would ensure that the hardware is in a good state
    // and hvl, etc wont get stuck waiting for some hardware operation
    // before giving the reset exclusive access    
    Hw11NdisResetStep1(adapter->Hw);

    // The lock is acquired here since the VNIC expects us to have only
    // one PNP operation requesting exclusive access from it. Note that
    // this is acquired after we call HwNdisReset
    PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));        
    
    // Now queue the exclusive access operation
    ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
        HelperPortResetExAccessCallback, 
        &resetParams,
        TRUE
        );
    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // the function completed synchronously, call the callback ourselves
        HelperPortResetExAccessCallback(Port, &resetParams);
    }
    else if (ndisStatus == NDIS_STATUS_PENDING)
    {
        // Will be processed asynchronously
        ndisStatus = NDIS_STATUS_SUCCESS;
    }


    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // wait for the reset to complete
        NdisWaitEvent(&resetParams.CompleteEvent, 0);

        // release exclusive access
        HelperPortReleaseExclusiveAccess(helperPort);
    }
    else    // Exclusive access request failed
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Miniport Reset failed with status 0x%08x\n", ndisStatus));        
    }

    // Exclusive access is released before this is released
    PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

    MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Miniport Reset Finished\n"));
    
    return resetParams.ResetStatus;

}

_Success_(return == NDIS_STATUS_SUCCESS)
NDIS_STATUS
HelperPortAllocateNdisPort(
    _In_  PMP_PORT                HelperPort,
    _Out_ PNDIS_PORT_NUMBER       AllocatedPortNumber
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NDIS_PORT_CHARACTERISTICS   portChar;

    // Call NDIS to allocate the port
    NdisZeroMemory(&portChar, sizeof(NDIS_PORT_CHARACTERISTICS));

    MP_ASSIGN_NDIS_OBJECT_HEADER(portChar.Header, NDIS_OBJECT_TYPE_DEFAULT,
        NDIS_PORT_CHARACTERISTICS_REVISION_1, sizeof(NDIS_PORT_CHARACTERISTICS));

    portChar.Flags = NDIS_PORT_CHAR_USE_DEFAULT_AUTH_SETTINGS;
    portChar.Type = NdisPortTypeUndefined;
    portChar.MediaConnectState = MediaConnectStateConnected;
    portChar.XmitLinkSpeed = NDIS_LINK_SPEED_UNKNOWN;
    portChar.RcvLinkSpeed = NDIS_LINK_SPEED_UNKNOWN;
    portChar.Direction = NET_IF_DIRECTION_SENDRECEIVE;
    portChar.SendControlState = NdisPortControlStateUnknown;
    portChar.RcvControlState = NdisPortControlStateUnknown;
    portChar.SendAuthorizationState = NdisPortControlStateUncontrolled; // Ignored
    portChar.RcvAuthorizationState = NdisPortControlStateUncontrolled; // Ignored
               
    ndisStatus = NdisMAllocatePort(HelperPort->MiniportAdapterHandle, &portChar);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate NDIS port. Status = 0x%08x\n",
            ndisStatus));
    }
    else
    {
        MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Associated Port Number %d with allocated port\n", 
                    portChar.PortNumber));
                    
        // Return the NDIS port number that has been allocated to this port
        *AllocatedPortNumber = portChar.PortNumber;
    }
    
    return ndisStatus;
}

VOID
HelperPortFreeNdisPort(
    _In_  PMP_PORT                HelperPort,
    _In_  NDIS_PORT_NUMBER        PortNumberToFree
    )
{
    NDIS_STATUS                 ndisStatus;

    // Free the NDIS port
    ndisStatus = NdisMFreePort(HelperPort->MiniportAdapterHandle, PortNumberToFree);
    MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
    _Analysis_assume_( ndisStatus == NDIS_STATUS_SUCCESS );

}

NDIS_STATUS
HelperPortActivateNdisPort(
    _In_  PMP_PORT                HelperPort,
    _In_  NDIS_PORT_NUMBER        PortNumberToActivate
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NET_PNP_EVENT_NOTIFICATION  netPnpEventNotification;
    NDIS_PORT                   ndisPort;
    PNDIS_PORT_CHARACTERISTICS  portChar;

    NdisZeroMemory(&netPnpEventNotification, sizeof(NET_PNP_EVENT_NOTIFICATION));
    NdisZeroMemory(&ndisPort, sizeof(NDIS_PORT));

    MP_ASSIGN_NDIS_OBJECT_HEADER(netPnpEventNotification.Header, NDIS_OBJECT_TYPE_DEFAULT,
        NET_PNP_EVENT_NOTIFICATION_REVISION_1, sizeof(NET_PNP_EVENT_NOTIFICATION));

    netPnpEventNotification.NetPnPEvent.NetEvent = NetEventPortActivation;

    // Refill the characteristics structure for the port
    portChar = &(ndisPort.PortCharacteristics);
    MP_ASSIGN_NDIS_OBJECT_HEADER(portChar->Header, NDIS_OBJECT_TYPE_DEFAULT,
        NDIS_PORT_CHARACTERISTICS_REVISION_1, sizeof(NDIS_PORT_CHARACTERISTICS));

    portChar->Flags = NDIS_PORT_CHAR_USE_DEFAULT_AUTH_SETTINGS;
    portChar->Type = NdisPortTypeUndefined;
    portChar->MediaConnectState = MediaConnectStateConnected;
    portChar->XmitLinkSpeed = NDIS_LINK_SPEED_UNKNOWN;
    portChar->RcvLinkSpeed = NDIS_LINK_SPEED_UNKNOWN;
    portChar->Direction = NET_IF_DIRECTION_SENDRECEIVE;
    portChar->SendControlState = NdisPortControlStateUnknown;
    portChar->RcvControlState = NdisPortControlStateUnknown;
    portChar->SendAuthorizationState = NdisPortControlStateUncontrolled; // Ignored
    portChar->RcvAuthorizationState = NdisPortControlStateUncontrolled; // Ignored
    portChar->PortNumber = PortNumberToActivate;
    
    // Single port is being activated
    ndisPort.Next = NULL;

    // We need to save a pointer to the NDIS_PORT in the NetPnPEvent::Buffer field
    netPnpEventNotification.NetPnPEvent.Buffer = (PVOID)&ndisPort;
    netPnpEventNotification.NetPnPEvent.BufferLength = sizeof(NDIS_PORT);

    ndisStatus = NdisMNetPnPEvent(HelperPort->MiniportAdapterHandle, &netPnpEventNotification);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to activate NDIS port %d. Status = 0x%08x\n", 
            PortNumberToActivate, ndisStatus));
    }
    else
    {
        MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Activated Port Number %d\n", PortNumberToActivate));
    } 

    return ndisStatus;
}

VOID
HelperPortDeactivateNdisPort(
    _In_  PMP_PORT                HelperPort,
    _In_  NDIS_PORT_NUMBER        PortNumberToDeactivate
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NET_PNP_EVENT_NOTIFICATION  netPnpEventNotification;
    NDIS_PORT_NUMBER            portNumberArray[1];

    NdisZeroMemory(&netPnpEventNotification, sizeof(NET_PNP_EVENT_NOTIFICATION));

    MP_ASSIGN_NDIS_OBJECT_HEADER(netPnpEventNotification.Header, NDIS_OBJECT_TYPE_DEFAULT,
        NET_PNP_EVENT_NOTIFICATION_REVISION_1, sizeof(NET_PNP_EVENT_NOTIFICATION));

    netPnpEventNotification.NetPnPEvent.NetEvent = NetEventPortDeactivation;

    // We need to save a pointer to the NDIS_PORT_NUMBER in the NetPnPEvent::Buffer field
    portNumberArray[0] = PortNumberToDeactivate;            
    netPnpEventNotification.NetPnPEvent.Buffer = (PVOID)portNumberArray;
    netPnpEventNotification.NetPnPEvent.BufferLength = sizeof(NDIS_PORT_NUMBER);

    ndisStatus = NdisMNetPnPEvent(HelperPort->MiniportAdapterHandle, &netPnpEventNotification);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to deactivate NDIS port %d. Status = 0x%08x\n", 
            PortNumberToDeactivate, ndisStatus));
    }
    else
    {
        MpTrace(COMP_INIT_PNP, DBG_NORMAL, ("Deactivated Port Number %d\n", PortNumberToDeactivate));
    }        
}


NDIS_STATUS
HelperPortCreateMacHandler(
    _In_ PMP_PORT                 Port,
    _In_ PNDIS_OID_REQUEST        OidRequest
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PMP_PORT                    newPort = NULL;
    BOOLEAN                     portInit = FALSE, portInserted = FALSE;
    BOOLEAN                     miniportPaused = FALSE;
    BOOLEAN                     ndisPortAllocated = FALSE, ndisPortActivated = FALSE;
    PDOT11_MAC_INFO             dot11MacInfo = NULL;
    PDOT11_MAC_ADDRESS          macAddr = NULL;
    NDIS_PORT_NUMBER            portNumber = DEFAULT_NDIS_PORT_NUMBER;
    
    do
    {
        OidRequest->DATA.METHOD_INFORMATION.BytesWritten = 0;
        OidRequest->DATA.METHOD_INFORMATION.BytesRead = 0;
        OidRequest->DATA.METHOD_INFORMATION.BytesNeeded = 0;


        /*
            Pause the miniport before we modify the adapter's port list. 
            This is an expensive way to achieve this but it is simple to implement
            */
    
        ndisStatus = HelperPortHandleMiniportPause(Port, NULL);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortHandleMiniportPause failed 0x%x\n", ndisStatus));
            break;
        }        
        miniportPaused = TRUE;

        // By default, our ports are EXTSTA_PORTs only. 
        ndisStatus = Port11AllocatePort(Port->Adapter, 
                        EXTSTA_PORT, 
                        &newPort
                        );
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to allocate a new port\n"));
            break;
        }

        //
        // We will allocate an NDIS port corresponding to this port
        //
        ndisStatus = HelperPortAllocateNdisPort(Port, &portNumber);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        newPort->PortNumber = portNumber;
        ndisPortAllocated = TRUE;

        // Initialize the port
        ndisStatus = Port11InitializePort(newPort, 
                        Port->Adapter->Hvl, 
                        Port->Adapter->PortRegInfo
                        );
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        portInit = TRUE;
        
        // Add it to the adapter list
        Port->Adapter->PortList[Port->Adapter->NumberOfPorts] = newPort;
        Port->Adapter->NumberOfPorts++;
        portInserted = TRUE;

        /*
            Restart so that normal operation may continue
            */
        miniportPaused = FALSE; // We clear this before we attempt to restart
        ndisStatus = HelperPortHandleMiniportRestart(Port, NULL);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortHandleMiniportRestart failed 0x%x", ndisStatus));
            break;
        } 
        
        /*
            Done creating the new virtual adapter
            */
        dot11MacInfo = (PDOT11_MAC_INFO)OidRequest->DATA.METHOD_INFORMATION.InformationBuffer;
        dot11MacInfo->uNdisPortNumber = newPort->PortNumber;
        macAddr = VNic11QueryMACAddress(PORT_GET_VNIC(newPort));
        
        NdisMoveMemory(dot11MacInfo->MacAddr, macAddr, sizeof(DOT11_MAC_ADDRESS));
        
        OidRequest->DATA.METHOD_INFORMATION.BytesWritten = sizeof(DOT11_MAC_INFO);

        MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("Created a new Port \n" ));
    } while (FALSE);
    
    if (ndisStatus != NDIS_STATUS_SUCCESS)
    {
        if (newPort != NULL)
        {
            if (portInserted)
            {
                Port11RemovePortFromAdapterList(newPort);
            }
            
            if (portInit)
            {
                HelperPortHandlePortTerminate(Port, newPort);
            }
            
            Port11FreePort(newPort, TRUE);            
        }

        if (miniportPaused)
        {
            if (HelperPortHandleMiniportRestart(Port, NULL) != NDIS_STATUS_SUCCESS)
            {
                MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortHandleMiniportRestart failed"));
            }
        }
    }

    //
    // Complete the OID
    //
    Port11CompletePendingOidRequest(Port, ndisStatus);

    //
    // We can now activate/deactivate the port. We cannot do this while we are processing
    // the OID, else the OS would deadlock. 
    //
    if (ndisStatus == NDIS_STATUS_SUCCESS)
    {
        // If this port has been allocated with NDIS, activate it. This notification
        // goes upto the OS and it would handle the request
        ndisStatus = HelperPortActivateNdisPort(Port, portNumber);
        MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
    }
    else
    {
        if (IS_ALLOCATED_PORT_NUMBER(portNumber))
        {
            // If activated, deactivate the NDIS port
            if (ndisPortActivated)
            {
                HelperPortDeactivateNdisPort(Port, portNumber);
            }

            // If allocated free the NDIS port
            if (ndisPortAllocated)
            {
                HelperPortFreeNdisPort(Port, portNumber);
            }
        }
    }
    
    return ndisStatus;
}

NDIS_STATUS
HelperPortCreateMac(
    _In_ PMP_PORT                 Port,
    _In_ PVOID                    NdisOidRequest,
    _Out_ BOOLEAN                 *pfOidCompleted
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PNDIS_OID_REQUEST           oidRequest = (PNDIS_OID_REQUEST)NdisOidRequest;

    *pfOidCompleted = FALSE;
    
    do
    {
        oidRequest->DATA.METHOD_INFORMATION.BytesWritten = 0;
        oidRequest->DATA.METHOD_INFORMATION.BytesRead = 0;
        oidRequest->DATA.METHOD_INFORMATION.BytesNeeded = 0;

        if (oidRequest->RequestType != NdisRequestMethod)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Invalid request type %d for OID_DOT11_CREATE_MAC\n", 
                oidRequest->RequestType));
            ndisStatus = NDIS_STATUS_NOT_SUPPORTED;
            break;
        }
    
        if (oidRequest->DATA.METHOD_INFORMATION.OutputBufferLength < sizeof(DOT11_MAC_INFO))
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("The buffer being passed into OID_DOT11_CREATE_MAC is too small(%d)\n", 
                oidRequest->DATA.METHOD_INFORMATION.OutputBufferLength));
            oidRequest->DATA.METHOD_INFORMATION.BytesNeeded = sizeof(DOT11_MAC_INFO);
            ndisStatus = NDIS_STATUS_INVALID_LENGTH;
            break;
        }

        //
        // Since OID calls are serialized, we do not expect the NumberOfPorts to change
        // while we are checking the following until this OID is completed. So we do not need 
        // to protect the NumberOfPorts in any way
        //
        if (Port->Adapter->NumberOfPorts >= MP_MAX_NUMBER_OF_PORT)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("Number of existing ports exceed max supported. Failing new port creation\n"));            
            ndisStatus = NDIS_STATUS_NOT_SUPPORTED;
            break;
        }

        ndisStatus = HelperPortCreateMacHandler(Port, oidRequest);
        // regardless of the return result, HelperPortCreateMacHandler always completes the Oid
        *pfOidCompleted = TRUE;
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortCreateMacHandler failed. Status = 0x%08x\n", ndisStatus));
            break;            
        }
    } while (FALSE);

    return ndisStatus;
}

NDIS_STATUS
HelperPortDeleteMacHandler(
    _In_ PMP_PORT                 Port,
    _In_ PVOID                    NdisOidRequest
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PNDIS_OID_REQUEST           oidRequest = (PNDIS_OID_REQUEST)NdisOidRequest;
    PDOT11_MAC_INFO             dot11MacInfo = NULL;
    PMP_PORT                    destinationPort = NULL;
    NDIS_PORT_NUMBER            portNumber;
    BOOLEAN                     destroyPortNumber = FALSE;
    
    do
    {
        dot11MacInfo = (PDOT11_MAC_INFO)oidRequest->DATA.SET_INFORMATION.InformationBuffer;
        portNumber = dot11MacInfo->uNdisPortNumber;
        
        //
        // First we would need to translate from the NDIS_PORT_NUMBER
        // to our port structure. This is done by walking the PortList
        // Since OID calls are serialized, we do not expect the Portlist to change
        // while we are trying to find the port or for the port to get deleted
        // until this OID is completed. So we do not need to protect the Port/PortList
        // in any way
        //
        destinationPort = Port11TranslatePortNumberToPort(
                            Port->Adapter, 
                            portNumber
                            );
        if (destinationPort == NULL)
        {
            MpTrace(COMP_OID, DBG_SERIOUS, ("Unable to find Port corresponding to PortNumber %d\n", 
                dot11MacInfo->uNdisPortNumber));

            ndisStatus = NDIS_STATUS_INVALID_PORT;
            break;
        }

        if (IS_ALLOCATED_PORT_NUMBER(portNumber))
        {
            // This port has been allocate with NDIS. When we are done, delete the
            // port
            destroyPortNumber = TRUE;
        }

        /*
            Pause the miniport before we modify the adapter's port list. 
            This is an expensive way to achieve this but it is simple to implement
            */
    
        ndisStatus = HelperPortHandleMiniportPause(Port, NULL);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortHandleMiniportPause failed 0x%x\n", ndisStatus));
            break;
        }        

        // remove it from the adapter list
        Port11RemovePortFromAdapterList(destinationPort);

        // now free up this port
        HelperPortHandlePortTerminate(Port, destinationPort);
        Port11FreePort(destinationPort, TRUE);

        /*
            Restart so that normal operation may continue
            */
        ndisStatus = HelperPortHandleMiniportRestart(Port, NULL);
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortHandleMiniportRestart failed 0x%x", ndisStatus));
            break;
        }        

        /*
            Done deleting the mac state
            */
        oidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(DOT11_MAC_INFO);

        MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("Deleted the Mac with port number %d", dot11MacInfo->uNdisPortNumber));
    } while (FALSE);

    //
    // Complete the OID
    //
    Port11CompletePendingOidRequest(Port, ndisStatus);

    //
    // We can now deactivate the port. We cannot do this while we are processing
    // the OID, else the OS would deadlock. 
    //
    if ((ndisStatus == NDIS_STATUS_SUCCESS) && (destroyPortNumber == TRUE))
    {
        // Deactivate & free the NDIS_PORT
        HelperPortDeactivateNdisPort(Port, portNumber);
        HelperPortFreeNdisPort(Port, portNumber);
    }
    
    return ndisStatus;
}


NDIS_STATUS
HelperPortDeleteMac(
    _In_ PMP_PORT                 Port,
    _In_ PNDIS_OID_REQUEST        OidRequest,
    _Out_ BOOLEAN                 *pfOidCompleted
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PDOT11_MAC_INFO             dot11MacInfo = NULL;

    *pfOidCompleted = FALSE;
    
    do
    {
        OidRequest->DATA.SET_INFORMATION.BytesRead = 0;
        OidRequest->DATA.SET_INFORMATION.BytesNeeded = 0;

        if (OidRequest->RequestType != NdisRequestSetInformation)
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Invalid request type %d for OID_DOT11_DELETE_MAC\n", 
                OidRequest->RequestType));
            ndisStatus = NDIS_STATUS_NOT_SUPPORTED;
            break;
        }

        if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength < sizeof(DOT11_MAC_INFO))
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("The buffer being passed into OID_DOT11_DELETE_MAC is too small(%d)", 
                OidRequest->DATA.SET_INFORMATION.InformationBufferLength));
            OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(DOT11_MAC_INFO);
            ndisStatus = NDIS_STATUS_INVALID_LENGTH;
            break;
        }

        dot11MacInfo = (PDOT11_MAC_INFO)OidRequest->DATA.SET_INFORMATION.InformationBuffer;

        if (dot11MacInfo->uNdisPortNumber > MP_MAX_NUMBER_OF_PORT ||
          dot11MacInfo->uNdisPortNumber == DEFAULT_NDIS_PORT_NUMBER ||
          dot11MacInfo->uNdisPortNumber == HELPER_PORT_PORT_NUMBER)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("The port number (%d) being passed in is invalid", dot11MacInfo->uNdisPortNumber));
            ndisStatus = NDIS_STATUS_INVALID_DATA;
            break;
        }

        ndisStatus = HelperPortDeleteMacHandler(Port, OidRequest);

        // regardless of the return result, HelperPortCreateMacHandler always completes the Oid
        *pfOidCompleted = TRUE;
        
        if (ndisStatus != NDIS_STATUS_SUCCESS)
        {
            MpTrace (COMP_INIT_PNP, DBG_SERIOUS, ("HelperPortDeleteMacHandler failed. Status = 0x%08x\n", ndisStatus));
            break;            
        }
    }while (FALSE);

    return ndisStatus;
}



VOID
HelperPortHandleMacCleanup(
    _In_ PMP_PORT                 HelperPort
    )
{
    PMP_PORT                    destinationPort = NULL;
    NDIS_PORT_NUMBER            portNumber;
    BOOLEAN                     destroyPortNumber = FALSE;

    // The only thing we do here is delete any port that was created on an OID
    // but the OS did not delete.

    // Port at index 0 is auto created. All others are manually created
    while (HelperPort->Adapter->NumberOfPorts > 1)
    {
        // The one we want to delete is always at index 1 since
        // Port11RemovePortFromAdapterList moves ports around
        destinationPort = HelperPort->Adapter->PortList[1];
        portNumber = destinationPort->PortNumber;

        destroyPortNumber = FALSE;
        if (IS_ALLOCATED_PORT_NUMBER(portNumber))
        {
            // This port has been allocate with NDIS. When we are done, delete the
            // port
            destroyPortNumber = TRUE;
        }

        // remove it from the adapter list. This also decrements
        // Adapter->NumberOfPorts
        Port11RemovePortFromAdapterList(destinationPort);

        // now free up this port
        HelperPortHandlePortTerminate(HelperPort, destinationPort);
        Port11FreePort(destinationPort, TRUE);

        if (destroyPortNumber == TRUE)
        {
            // Deactivate & free the NDIS_PORT
            HelperPortDeactivateNdisPort(HelperPort, portNumber);
            HelperPortFreeNdisPort(HelperPort, portNumber);
        }

    }

}


NDIS_STATUS
HelperPortHandleQueryPower(
    _In_ PMP_PORT                 Port,
    _Inout_ PVOID                InformationBuffer,
    _In_ ULONG                    InformationBufferLength,
    _Inout_ PULONG               BytesWritten,
    _Inout_ PULONG               BytesNeeded
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NDIS_DEVICE_POWER_STATE     devicePowerState;

    do
    {
        *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
        if (InformationBufferLength < *BytesNeeded)
        {
            //
            // Too little data. Bail out.
            //
            MpTrace(COMP_POWER, DBG_SERIOUS,  ("Bad length received for the QUERY_POWER request\n"));
            ndisStatus = NDIS_STATUS_INVALID_LENGTH;
            break;
        }
        
        NdisMoveMemory(&devicePowerState, InformationBuffer, sizeof(NDIS_DEVICE_POWER_STATE));
        
        if (devicePowerState <= NdisDeviceStateUnspecified || devicePowerState >= NdisDeviceStateMaximum)
        {
            //
            // An invalid device state has been specified. Bail out.
            //
            MpTrace(COMP_POWER, DBG_SERIOUS,  ("Invalid data received in QUERY_POWER request\n"));
            ndisStatus = NDIS_STATUS_INVALID_DATA;
            break;
        }

        *BytesWritten = 0;

        // This request gets forwarded to the HW
        ndisStatus = Hw11CanTransitionPower(Port->Adapter->Hw, devicePowerState);
    } while(FALSE);

    return ndisStatus;
}


NDIS_STATUS 
HelperPortSetPower(
    _In_  PMP_HELPER_PORT         HelperPort,
    _In_  NDIS_DEVICE_POWER_STATE NewDeviceState
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    PADAPTER                    adapter = HelperPort->ParentPort->Adapter;
    ULONG                       i;

    //
    // If we are going to sleep, notify the powers about the new power state
    // now before we do stuff on the hardware
    //
    if (NewDeviceState != NdisDeviceStateD0)
    {
        for (i = 0; i < adapter->NumberOfPorts; i++)
        {
            // Activate the ports since they may want to do stuff like
            // StopBSS, etc
            HelperPortDelegateExclusiveAccess(HelperPort, adapter->PortList[i]);
                        
            // Notify the port of power state
            ndisStatus = Port11SetPower(adapter->PortList[i], NewDeviceState);
            
            MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
        }

        // Reobtain active context
        HelperPortDelegateExclusiveAccess(HelperPort, HELPPORT_GET_MP_PORT(HelperPort));
    }

    //
    // The current DevicePowerState has been set to NewDeviceState before
    // calling the hardware intentionally. The call to Hw11SetPower
    // cannot fail. Before the call returns, Interrupts may be enabled for this
    // device (when going to D0)
    //
    HelperPort->DevicePowerState = NewDeviceState;

    //
    // Change hardware power state
    //
    ndisStatus = Hw11SetPower(adapter->Hw, NewDeviceState);

    //
    // If we are waking up from sleep, notify the powers about the new power state
    // now that the hardware is ready
    //
    if (NewDeviceState == NdisDeviceStateD0)
    {
        for (i = 0; i < adapter->NumberOfPorts; i++)
        {
            // We dont activate the ports here. There is no real
            // point since the miniport is anyways pause & ports cannot
            // do anything yet
            
            // Notify the port of power state
            ndisStatus = Port11SetPower(adapter->PortList[i], NewDeviceState);
            
            MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
        }
    }
    
    return ndisStatus;
}

NDIS_STATUS
HelperPortSetPowerExAccessCallback(PMP_PORT Port, PVOID Ctx)
{
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    PMP_POWER_PARAMETERS        powerParameters = (PMP_POWER_PARAMETERS)Ctx;

    HelperPortExclusiveAccessGranted(helperPort);
    HelperPortSetPower(helperPort, powerParameters->NewDeviceState);

    NdisSetEvent(&powerParameters->CompleteEvent);

    return NDIS_STATUS_SUCCESS;
}

NDIS_STATUS
HelperPortHandleSetPower(
    _In_ PMP_PORT                 Port,
    _Inout_ PVOID                InformationBuffer,
    _In_ ULONG                    InformationBufferLength,
    _Inout_ PULONG               BytesRead,
    _Inout_ PULONG               BytesNeeded
    )
{
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_SUCCESS;
    NDIS_DEVICE_POWER_STATE     newDeviceState;
    PMP_HELPER_PORT             helperPort = MP_GET_HELPPORT(Port);
    MP_POWER_PARAMETERS         powerParameters;

    do
    {
        //
        // Store new power state and succeed the request.
        //
        *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
        if (InformationBufferLength < *BytesNeeded)
        {
            //
            // Too little data. Bail out.
            //
            MpTrace(COMP_POWER, DBG_SERIOUS,  ("Bad length received for the SET_POWER request\n"));
            ndisStatus = NDIS_STATUS_INVALID_LENGTH;
            break;
        }
        
        NdisMoveMemory(&newDeviceState, InformationBuffer, sizeof(NDIS_DEVICE_POWER_STATE));
        *BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
        
        if (newDeviceState <= NdisDeviceStateUnspecified || newDeviceState >= NdisDeviceStateMaximum)
        {
            //
            // An invalid device state has been specified. Bail out.
            //
            MpTrace(COMP_POWER, DBG_SERIOUS,  ("Invalid data received in SET_POWER request\n"));
            ndisStatus = NDIS_STATUS_INVALID_DATA;
            break;
        }
        
        if (newDeviceState == helperPort->DevicePowerState)
        {
            //
            // We are already in the device state being set. Succeed the call.
            //
            MpTrace(COMP_POWER, DBG_NORMAL,  ("Device is already in power state D%d\n", newDeviceState));
            ndisStatus = NDIS_STATUS_SUCCESS;
            break;
        }

        // Populate the parameters to pass to the handler
        NdisZeroMemory(&powerParameters, sizeof(MP_POWER_PARAMETERS));
        powerParameters.NewDeviceState = newDeviceState;
        NdisInitializeEvent(&powerParameters.CompleteEvent);
        NdisResetEvent(&powerParameters.CompleteEvent);

        PORT_ACQUIRE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

        //
        // Request exclusive access. Since this is called after a pause,
        // in most cases we would already own the exclusive access
        //
        ndisStatus = HelperPortRequestExclusiveAccess(helperPort, 
            HelperPortSetPowerExAccessCallback, 
            &powerParameters,
            TRUE
            );
        
        if (ndisStatus == NDIS_STATUS_SUCCESS)
        {
            // the function completed synchronously, call the callback ourselves
            HelperPortSetPowerExAccessCallback(Port, &powerParameters);
        }
        else if (ndisStatus == NDIS_STATUS_PENDING)
        {
            // Will be processed asynchronously
            ndisStatus = NDIS_STATUS_SUCCESS;
        }

        if (ndisStatus == NDIS_STATUS_SUCCESS)
        {
            // wait for the power event to complete
            NdisWaitEvent(&powerParameters.CompleteEvent, 0);

            // release exclusive access
            HelperPortReleaseExclusiveAccess(helperPort);
        }
        else    // Exclusive access request failed
        {
            MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Exclusive access request for Set Power failed with status 0x%08x\n", ndisStatus));        
        }

        PORT_RELEASE_PNP_MUTEX(HELPPORT_GET_MP_PORT(helperPort));

        // We must succeed the power request
        ndisStatus = NDIS_STATUS_SUCCESS;
    } while(FALSE);

    return ndisStatus;
}

NDIS_STATUS
HelperPortHandleOidRequest(
    _In_  PMP_PORT                Port,
    _In_  PNDIS_OID_REQUEST       NdisOidRequest,
    _Out_ BOOLEAN                 *pfOidCompleted
    )
{
    NDIS_OID                    oid;
    NDIS_STATUS                 ndisStatus = NDIS_STATUS_NOT_SUPPORTED;
    
    oid = NdisOidRequest->DATA.QUERY_INFORMATION.Oid; // Oid is at same offset for all RequestTypes

    // Hold this in the pending OID request structure
    Port->PendingOidRequest = NdisOidRequest;

    *pfOidCompleted = FALSE;

    switch (oid)
    {
        case OID_DOT11_CREATE_MAC:
            {
                ndisStatus = HelperPortCreateMac(Port, NdisOidRequest, pfOidCompleted);                
            }
            break;
                
        case OID_DOT11_DELETE_MAC:
            {
                ndisStatus = HelperPortDeleteMac(Port, NdisOidRequest, pfOidCompleted);                
            }                            
            break;


        case OID_PNP_QUERY_POWER:
            if (NdisOidRequest->RequestType != NdisRequestQueryInformation)
            {
                MpTrace(COMP_POWER, DBG_SERIOUS, ("Invalid request type %d for OID_PNP_QUERY_POWER\n", 
                    NdisOidRequest->RequestType));
            }
            else
            {
                ndisStatus = HelperPortHandleQueryPower(
                                Port,
                                NdisOidRequest->DATA.QUERY_INFORMATION.InformationBuffer,
                                NdisOidRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
                                (PULONG)&NdisOidRequest->DATA.QUERY_INFORMATION.BytesWritten,
                                (PULONG)&NdisOidRequest->DATA.QUERY_INFORMATION.BytesNeeded
                                );
            }
            break;

        case OID_PNP_SET_POWER:
            if (NdisOidRequest->RequestType != NdisRequestSetInformation)
            {
                MpTrace(COMP_POWER, DBG_SERIOUS, ("Invalid request type %d for OID_PNP_SET_POWER\n", 
                    NdisOidRequest->RequestType));
            }
            else
            {
                ndisStatus = HelperPortHandleSetPower(
                                Port,
                                NdisOidRequest->DATA.SET_INFORMATION.InformationBuffer,
                                NdisOidRequest->DATA.SET_INFORMATION.InformationBufferLength,
                                (PULONG)&NdisOidRequest->DATA.SET_INFORMATION.BytesRead,
                                (PULONG)&NdisOidRequest->DATA.SET_INFORMATION.BytesNeeded
                                );
            }
            break;
        default:
            MPASSERT(FALSE);
    };

    if ( (FALSE == *pfOidCompleted) && (NDIS_STATUS_PENDING != ndisStatus))
    {
        // No OID requests pending
        Port->PendingOidRequest = NULL;
    }
    
    return ndisStatus;
}



Our Services

  • What our customers say about us?

© 2011-2025 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