Sample Code

Windows Driver Samples/ Hyper-V Extensible Switch extension filter driver/ C++/ base/ SxBase.c/

/*++

Copyright (c) Microsoft Corporation. All Rights Reserved.

Module Name:

    SxBase.c

Abstract:

    This file contains the common code for building a switch extension. This
    file includes all the standard NDIS handling and exposes a function based
    interface for the control path and data path. This also has reusable code
    for basic operations such as pause/resume handling etc.


--*/

#include "precomp.h"

ULONG SxDebugLevel;
NDIS_HANDLE SxDriverHandle = NULL;
NDIS_HANDLE SxDriverObject;
NDIS_SPIN_LOCK SxExtensionListLock;
LIST_ENTRY SxExtensionList;

NDIS_STRING SxExtensionFriendlyName;
NDIS_STRING SxExtensionGuid;

NDIS_STATUS
SxpNdisProcessSetOid(
    __in PSX_SWITCH_OBJECT Switch,
    __inout PNDIS_OID_REQUEST OidRequest,
    __out PBOOLEAN Complete
    );

NDIS_STATUS
SxpNdisProcessMethodOid(
    __in PSX_SWITCH_OBJECT Switch,
    __inout PNDIS_OID_REQUEST OidRequest,
    __out PBOOLEAN Complete,
    __out PULONG BytesNeeded
    );

    
//
// DriverEntry
// http://msdn.microsoft.com/en-us/library/ff544113(v=VS.85).aspx
//
_Use_decl_annotations_
NTSTATUS
DriverEntry(
    PDRIVER_OBJECT DriverObject,
    PUNICODE_STRING RegistryPath
    )
{
    NDIS_STATUS status;
    NDIS_FILTER_DRIVER_CHARACTERISTICS fChars;
    NDIS_STRING serviceName;

    UNREFERENCED_PARAMETER(RegistryPath);
    
    //
    // Initialize extension specific data.
    //
    status = SxExtInitialize();
    if (status != NDIS_STATUS_SUCCESS)
    {
        goto Cleanup;
    }

    RtlInitUnicodeString(&serviceName, SxExtServiceName);
    RtlInitUnicodeString(&SxExtensionFriendlyName, SxExtFriendlyName);
    RtlInitUnicodeString(&SxExtensionGuid, SxExtUniqueName);
    SxDriverObject = DriverObject;

    NdisZeroMemory(&fChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
    fChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
    fChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
    fChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2;
    fChars.MajorNdisVersion = SxExtMajorNdisVersion;
    fChars.MinorNdisVersion = SxExtMinorNdisVersion;
    fChars.MajorDriverVersion = 1;
    fChars.MinorDriverVersion = 0;
    fChars.Flags = 0;
    fChars.FriendlyName = SxExtensionFriendlyName;
    fChars.UniqueName = SxExtensionGuid;
    fChars.ServiceName = serviceName;
    
    fChars.SetOptionsHandler = SxNdisSetOptions;
    fChars.SetFilterModuleOptionsHandler = SxNdisSetFilterModuleOptions;
    
    fChars.AttachHandler = SxNdisAttach;
    fChars.DetachHandler = SxNdisDetach;
    fChars.PauseHandler = SxNdisPause;
    fChars.RestartHandler = SxNdisRestart;

    fChars.SendNetBufferListsHandler = SxNdisSendNetBufferLists;
    fChars.SendNetBufferListsCompleteHandler = SxNdisSendNetBufferListsComplete;
    fChars.CancelSendNetBufferListsHandler = SxNdisCancelSendNetBufferLists;
    fChars.ReceiveNetBufferListsHandler = SxNdisReceiveNetBufferLists;
    fChars.ReturnNetBufferListsHandler = SxNdisReturnNetBufferLists;
    
    fChars.OidRequestHandler = SxNdisOidRequest;
    fChars.OidRequestCompleteHandler = SxNdisOidRequestComplete;
    fChars.CancelOidRequestHandler = SxNdisCancelOidRequest;
    
    fChars.NetPnPEventHandler = SxNdisNetPnPEvent;
    fChars.StatusHandler = SxNdisStatus;
    
    NdisAllocateSpinLock(&SxExtensionListLock);
    InitializeListHead(&SxExtensionList);

    DriverObject->DriverUnload = SxNdisUnload;

    status = NdisFRegisterFilterDriver(DriverObject,
                                       (NDIS_HANDLE)SxDriverObject,
                                       &fChars,
                                       &SxDriverHandle);

Cleanup:

    if (status != NDIS_STATUS_SUCCESS)
    {
        if (SxDriverHandle != NULL)
        {
            NdisFDeregisterFilterDriver(SxDriverHandle);
            SxDriverHandle = NULL;
        }

        NdisFreeSpinLock(&SxExtensionListLock);
        
        SxExtUninitialize();
    }

    return status;
}


//
// Unload Routine
// http://msdn.microsoft.com/en-us/library/ff564886(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisUnload(
    PDRIVER_OBJECT DriverObject
    )
{
    UNREFERENCED_PARAMETER(DriverObject);

    SxExtUninitialize();
    
    NdisFDeregisterFilterDriver(SxDriverHandle);
    NdisFreeSpinLock(&SxExtensionListLock);
}


//
// FilterSetOptions Function
// http://msdn.microsoft.com/en-us/library/ff549972(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisSetOptions(
    NDIS_HANDLE NdisDriverHandle,
    NDIS_HANDLE DriverContext
    )
{
    UNREFERENCED_PARAMETER(NdisDriverHandle);
    UNREFERENCED_PARAMETER(DriverContext);
    return NDIS_STATUS_SUCCESS;
}
    

//
// FilterSetModuleOptions Function
// http://msdn.microsoft.com/en-us/library/ff549970(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisSetFilterModuleOptions(
    NDIS_HANDLE FilterModuleContext
    )
{
    UNREFERENCED_PARAMETER(FilterModuleContext);
    return NDIS_STATUS_SUCCESS;
}


//
// FilterAttach Function
// http://msdn.microsoft.com/en-us/library/ff549905(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisAttach(
    NDIS_HANDLE NdisFilterHandle,
    NDIS_HANDLE SxDriverContext,
    PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
    )
{
    NDIS_STATUS status;
    NDIS_FILTER_ATTRIBUTES sxAttributes;
    ULONG switchObjectSize;
    NDIS_SWITCH_CONTEXT switchContext;
    NDIS_SWITCH_OPTIONAL_HANDLERS switchHandler;
    PSX_SWITCH_OBJECT switchObject;
    
    UNREFERENCED_PARAMETER(SxDriverContext);

    DEBUGP(DL_TRACE, ("===>SxAttach: NdisFilterHandle %p\n", NdisFilterHandle));

    status = NDIS_STATUS_SUCCESS;
    switchObject = NULL;

    NT_ASSERT(SxDriverContext == (NDIS_HANDLE)SxDriverObject);

    if (AttachParameters->MiniportMediaType != NdisMedium802_3)
    {
        status = NDIS_STATUS_INVALID_PARAMETER;
        goto Cleanup;
    }

    switchHandler.Header.Type = NDIS_OBJECT_TYPE_SWITCH_OPTIONAL_HANDLERS;
    switchHandler.Header.Size = NDIS_SIZEOF_SWITCH_OPTIONAL_HANDLERS_REVISION_1;
    switchHandler.Header.Revision = NDIS_SWITCH_OPTIONAL_HANDLERS_REVISION_1;

    status = NdisFGetOptionalSwitchHandlers(NdisFilterHandle,
                                            &switchContext,
                                            &switchHandler);

    if (status != NDIS_STATUS_SUCCESS)
    {
        DEBUGP(DL_ERROR,
               ("SxAttach: Extension is running in non-switch environment.\n"));
        goto Cleanup;
    }

    switchObjectSize = sizeof(SX_SWITCH_OBJECT);
    switchObject = ExAllocatePoolWithTag(NonPagedPoolNx,
                                         switchObjectSize,
                                         SxExtAllocationTag);

    if (switchObject == NULL)
    {
        status = NDIS_STATUS_RESOURCES;
        goto Cleanup;
    }

    RtlZeroMemory(switchObject, switchObjectSize);

    //
    // Initialize NDIS related information.
    //
    switchObject->NdisFilterHandle = NdisFilterHandle;
    switchObject->NdisSwitchContext = switchContext;
    RtlCopyMemory(&switchObject->NdisSwitchHandlers,
                  &switchHandler,
                  sizeof(NDIS_SWITCH_OPTIONAL_HANDLERS));

    //
    // Let the extension create its own context.
    //
    status = SxExtCreateSwitch(switchObject,
                               &(switchObject->ExtensionContext));

    if (status != NDIS_STATUS_SUCCESS)
    {
        goto Cleanup;
    }

    //
    // Register the object with NDIS because NDIS passes this object when it
    // calls into the driver.
    //
    NdisZeroMemory(&sxAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
    sxAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
    sxAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
    sxAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
    sxAttributes.Flags = 0;

    NDIS_DECLARE_FILTER_MODULE_CONTEXT(SX_SWITCH_OBJECT);
    status = NdisFSetAttributes(NdisFilterHandle, switchObject, &sxAttributes);

    if (status != NDIS_STATUS_SUCCESS)
    {
        DEBUGP(DL_ERROR, ("SxBase: Failed to set attributes.\n"));
        goto Cleanup;
    }

    switchObject->ControlFlowState = SxSwitchAttached;
    switchObject->DataFlowState = SxSwitchPaused;
    
    NdisAcquireSpinLock(&SxExtensionListLock);
    InsertHeadList(&SxExtensionList, &switchObject->Link);
    NdisReleaseSpinLock(&SxExtensionListLock);
    
Cleanup:

    if (status != NDIS_STATUS_SUCCESS)
    {
        if (switchObject != NULL)
        {
            ExFreePool(switchObject);
        }
    }

    DEBUGP(DL_TRACE, ("<===SxAttach: status %x\n", status));

    return status;
}


//
// FilterDetach Function
// http://msdn.microsoft.com/en-us/library/ff549918(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisDetach(
    NDIS_HANDLE FilterModuleContext
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;

    DEBUGP(DL_TRACE, ("===>SxDetach: SxInstance %p\n", FilterModuleContext));

    //
    // The extension must be in paused state.
    //
    NT_ASSERT(switchObject->DataFlowState == SxSwitchPaused);
    switchObject->ControlFlowState = SxSwitchDetached;
    
    KeMemoryBarrier();
    
    while(switchObject->PendingOidCount > 0)
    {
        NdisMSleep(1000);
    }
    
    SxExtDeleteSwitch(switchObject, switchObject->ExtensionContext);

    NdisAcquireSpinLock(&SxExtensionListLock);
    RemoveEntryList(&switchObject->Link);
    NdisReleaseSpinLock(&SxExtensionListLock);
    
    ExFreePool(switchObject);

    //
    // Alway return success.
    //
    DEBUGP(DL_TRACE, ("<===SxDetach Successfully\n"));

    return;
}


//
// FilterRestart Function
// http://msdn.microsoft.com/en-us/library/ff549962(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisPause(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)(FilterModuleContext);

    UNREFERENCED_PARAMETER(PauseParameters);

    DEBUGP(DL_TRACE,
           ("===>NDISLWF SxPause: SxInstance %p\n", FilterModuleContext));

    SxExtPauseSwitch(switchObject, switchObject->ExtensionContext);
           
    //
    // Set the flag that the filter is going to pause.
    //
    NT_ASSERT(switchObject->DataFlowState == SxSwitchRunning);
    switchObject->DataFlowState = SxSwitchPaused;
    
    KeMemoryBarrier();
    
    while(switchObject->PendingInjectedNblCount > 0)
    {
        NdisMSleep(1000);
    }

    DEBUGP(DL_TRACE, ("<===SxPause: status %x\n", NDIS_STATUS_SUCCESS));

    return NDIS_STATUS_SUCCESS;
}


//
// FilterPause Function
// http://msdn.microsoft.com/en-us/library/ff549957(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisRestart(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(RestartParameters);

    DEBUGP(DL_TRACE,
           ("===>SxRestart: FilterModuleContext %p\n", FilterModuleContext));
           
    status = SxExtRestartSwitch(switchObject,
                                switchObject->ExtensionContext);
    if (status != NDIS_STATUS_SUCCESS)
    {
        status = NDIS_STATUS_RESOURCES;
        goto Cleanup;
    }

    NT_ASSERT(switchObject->DataFlowState == SxSwitchPaused);
    switchObject->DataFlowState = SxSwitchRunning;
    
    DEBUGP(DL_TRACE,
           ("<===SxRestart: FilterModuleContext %p, status %x\n",
            FilterModuleContext,
            NDIS_STATUS_SUCCESS));

Cleanup:
    return status;
}


//
// FilterOidRequest Function
// http://msdn.microsoft.com/en-us/library/ff549954(v=VS.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisOidRequest(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_OID_REQUEST OidRequest
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    NDIS_STATUS status;
    PNDIS_OID_REQUEST clonedRequest=NULL;
    PVOID *cloneRequestContext;
    BOOLEAN completeOid = FALSE;
    ULONG bytesNeeded = 0;
   
    status = NDIS_STATUS_SUCCESS;

    DEBUGP(DL_TRACE, ("===>SxOidRequest: OidRequest %p.\n", OidRequest));
    
    NdisInterlockedIncrement(&switchObject->PendingOidCount);

    status = NdisAllocateCloneOidRequest(switchObject->NdisFilterHandle,
                                         OidRequest,
                                         SxExtAllocationTag,
                                         &clonedRequest);
    if (status != NDIS_STATUS_SUCCESS)
    {
        DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone OidRequest\n"));
        goto Cleanup;
    }

    cloneRequestContext = (PVOID*)(&clonedRequest->SourceReserved[0]);
    *cloneRequestContext = OidRequest;
    
    switch (clonedRequest->RequestType)
    {           
        case NdisRequestSetInformation:
            status = SxpNdisProcessSetOid(switchObject,
                                          clonedRequest,
                                          &completeOid);
            break;
        
        case NdisRequestMethod:
            status = SxpNdisProcessMethodOid(switchObject,
                                             clonedRequest,
                                             &completeOid,
                                             &bytesNeeded);

            break;
    }
    
    if (completeOid)
    {
        NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, clonedRequest);
        OidRequest->DATA.METHOD_INFORMATION.BytesNeeded = bytesNeeded;
        NdisInterlockedDecrement(&switchObject->PendingOidCount);
        goto Cleanup;
    }

    status = NdisFOidRequest(switchObject->NdisFilterHandle, clonedRequest);

    if (status != NDIS_STATUS_PENDING)
    {
        SxNdisOidRequestComplete(switchObject, clonedRequest, status);

        //
        // We must still return status as pending because we complete the
        // request using NdisFOidRequestComplete() in SxOidRequestComplete().
        //
        status = NDIS_STATUS_PENDING;
    }

Cleanup:

    DEBUGP(DL_TRACE, ("<===SxOidRequest: status %8x.\n", status));
    return status;
}


//
// FilterCancelOidRequest Function
// http://msdn.microsoft.com/en-us/library/ff549911(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisCancelOidRequest(
    NDIS_HANDLE FilterModuleContext,
    PVOID RequestId
    )
{
    UNREFERENCED_PARAMETER(FilterModuleContext);
    UNREFERENCED_PARAMETER(RequestId);
}


//
// FilterOidRequestComplete Function
// http://msdn.microsoft.com/en-us/library/ff549956(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisOidRequestComplete(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_OID_REQUEST NdisOidRequest,
    NDIS_STATUS Status
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    PNDIS_OID_REQUEST originalRequest;
    PVOID *oidRequestContext;
    PNDIS_SWITCH_NIC_OID_REQUEST nicOidRequestBuf;
    PNDIS_OBJECT_HEADER header;

    DEBUGP(DL_TRACE,
           ("===>SxOidRequestComplete, NdisOidRequest %p.\n", NdisOidRequest));

    oidRequestContext = (PVOID*)(&NdisOidRequest->SourceReserved[0]);
    originalRequest = (*oidRequestContext);

    //
    // This is the internal request
    //
    if (originalRequest == NULL)
    {
        SxpNdisCompleteInternalOidRequest(switchObject, NdisOidRequest, Status);
        goto Cleanup;
    }

    //
    // Copy the information from the returned request to the original request
    //
    switch(NdisOidRequest->RequestType)
    {
    case NdisRequestMethod:
        originalRequest->DATA.METHOD_INFORMATION.OutputBufferLength =
            NdisOidRequest->DATA.METHOD_INFORMATION.OutputBufferLength;
        originalRequest->DATA.METHOD_INFORMATION.BytesRead =
            NdisOidRequest->DATA.METHOD_INFORMATION.BytesRead;
        originalRequest->DATA.METHOD_INFORMATION.BytesNeeded =
            NdisOidRequest->DATA.METHOD_INFORMATION.BytesNeeded;
        originalRequest->DATA.METHOD_INFORMATION.BytesWritten =
            NdisOidRequest->DATA.METHOD_INFORMATION.BytesWritten;
            
        if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_NIC_REQUEST &&
                switchObject->OldNicRequest != NULL)
        {
            nicOidRequestBuf = NdisOidRequest->DATA.METHOD_INFORMATION.InformationBuffer;
            Status = SxExtProcessNicRequestComplete(switchObject,
                                                    switchObject->ExtensionContext,
                                                    nicOidRequestBuf->OidRequest,
                                                    nicOidRequestBuf->SourcePortId,
                                                    nicOidRequestBuf->SourceNicIndex,
                                                    nicOidRequestBuf->DestinationPortId,
                                                    nicOidRequestBuf->DestinationNicIndex,
                                                    Status);
            
            originalRequest->DATA.METHOD_INFORMATION.InformationBuffer =
                                                    switchObject->OldNicRequest;
            switchObject->OldNicRequest = NULL;
            ExFreePoolWithTag(nicOidRequestBuf, SxExtAllocationTag);
        }
        
        break;

    case NdisRequestSetInformation:
        header = originalRequest->DATA.SET_INFORMATION.InformationBuffer;
        
        originalRequest->DATA.SET_INFORMATION.BytesRead =
            NdisOidRequest->DATA.SET_INFORMATION.BytesRead;
        originalRequest->DATA.SET_INFORMATION.BytesNeeded =
            NdisOidRequest->DATA.SET_INFORMATION.BytesNeeded;
            
        if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_PORT_CREATE &&
            Status != NDIS_STATUS_SUCCESS)
        {
            SxExtDeletePort(switchObject,
                            switchObject->ExtensionContext,
                            (PNDIS_SWITCH_PORT_PARAMETERS)header);
        }
        else if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_PORT_CREATE &&
                 Status != NDIS_STATUS_SUCCESS)
        {
            SxExtDeleteNic(switchObject,
                           switchObject->ExtensionContext,
                           (PNDIS_SWITCH_NIC_PARAMETERS)header);
            
        }

        break;

    case NdisRequestQueryInformation:
    case NdisRequestQueryStatistics:
    default:
        originalRequest->DATA.QUERY_INFORMATION.BytesWritten =
            NdisOidRequest->DATA.QUERY_INFORMATION.BytesWritten;
        originalRequest->DATA.QUERY_INFORMATION.BytesNeeded =
            NdisOidRequest->DATA.QUERY_INFORMATION.BytesNeeded;
        break;
    }

    (*oidRequestContext) = NULL;

    NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, NdisOidRequest);

    NdisFOidRequestComplete(switchObject->NdisFilterHandle,
                            originalRequest,
                            Status);

    DEBUGP(DL_TRACE, ("<===SxOidRequestComplete.\n"));
    
Cleanup:
    NdisInterlockedDecrement(&switchObject->PendingOidCount);
}


//
// FilterSendNetBufferLists Function
// http://msdn.microsoft.com/en-us/library/ff549966(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisSendNetBufferLists(
    NDIS_HANDLE FilterModuleContext,
    PNET_BUFFER_LIST NetBufferLists,
    NDIS_PORT_NUMBER PortNumber,
    ULONG SendFlags
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    
    UNREFERENCED_PARAMETER(PortNumber);

    SxExtStartNetBufferListsIngress(switchObject,
                                    switchObject->ExtensionContext,
                                    NetBufferLists,
                                    SendFlags);
}


//
// FilterSendNetBufferListsComplete Function
// http://msdn.microsoft.com/en-us/library/ff549967(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisSendNetBufferListsComplete(
    NDIS_HANDLE FilterModuleContext,
    PNET_BUFFER_LIST NetBufferLists,
    ULONG SendCompleteFlags
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;

    SxExtStartCompleteNetBufferListsIngress(switchObject,
                                            switchObject->ExtensionContext,
                                            NetBufferLists,
                                            SendCompleteFlags);
}


//
// FilterReceiveNetBufferLists Function
// http://msdn.microsoft.com/en-us/library/ff549960(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisReceiveNetBufferLists(
    NDIS_HANDLE FilterModuleContext,
    PNET_BUFFER_LIST NetBufferLists,
    NDIS_PORT_NUMBER PortNumber,
    ULONG NumberOfNetBufferLists,
    ULONG ReceiveFlags
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    
    UNREFERENCED_PARAMETER(PortNumber);

    SxExtStartNetBufferListsEgress(switchObject,
                                   switchObject->ExtensionContext,
                                   NetBufferLists,
                                   NumberOfNetBufferLists,
                                   ReceiveFlags);
}


//
// FilterReturnNetBufferLists Function
// http://msdn.microsoft.com/en-us/library/ff549964(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisReturnNetBufferLists(
    NDIS_HANDLE FilterModuleContext,
    PNET_BUFFER_LIST NetBufferLists,
    ULONG ReturnFlags
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;

    SxExtStartCompleteNetBufferListsEgress(switchObject,
                                           switchObject->ExtensionContext,
                                           NetBufferLists,
                                           ReturnFlags);
}


//
// FilterCancelSendNetBufferLists Function
// http://msdn.microsoft.com/en-us/library/ff549915(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisCancelSendNetBufferLists(
    NDIS_HANDLE FilterModuleContext,
    PVOID CancelId
    )
{
    UNREFERENCED_PARAMETER(FilterModuleContext);
    UNREFERENCED_PARAMETER(CancelId);
}


//
// FilterNetPnPEvent Function
// http://msdn.microsoft.com/en-us/library/ff549952(v=vs.85).aspx
//
_Use_decl_annotations_
NDIS_STATUS
SxNdisNetPnPEvent(
    NDIS_HANDLE FilterModuleContext,
    PNET_PNP_EVENT_NOTIFICATION NetPnPEvent
    )
{
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    
    if (NetPnPEvent->NetPnPEvent.NetEvent == NetEventSwitchActivate)
    {   
        //
        // Switch Activation must be passed along regardless of successful
        // initialization.
        //
        SxExtActivateSwitch(switchObject,
                            switchObject->ExtensionContext);
    }
    
    return NdisFNetPnPEvent(switchObject->NdisFilterHandle,
                            NetPnPEvent);
}


//
// FilterStatus Function
// http://msdn.microsoft.com/en-us/library/ff549973(v=VS.85).aspx
//
_Use_decl_annotations_
VOID
SxNdisStatus(
    NDIS_HANDLE FilterModuleContext,
    PNDIS_STATUS_INDICATION StatusIndication
    )
{
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
    PNDIS_SWITCH_NIC_STATUS_INDICATION nicIndication;
    PNDIS_STATUS_INDICATION originalIndication;
    
    if (StatusIndication->Header.Type != NDIS_OBJECT_TYPE_STATUS_INDICATION ||
        StatusIndication->Header.Revision != NDIS_STATUS_INDICATION_REVISION_1 ||
        StatusIndication->Header.Size < NDIS_SIZEOF_STATUS_INDICATION_REVISION_1)
    {
        goto Cleanup;
    }
    
    //
    // Only NDIS_STATUS_SWITCH_NIC_STAUTUS indications need to be processed
    // by switch extensions.
    //
    if (StatusIndication->StatusCode != NDIS_STATUS_SWITCH_NIC_STATUS)
    {
        goto Cleanup;
    }
    
    nicIndication = StatusIndication->StatusBuffer;
    
    if (nicIndication->Header.Type != NDIS_OBJECT_TYPE_STATUS_INDICATION ||
        nicIndication->Header.Revision != NDIS_SWITCH_NIC_STATUS_INDICATION_REVISION_1 ||
        nicIndication->Header.Size < NDIS_SIZEOF_SWITCH_NIC_STATUS_REVISION_1)
    {
        goto Cleanup;
    }
    
    originalIndication = nicIndication->StatusIndication;
    
    status = SxExtProcessNicStatus(switchObject,
                                   switchObject->ExtensionContext,
                                   originalIndication,
                                   nicIndication->SourcePortId,
                                   nicIndication->SourceNicIndex);
                                   
Cleanup:
    if (status == NDIS_STATUS_SUCCESS)
    {
        NdisFIndicateStatus(switchObject->NdisFilterHandle,
                            StatusIndication);
    }

    return;
                           
}


NDIS_STATUS
SxpNdisProcessSetOid(
    __in PSX_SWITCH_OBJECT Switch,
    __inout PNDIS_OID_REQUEST OidRequest,
    __out PBOOLEAN Complete
    )
{
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
    NDIS_OID oid = OidRequest->DATA.SET_INFORMATION.Oid;
    PNDIS_OBJECT_HEADER header;
    ULONG bytesRestored = 0;
    
    *Complete = FALSE;
    
    header = OidRequest->DATA.SET_INFORMATION.InformationBuffer;
    
    if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != 0 &&
        OidRequest->DATA.SET_INFORMATION.InformationBufferLength < 
            sizeof(NDIS_OBJECT_HEADER))
    {
        status = NDIS_STATUS_NOT_SUPPORTED;
        *Complete = TRUE;
        goto Cleanup;
    }
    
    if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength == 0)
    {
        *Complete = FALSE;
        goto Cleanup;
    }
    
    switch(oid)
    {
        case OID_SWITCH_PROPERTY_ADD:
        case OID_SWITCH_PROPERTY_UPDATE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_PROPERTY_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PROPERTY_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            if (oid == OID_SWITCH_PROPERTY_ADD)
            {
                status = SxExtAddSwitchProperty(Switch,
                                                Switch->ExtensionContext,
                                                (PNDIS_SWITCH_PROPERTY_PARAMETERS)header);
            }
            else
            {
                status = SxExtUpdateSwitchProperty(Switch,
                                                   Switch->ExtensionContext,
                                                   (PNDIS_SWITCH_PROPERTY_PARAMETERS)header);
            }
            
            if (status == NDIS_STATUS_NOT_SUPPORTED)
            {
                status = NDIS_STATUS_SUCCESS;
            }
            else
            {
                *Complete = TRUE;
                goto Cleanup;
            }
            
            break;
        case OID_SWITCH_PROPERTY_DELETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_PROPERTY_DELETE_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PROPERTY_DELETE_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            *Complete = SxExtDeleteSwitchProperty(Switch,
                                                  Switch->ExtensionContext,
                                                 (PNDIS_SWITCH_PROPERTY_DELETE_PARAMETERS)header);
                                                 
            break;
        
        case OID_SWITCH_PORT_PROPERTY_ADD:
        case OID_SWITCH_PORT_PROPERTY_UPDATE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
        
            if (oid == OID_SWITCH_PORT_PROPERTY_ADD)
            {
                status = SxExtAddPortProperty(Switch,
                                              Switch->ExtensionContext,
                                              (PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS)header);
            }
            else
            {
                status = SxExtUpdatePortProperty(Switch,
                                                 Switch->ExtensionContext,
                                                 (PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS)header);
            }
            
            if (status == NDIS_STATUS_NOT_SUPPORTED)
            {
                status = NDIS_STATUS_SUCCESS;
            }
            else
            {
                *Complete = TRUE;
                goto Cleanup;
            }
            
            break;
        
        case OID_SWITCH_PORT_PROPERTY_DELETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            *Complete = SxExtDeletePortProperty(Switch,
                                                Switch->ExtensionContext,
                                                (PNDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS)header);
            
            break;
            
        case OID_SWITCH_PORT_CREATE:
        case OID_SWITCH_PORT_UPDATED:
        case OID_SWITCH_PORT_TEARDOWN:
        case OID_SWITCH_PORT_DELETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_PORT_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
        
            if (oid == OID_SWITCH_PORT_CREATE)
            {
                status = SxExtCreatePort(Switch,
                                         Switch->ExtensionContext,
                                         (PNDIS_SWITCH_PORT_PARAMETERS)header);
                                       
                if (status != NDIS_STATUS_SUCCESS)
                {
                    *Complete = TRUE;
                }
            }
            else if (oid == OID_SWITCH_PORT_UPDATED)
            {   
                SxExtUpdatePort(Switch,
                                Switch->ExtensionContext,
                                (PNDIS_SWITCH_PORT_PARAMETERS)header);
            }
            else if (oid == OID_SWITCH_PORT_TEARDOWN)
            {   
                SxExtTeardownPort(Switch,
                                  Switch->ExtensionContext,
                                  (PNDIS_SWITCH_PORT_PARAMETERS)header);
            }
            else
            {
                SxExtDeletePort(Switch,
                                Switch->ExtensionContext,
                                (PNDIS_SWITCH_PORT_PARAMETERS)header);
            }
        
            break;
        
        case OID_SWITCH_NIC_CREATE:
        case OID_SWITCH_NIC_CONNECT:
        case OID_SWITCH_NIC_UPDATED:
        case OID_SWITCH_NIC_DISCONNECT:
        case OID_SWITCH_NIC_DELETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            if (oid == OID_SWITCH_NIC_CREATE)
            {
                status = SxExtCreateNic(Switch,
                                        Switch->ExtensionContext,
                                        (PNDIS_SWITCH_NIC_PARAMETERS)header);
                if (status != NDIS_STATUS_SUCCESS)
                {
                    *Complete = TRUE;
                }
            }
            else if (oid == OID_SWITCH_NIC_CONNECT)
            {   
                SxExtConnectNic(Switch,
                                Switch->ExtensionContext,
                                (PNDIS_SWITCH_NIC_PARAMETERS)header);
            }
            else if (oid == OID_SWITCH_NIC_UPDATED)
            {
                SxExtUpdateNic(Switch,
                               Switch->ExtensionContext,
                               (PNDIS_SWITCH_NIC_PARAMETERS)header);
            }
            else if (oid == OID_SWITCH_NIC_DISCONNECT)
            {
                SxExtDisconnectNic(Switch,
                                   Switch->ExtensionContext,
                                   (PNDIS_SWITCH_NIC_PARAMETERS)header);
            }
            else
            {
                SxExtDeleteNic(Switch,
                               Switch->ExtensionContext,
                               (PNDIS_SWITCH_NIC_PARAMETERS)header);
            }
            
            break;
        
        case OID_SWITCH_NIC_RESTORE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                goto Cleanup;
            }
            
            status = SxExtNicRestore(Switch,
                                     Switch->ExtensionContext,
                                     (PNDIS_SWITCH_NIC_SAVE_STATE)header,
                                     &bytesRestored);
                                     
            if (status != NDIS_STATUS_SUCCESS)
            {
                *Complete = TRUE;
            }
            else if (bytesRestored > 0)
            {
                *Complete = TRUE;
            }
                                      
            break;    

        case OID_SWITCH_NIC_SAVE_COMPLETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            SxExtSaveNicComplete(Switch,
                                 Switch->ExtensionContext,
                                 (PNDIS_SWITCH_NIC_SAVE_STATE)header);    

            break;
            
        case OID_SWITCH_NIC_RESTORE_COMPLETE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            SxExtNicRestoreComplete(Switch,
                                    Switch->ExtensionContext,
                                    (PNDIS_SWITCH_NIC_SAVE_STATE)header);    

            break;
            
        default:
            break;
    }
    
Cleanup:
    return status;
}


NDIS_STATUS
SxpNdisProcessMethodOid(
    __in PSX_SWITCH_OBJECT Switch,
    __inout PNDIS_OID_REQUEST OidRequest,
    __out PBOOLEAN Complete,
    __out PULONG BytesNeeded
    )
{
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
    NDIS_OID oid = OidRequest->DATA.SET_INFORMATION.Oid;
    PNDIS_OBJECT_HEADER header;
    PNDIS_SWITCH_NIC_OID_REQUEST nicOidRequest;
    PNDIS_SWITCH_NIC_OID_REQUEST newNicOidRequest = NULL;
    NDIS_SWITCH_PORT_ID destPort, sourcePort;
    NDIS_SWITCH_NIC_INDEX destNic, sourceNic;
    ULONG bytesWritten = 0;
    ULONG bytesNeeded = 0;
    
    *Complete = FALSE;
    *BytesNeeded = 0;
    
    header = OidRequest->DATA.METHOD_INFORMATION.InformationBuffer;
    
    switch(oid)
    {
        case OID_SWITCH_FEATURE_STATUS_QUERY:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            *Complete = SxExtQuerySwitchFeatureStatus(Switch,
                                                      Switch->ExtensionContext,
                                                      (PNDIS_SWITCH_FEATURE_STATUS_PARAMETERS)header,
                                                      BytesNeeded);
                                                      
            if (*BytesNeeded > 0)
            {
                status = NDIS_STATUS_BUFFER_TOO_SHORT;
            }
        
            break;
            
        case OID_SWITCH_PORT_FEATURE_STATUS_QUERY:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            *Complete = SxExtQueryPortFeatureStatus(Switch,
                                                    Switch->ExtensionContext,
                                                    (PNDIS_SWITCH_PORT_FEATURE_STATUS_PARAMETERS)header,
                                                    BytesNeeded);
                                                    
            if (*BytesNeeded > 0)
            {
                status = NDIS_STATUS_BUFFER_TOO_SHORT;
            }
        
            break;
            
        case OID_SWITCH_NIC_REQUEST:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            nicOidRequest = (PNDIS_SWITCH_NIC_OID_REQUEST)header;
            
            sourcePort = nicOidRequest->SourcePortId;
            sourceNic = nicOidRequest->SourceNicIndex;
            destPort = nicOidRequest->DestinationPortId;
            destNic = nicOidRequest->DestinationNicIndex;
            
            status = SxExtProcessNicRequest(Switch,
                                            Switch->ExtensionContext,
                                            nicOidRequest->OidRequest,
                                            &sourcePort,
                                            &sourceNic,
                                            &destPort,
                                            &destNic);
                                           
            if (status != NDIS_STATUS_SUCCESS)
            {
                *Complete = TRUE;
                goto Cleanup;
            }
                                           
            if (sourcePort != nicOidRequest->SourcePortId ||
                sourceNic != nicOidRequest->SourceNicIndex ||
                destPort != nicOidRequest->DestinationPortId ||
                destNic != nicOidRequest->DestinationNicIndex)
            {
                ASSERT(Switch->OldNicRequest == NULL);
                Switch->OldNicRequest = nicOidRequest;
                
                newNicOidRequest = (PNDIS_SWITCH_NIC_OID_REQUEST)ExAllocatePoolWithTag(
                                                                    NonPagedPoolNx,
                                                                    sizeof(NDIS_SWITCH_NIC_OID_REQUEST),
                                                                    SxExtAllocationTag);
                                                                    
                if (newNicOidRequest == NULL)
                {
                    status = NDIS_STATUS_RESOURCES;
                    *Complete = TRUE;
                    goto Cleanup;
                }
                                                                    
                newNicOidRequest->Header = nicOidRequest->Header;
                newNicOidRequest->SourcePortId = sourcePort;
                newNicOidRequest->SourceNicIndex = sourceNic;
                newNicOidRequest->DestinationPortId = destPort;
                newNicOidRequest->DestinationNicIndex = destNic;
                newNicOidRequest->OidRequest = nicOidRequest->OidRequest;
                        
                OidRequest->DATA.METHOD_INFORMATION.InformationBuffer = newNicOidRequest;
            }
        
            break;
            
        case OID_SWITCH_NIC_SAVE:
            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
            {
                status = NDIS_STATUS_NOT_SUPPORTED;
                *Complete = TRUE;
                goto Cleanup;
            }
            
            status = SxExtSaveNic(Switch,
                                  Switch->ExtensionContext,
                                  (PNDIS_SWITCH_NIC_SAVE_STATE)header,
                                  &bytesWritten,
                                  &bytesNeeded);
                                       
            if (status == NDIS_STATUS_SUCCESS &&
                bytesWritten > 0)
            {
                *Complete = TRUE;
            }
            else if (status == NDIS_STATUS_BUFFER_TOO_SHORT)
            {
                *BytesNeeded = ((PNDIS_SWITCH_NIC_SAVE_STATE)header)->SaveDataOffset +
                                bytesNeeded;
                *Complete = TRUE;
            }
            else if (status != NDIS_STATUS_SUCCESS)
            {
                *Complete = TRUE;
            }
            
            break;
            
        default:
            break;
    }
    
Cleanup:
    return status;
}


VOID
SxpNdisCompleteInternalOidRequest(
    __in PSX_SWITCH_OBJECT Switch,
    __in PNDIS_OID_REQUEST NdisRequest,
    __in NDIS_STATUS Status
    )
/*++

Routine Description:

    NDIS entry point indicating completion of a pended NDIS_OID_REQUEST.

Arguments:

    Switch - pointer to switch object.

    NdisRequest - pointer to NDIS request

    Status - Status of request completion

Return Value:

    None

--*/
{
    PSX_OID_REQUEST oidRequest;
    ULONG bytesNeeded;
    
    UNREFERENCED_PARAMETER(Switch);

    bytesNeeded = 0;
    oidRequest = NULL;

    switch (NdisRequest->RequestType)
    {
    case NdisRequestSetInformation:
        bytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
        break;

    case NdisRequestQueryInformation:
        bytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
        break;

    case NdisRequestMethod:
        bytesNeeded = NdisRequest->DATA.METHOD_INFORMATION.BytesNeeded;
        break;
    }

    //
    // Get at the request context.
    //
    oidRequest = CONTAINING_RECORD(NdisRequest, SX_OID_REQUEST, NdisOidRequest);

    //
    // Save away the completion status.
    //
    oidRequest->Status = Status;
    
    //
    // Save bytesNeeded
    //
    oidRequest->BytesNeeded = bytesNeeded;

    //
    // Wake up the thread blocked for this request to complete.
    //
    NdisSetEvent(&oidRequest->ReqEvent);
}

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