对PassThru中的Protocol.c的注释

时间:2020-11-26 21:18:14
#include "precomp.h"
#pragma hdrstop

#define MAX_PACKET_POOL_SIZE 0x0000FFFF//最大64K
#define MIN_PACKET_POOL_SIZE 0x000000FF//最小256字节
//------------------------------------------------------------------------
VOID
PtBindAdapter(
              OUT PNDIS_STATUS Status,
              IN NDIS_HANDLE BindContext,
              IN PNDIS_STRING DeviceName,
              IN PVOID SystemSpecific1,
              IN PVOID SystemSpecific2
              )
              /*++
              程序描述:

              被NDIS调用来绑定到下层微端口.

              参数描述:

              Status - 返回状态.
              BindContext - 代表绑定请求NDIS的环境,在中间层驱动程序完成与绑定相关的操作并准备
              接受发送请求时,该句柄作为NdisCompleteBindAdapter的参数返回NDIS.
              DeviceName - 要绑定到的设备名. 传递给NdisOpenAdapter.不能传递副本。
              SystemSpecific1 - 传递给NdisOpenProtocolConfiguration 读取绑定信息。
              SystemSpecific2 - 预留系统使用.

              返回值:

              如果绑定相关操作准备接受发送请求,返回NDIS_STATUS_PENDING,这种情况下调用
              NdisCompleteBindAdapter完成绑定.
              返回其他值,
              --*/
{
    NDIS_HANDLE ConfigHandle = NULL;
    PNDIS_CONFIGURATION_PARAMETER Param;
    NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
    PADAPT pAdapt = NULL;
    NDIS_STATUS Sts;
    UINT MediumIndex;

    PNDIS_CONFIGURATION_PARAMETER BundleParam;
    NDIS_STRING BundleStr = NDIS_STRING_CONST("BundleId");
    NDIS_STATUS BundleStatus;

    DBGPRINT("==> Passthru Protocol Initialize/n");

    do
    {
        // Start off by opening the config section and reading our instance which we want
        // to export for this binding
        //获取中间层驱动程序存储与适配器相关信息的注册表键句柄
        NdisOpenProtocolConfiguration(Status,
            &ConfigHandle,//获得句柄
            SystemSpecific1);
        if (*Status != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        //读取获得的句柄下的信息
        NdisReadConfiguration(Status,
            &Param,
            ConfigHandle,
            &DeviceStr,
            NdisParameterString);
        if (*Status != NDIS_STATUS_SUCCESS)
        {
            break;
        }

        //为Adapter structure分配内存,
        //当微端口初始化后它表现为协议相关(protocol-context)和adapter structure两个方面。
        NdisAllocateMemoryWithTag(&pAdapt, sizeof(ADAPT), TAG);

        if (pAdapt == NULL)
        {
            *Status = NDIS_STATUS_RESOURCES;
            break;
        }

        //零初始化ADAPT结构
        NdisZeroMemory(pAdapt, sizeof(ADAPT));

        //利用注册来存储字符串,将被用于从注册处读取数据
        NdisAllocateMemoryWithTag( &(pAdapt->BundleUniString.Buffer), MAX_BUNDLEID_LENGTH ,TAG);

        if (pAdapt->BundleUniString.Buffer == NULL)
        {
            *Status = NDIS_STATUS_RESOURCES;
            break;
        }

        pAdapt->BundleUniString.MaximumLength = MAX_BUNDLEID_LENGTH ;
        //读取键值信息
        NdisReadConfiguration(&BundleStatus,
            &BundleParam,
            ConfigHandle,
            &BundleStr,
            NdisParameterString);

        if (BundleStatus == NDIS_STATUS_SUCCESS)
        {
            //拷贝包描述符到自己的内存
            ASSERT(pAdapt->BundleUniString.MaximumLength >= BundleParam->ParameterData.StringData.Length);

            pAdapt->BundleUniString.Length = BundleParam->ParameterData.StringData.Length;

            RtlCopyUnicodeString(&pAdapt->BundleUniString, &BundleParam->ParameterData.StringData);
        }
        else
        { // We do not have a bundle id entry in the registry. To play safe we will enter
            // make the escape sequence the Bundle Id, This ensures that no bundle id's are
            // spuriously formed
            //我们没有一个包标志进入注册,为了显示安全,我们将包标志倒序,这确保了没有包标志被伪造

            NDIS_STRING NoBundle = NDIS_STRING_CONST ("<no-bundle>");

            RtlCopyUnicodeString(&pAdapt->BundleUniString, &NoBundle);
        }
        //初始化事件和自旋锁
        NdisInitializeEvent(&pAdapt->Event);
        KeInitializeSpinLock(&pAdapt->SpinLock);

        // Allocate a packet pool for sends. We need this to pass sends down. We cannot use the same
        // packet descriptor that came down to our send handler
        //为发送分配数据包池。
        //我们需要这个来向下传递发送数据。我们不能使用到达我们的发送函数的同样的包描述符。
        NdisAllocatePacketPoolEx(Status,
            &pAdapt->SendPacketPoolHandle,
            MIN_PACKET_POOL_SIZE,
            MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
            sizeof(RSVD));

        if (*Status != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        //为接收开辟数据包池,我们需要这样指示接收
        NdisAllocatePacketPoolEx(Status,
            &pAdapt->RecvPacketPoolHandle,
            MIN_PACKET_POOL_SIZE,
            MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
            sizeof(RSVD));

        if (*Status != NDIS_STATUS_SUCCESS)
        {
            break;
        }
        //调用NdisOpenAdapter进行绑定
        NdisOpenAdapter(Status,
            &Sts,
            &pAdapt->BindingHandle,
            &MediumIndex,
            MediumArray,
            sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
            ProtHandle,
            pAdapt,
            DeviceName,
            0,
            NULL);

        if(*Status == NDIS_STATUS_PENDING)
        {
            NdisWaitEvent(&pAdapt->Event, 0);
            *Status = pAdapt->Status;
        }

        if(*Status != NDIS_STATUS_SUCCESS)
        {
            break;
        }

        pAdapt->Medium = MediumArray[MediumIndex];

        //微端口初始化(可初始化多个)
        NdisIMInitializeDeviceInstanceEx(DriverHandle,
            &Param->ParameterData.StringData,
            pAdapt);



    } while(FALSE);

    if (ConfigHandle != NULL)
    { //关闭表键
        NdisCloseConfiguration(ConfigHandle);
    }

    //如果分配资源失败,则释放分配的资源
    if (*Status != NDIS_STATUS_SUCCESS)
    {
        if (pAdapt != NULL)
        {
            if (pAdapt->SendPacketPoolHandle != NULL)
            {
                NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
            }

            if (pAdapt->RecvPacketPoolHandle != NULL)
            {
                NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
            }

            NdisFreeMemory(pAdapt, sizeof(ADAPT), 0);
        }
    }

    DBGPRINT("<== Passthru Protocol Initialize/n");
}
//----------------------------------------------------------------------
VOID
PtOpenAdapterComplete(
                      IN NDIS_HANDLE ProtocolBindingContext,
                      IN NDIS_STATUS Status,
                      IN NDIS_STATUS OpenErrorStatus
                      )
                      /*++
                      函数描述:
                      完成绑定到下层NIC。

                      如果中间层驱动程序对Ndis.OpenAdapter的调用返回
                      NDIS_STATUS_PENDING,则接着调用该函数来完成绑定.
                      参数描述:
                      ProtocolBindingContext adapter指针
                      Status NdisOpenAdapter返回状态
                      OpenErrorStatus Secondary status(此处忽略).

                      返回值:
                      无返回值。
                      --*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    DBGPRINT("==> Passthru PtOpenAdapterComplete/n");
    pAdapt->Status = Status;
    NdisSetEvent(&pAdapt->Event);
}
//------------------------------------------------------------------------------
VOID
PtUnbindAdapter(
                OUT PNDIS_STATUS Status,
                IN NDIS_HANDLE ProtocolBindingContext,
                IN NDIS_HANDLE UnbindContext
                )
                /*++

                程序描述:
                这个函数必须提供。NDIS调用该函数请求中间层驱动程序释放对下层NIC或虚拟NIC上上的绑定,
                NIC名作为一个该处理程序的一个参数传递
                当需要释放对下层的绑定时被NDIS调用。这个函数被微端口的HaltHandler函数共享。
                Called by NDIS when we are required to unbind to the adapter below.
                This functions shares functionality with the miniport's HaltHandler.
                程序必须保证NdisCloseAdapter和NdisFreeMemory只能有一个被调用一次。

                参数描述:

                Status 返回状态
                ProtocolBindingContext adapter指针
                UnbindContext Context for NdisUnbindComplete() if this pends

                返回值:

                NdisIMDeinitializeDeviceContext的返回值

                --*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    NDIS_HANDLE BindingHandle = pAdapt->BindingHandle;

    DBGPRINT("==> Passthru PtUnbindAdapter/n");

    if (pAdapt->QueuedRequest == TRUE)
    {
        pAdapt->QueuedRequest = FALSE;

        PtRequestComplete (pAdapt,
            &pAdapt->Request,
            NDIS_STATUS_FAILURE );

    }
    //调用NDIS卸载驱动设备实例,我们在HaltHandler中实现大部分功能。
    //如果passthru的小端口的Halt Handler被调用,或IM设备从未被初始化,这个句柄将为空。
    if(pAdapt->MiniportHandle != NULL)
    {
        *Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle);

        if(*Status != NDIS_STATUS_SUCCESS)
        {
            *Status = NDIS_STATUS_FAILURE;
        }
    }
    else
    {
        // We need to do some work here.
        //关闭对下层绑定并且释放分配的内存
        if(pAdapt->BindingHandle != NULL)
        {
            NdisResetEvent(&pAdapt->Event);

            NdisCloseAdapter(Status, pAdapt->BindingHandle);
            //等待关闭完成
            if(*Status == NDIS_STATUS_PENDING)
            {
                NdisWaitEvent(&pAdapt->Event, 0);
                *Status = pAdapt->Status;
            }
        }
        else
        {
            //MiniportHandle和Binding Handle均不能为空
            *Status = NDIS_STATUS_FAILURE;
            ASSERT(0);
        }
        //此处释放早期调用HaltHandler时未能释放的内存
        NdisFreeMemory(pAdapt, sizeof(ADAPT), 0);
    }

    DBGPRINT("<==Passthru UnbindAdapter/n");
}
//----------------------------------------------------------------------------
VOID
PtUnload(
         IN PDRIVER_OBJECT DriverObject
         )
{
    NDIS_STATUS Status;
    //释放注册时分配的空间
    NdisDeregisterProtocol(&Status, ProtHandle);
}
//----------------------------------------------------------------------------
VOID
PtCloseAdapterComplete(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_STATUS Status
    )
/*++
函数说明:

    Completion for the CloseAdapter call.

参数说明:

    ProtocolBindingContext 指向adapter structure
    Status 完成状态

返回值:

    None.

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    pAdapt->Status = Status;
    NdisSetEvent(&pAdapt->Event);
}


VOID
PtResetComplete(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_STATUS Status
    )
/*++

函数说明:

    完成复位操作。

参数说明:

    ProtocolBindingContext adapter structure指针
    Status 完成状态

返回值:

    无.

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    //我们这个程序不产生复位,所以不到达这里
    ASSERT(0);
}


VOID
PtRequestComplete(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNDIS_REQUEST NdisRequest,
    IN NDIS_STATUS Status
    )
/*++
函数说明:

    这个函数必须提供。当Ndis.Request函数(返回NDIS_STATUS_PENDING)调用启
    动的查询或设置工作完成时该函数将被调用. 所有OIDS被完成并送回原先所发出请求的同一个微端口。
    如果Oid == OID_PNP_QUERY_POWER,则数据结构需要returned with all entries =
    NdisDeviceStateUnspecified
   
参数说明:

    ProtocolBindingContext adapter structure指针
    NdisRequest 发出的请求
    Status 完成状态
   
返回值:

    无
--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    NDIS_OID Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;

    //
    // Change to the pAdapt for which the request originated
    //转换到最初请求的pAdapt
    if(MPIsSendOID(Oid))
    {
        pAdapt = pAdapt->pPrimaryAdapt;
        //如果没有捆绑则指向它自己(参看初始化)
    }

    // Since our request is not outstanding anymore
    //以后我们的请求不再突出(传递)
    pAdapt->OutstandingRequests = FALSE;

    //
    // Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
    //完成Set或者Query,如果需要则填充OID_PNP_CAPABILITIES的缓冲区
    switch(NdisRequest->RequestType)
    {
    case NdisRequestQueryInformation:
        //这将不会被传递到下面的微端口
        ASSERT(Oid != OID_PNP_QUERY_POWER);

        // 如果oid == OID_PNP_CAPABILITIES并且查询成功,则用请求的值填充缓冲区。
        if(Oid == OID_PNP_CAPABILITIES && Status == NDIS_STATUS_SUCCESS)
        {

            MPQueryPNPCapbilities(pAdapt,&Status);

        }

        *pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;

        *pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;

        NdisMQueryInformationComplete(pAdapt->MiniportHandle,
            Status);
        break;

    case NdisRequestSetInformation:

        ASSERT( Oid != OID_PNP_SET_POWER);

        *pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
        *pAdapt->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
        NdisMSetInformationComplete(pAdapt->MiniportHandle,
            Status);
        break;

    default:
        ASSERT(0);
        break;
    }

}
//--------------------------------------------------------------------------------
VOID
PtStatus(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_STATUS GeneralStatus,
    IN PVOID StatusBuffer,
    IN UINT StatusBufferSize
    )
/*++

函数说明:
    这个函数必须提供。NDIS调用下层NIC驱动程序发送的状态通知来调用该函数.
    下边界(protocol)状态。
参数说明:
    ProtocolBindingContext adapter structure指针
    GeneralStatus Status code
    StatusBuffer Status buffer
    StatusBufferSize status buffer大小

返回值:

    无

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    //如果我们在微端口被初始化前得到一个状态指示,忽略它
    //如果SampleIM没有打开,我们不传递状态指示
    if(pAdapt->MiniportHandle != NULL &&
        pAdapt->MPDeviceState == NdisDeviceStateD0 &&
        pAdapt->PTDeviceState == NdisDeviceStateD0 )
    {
        NdisMIndicateStatus(pAdapt->MiniportHandle,
            GeneralStatus,
            StatusBuffer,
            StatusBufferSize);
    }
}
//----------------------------------------------------------------------------------
VOID
PtStatusComplete(
    IN NDIS_HANDLE ProtocolBindingContext
    )
/*++

函数说明:

    这个函数必须提供。NDIS调用该函数来指示状态改变操作已经完成,该状态以前被指示给Status函数.
   
参数说明:

    返回值:

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    //如果我们在微端口被初始化前得到一个状态指示,忽略。
    if(pAdapt->MiniportHandle != NULL &&
        pAdapt->MPDeviceState == NdisDeviceStateD0 &&
        pAdapt->PTDeviceState == NdisDeviceStateD0 )
    {
        NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
    }
}


VOID
PtSendComplete(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNDIS_PACKET Packet,
    IN NDIS_STATUS Status
    )
/*++

函数说明:
    这个函数必须提供。对每个调用Ndis.Send函数传输的数据包,当其返回
    NDIS_STATUS_PENDING作为发送状态时,将调用该函数完成发送操作.如果
    调用Ndis.SendPacket发送一组数据包,那么对于每一个传送给Ndis.SendPacket
    的数据包,该函数将被调用一次.中间层驱动程序只根据发送给该函数的状
    态参数就能够确定Ndis.SendPacket的发送状态参数.

注意:
    我们希望所有的发送发送到二级NIC,但是当我们指示上面的协议时,
    我们需要回复最初的协议希望用来发送的微端口。
       
    Interesting case:
    We wish to send all sends down the secondary NIC. But when we indicate to the protocol above,
    we need to revert back to the original miniport that Protocol wished to use for the Send
   
 参数说明:

   返回值:

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    PNDIS_PACKET Pkt;
    PRSVD Rsvd;

    //
    // Returning the Send on the Primary, will point to itself if there is no bundle
    //返回在主程序中的发送,如果没有绑定则指向它自己
    pAdapt = pAdapt->pPrimaryAdapt;

    Rsvd =(PRSVD)(Packet->ProtocolReserved);
    Pkt = Rsvd->OriginalPkt;


    NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);

    NdisDprFreePacket(Packet);

    NdisMSendComplete(pAdapt->MiniportHandle,
        Pkt,
        Status);
}


VOID
PtTransferDataComplete(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNDIS_PACKET Packet,
    IN NDIS_STATUS Status,
    IN UINT BytesTransferred
    )
   
/*++

函数说明:

    像上面的Send,所有的发送需要在主程序的MiniportHandle中完成。
    如果PT.Receive要调用Ndis.TransferData函数,则必须提供该处理程序.

参数说明:
    ProtocolBindingContext
    Packet 包
    Status 状态
    BytesTransferred 传输的数据字节数

返回值:
   
    无
--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    // Returning the Send on the Primary, will point to itself if there is no LBFO
    //返回在主程序中的发送,如果没有LBFO将指向它自己。
    pAdapt = pAdapt->pPrimaryAdapt;

    if(pAdapt->MiniportHandle)
    {
        NdisMTransferDataComplete(pAdapt->MiniportHandle,
            Packet,
            Status,
            BytesTransferred);
    }
}
//---------------------------------------------------------------------------------
NDIS_STATUS
PtReceive(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_HANDLE MacReceiveContext,
    IN PVOID HeaderBuffer,
    IN UINT HeaderBufferSize,
    IN PVOID LookAheadBuffer,
    IN UINT LookAheadBufferSize,
    IN UINT PacketSize
    )
/*++

函数说明:
    这个函数必须提供。该函数以指向包含网络接收数据的预先分配的缓冲区的指针为参数被调用
    执行.如果该缓冲区包含的不是完整的网络数据包,该函数以数据描述符作为参数,调用
    Ndis.TransferData接收数据包的剩余部分.如果下层驱动程序调用Ndis.MIndicateReceivePacket
    指示接收数据包,那么传给该函数的预先分配的缓冲区的将永远是完整的网络数据包.
    LBFO - need to use primary for all receives

    参数说明:


    返回值:

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    PNDIS_PACKET MyPacket, Packet;
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

    if(!pAdapt->MiniportHandle)
    {
        Status = NDIS_STATUS_FAILURE;
    }
    else do
    {
        //
        // We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
        //

        if(pAdapt->isSecondary)
        {
            DBGPRINT("PASSTHRU GETTING RECIEVES ON SECONDARY/n");
            ASSERT(0);
        }

        //
        // If this was indicated by the miniport below as a packet, then get that packet pointer and indicate
        // it as a packet as well(with appropriate status). This way the OOB stuff is accessible to the
        // transport above us.
        //
        Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
        if(Packet != NULL)
        {
            //
            // Get a packet off the pool and indicate that up
            //
            NdisDprAllocatePacket(&Status,
                &MyPacket,
                pAdapt->RecvPacketPoolHandle);

            if(Status == NDIS_STATUS_SUCCESS)
            {
                MyPacket->Private.Head = Packet->Private.Head;
                MyPacket->Private.Tail = Packet->Private.Tail;

                //
                // Get the original packet(it could be the same packet as one received or a different one
                // based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
                // correctly at the top.
                //
                NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
                NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);

                //
                // Set Packet Flags
                //
                NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

                //
                // Make sure the status is set to NDIS_STATUS_RESOURCES.
                //
                NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);

                NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);

                ASSERT(NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES);
                NdisDprFreePacket(MyPacket);
                break;
            }
        }

        //
        // Fall through if the miniport below us has either not indicated a packet or we could not
        // allocate one
        //
        pAdapt->IndicateRcvComplete = TRUE;
        switch(pAdapt->Medium)
        {
        case NdisMedium802_3:
            NdisMEthIndicateReceive(pAdapt->MiniportHandle,
                MacReceiveContext,
                HeaderBuffer,
                HeaderBufferSize,
                LookAheadBuffer,
                LookAheadBufferSize,
                PacketSize);
            break;

        case NdisMedium802_5:
            NdisMTrIndicateReceive(pAdapt->MiniportHandle,
                MacReceiveContext,
                HeaderBuffer,
                HeaderBufferSize,
                LookAheadBuffer,
                LookAheadBufferSize,
                PacketSize);
            break;

        case NdisMediumFddi:
            NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
                MacReceiveContext,
                HeaderBuffer,
                HeaderBufferSize,
                LookAheadBuffer,
                LookAheadBufferSize,
                PacketSize);
            break;

        default:
            ASSERT(0);
            break;
        }

    } while(FALSE);

    return Status;
}
//----------------------------------------------------------------------------
VOID
PtReceiveComplete(
    IN NDIS_HANDLE ProtocolBindingContext
    )
/*++

函数说明:

    Called by the adapter below us when it is done indicating a batch of received buffers.
   
参数说明:

    ProtocolBindingContext Pointer to our adapter structure.

返回值:

    无

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

    //
    // We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
    //
    if(pAdapt->isSecondary)
    {
        DBGPRINT("PASSTHRU GETTING RECEIVES ON SECONDARY/n");
        ASSERT(0);
    }

    if((pAdapt->MiniportHandle != NULL) && pAdapt->IndicateRcvComplete)
    {
        switch(pAdapt->Medium)
        {
        case NdisMedium802_3:
            NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
            break;

        case NdisMedium802_5:
            NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
            break;

        case NdisMediumFddi:
            NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
            break;

        default:
            ASSERT(0);
            break;
        }
    }
    pAdapt->IndicateRcvComplete = FALSE;
}
//-------------------------------------------------------------------------------------
INT
PtReceivePacket(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNDIS_PACKET Packet       
    )
/*++

参数说明:

    ReceivePacket handler. Called up by the miniport below when it supports NDIS 4.0 style receives.
    Re-package the packet and hand it back to NDIS for protocols above us. The re-package part is
    important since NDIS uses the WrapperReserved part of the packet for its own book-keeping. Also
    the re-packaging works differently when packets flow-up or down. In the up-path(here) the protocol
    reserved is owned by the protocol above. We need to use the miniport reserved here.
   
函数说明:

    ProtocolBindingContext Pointer to our adapter structure.
    Packet - Pointer to the packet
   
返回值:

    == 0 -> We are done with the packet
    != 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    NDIS_STATUS Status;
    PNDIS_PACKET MyPacket;
    PRSVD Resvd;

    if(!pAdapt->MiniportHandle)
    {
        return 0;
    }

    //
    // We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
    //
    if(pAdapt->isSecondary)
    {
        DBGPRINT("PASSTHRU GETTING RECEIVES ON SECONDARY/n");
        ASSERT(0);
    }

    //
    // Get a packet off the pool and indicate that up
    //
    NdisDprAllocatePacket(&Status,
        &MyPacket,
        pAdapt->RecvPacketPoolHandle);

    if(Status == NDIS_STATUS_SUCCESS)
    {
        Resvd =(PRSVD)(MyPacket->MiniportReserved);
        Resvd->OriginalPkt = Packet;

        MyPacket->Private.Head = Packet->Private.Head;
        MyPacket->Private.Tail = Packet->Private.Tail;

        //
        // Get the original packet(it could be the same packet as one received or a different one
        // based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
        // correctly at the top.
        //
        NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));

        //
        // Set Packet Flags
        //
        NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

        Status = NDIS_GET_PACKET_STATUS(Packet);

        NDIS_SET_PACKET_STATUS(MyPacket, Status);
        NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));

        NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);

        if(Status == NDIS_STATUS_RESOURCES)
        {
            NdisDprFreePacket(MyPacket);
        }

        return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
    }
    else
    {
        //
        // We are out of packets. Silently drop it. Alternatively we can deal with it:
        // - By keeping separate send and receive pools
        // - Dynamically allocate more pools as needed and free them when not needed
        //
        return(0);
    }
}
//--------------------------------------------------------------------------------------
NDIS_STATUS
PtPNPHandler(
    IN NDIS_HANDLE ProtocolBindingContext,
    IN PNET_PNP_EVENT pNetPnPEvent
    )   
/*++
函数说明:

    This is the Protocol PNP handlers. All PNP Related OIDS(requests) are routed to this function
    If the Power of the SetPower PNP Event is received, then the new power state is copied to
    the internal state of the Passthru driver. Need to complete all sends and requests before
    returning from this function.
   
参数说明:

    ProtocolBindingContext Pointer to our adapter structure.
    pNetPnPEvent Pointer to a Net_PnP_Event
   
返回值:

    NDIS_STATUS_SUCCESS: as we do not do much here

--*/
{
    PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

    DBGPRINT ("PtPnPHandler");

    //
    // This will happen when all entities in the system need to be notified
    //

    switch(pNetPnPEvent->NetEvent)
    {
    case NetEventSetPower :
        Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
        break;

    case NetEventReconfigure :
        Status = PtPnPNetEventReconfigure(pAdapt, (PCWSTR)pNetPnPEvent->Buffer);
        break;

    default :
        Status = NDIS_STATUS_SUCCESS;
        break;
    }

    return Status;
}
//----------------------------------------------------------------------------------
NDIS_STATUS
PtPnPNetEventReconfigure(
    IN PADAPT pAdapt,
    IN PCWSTR pBundleString
    )
/*++
函数说明:
    This is the function that will be called by the PNP handler whenever a PNPNetEventReconfigure happens
    Protocol will read the Bundle from the registry.

    if pAdapt is NULL, then a global reconfig event has been issued. We should use this to ensure that our protocol
    is bound to its underlying miniports

    Simple Algorithm for Bundles:
    If bundleId was not changed then exit.   
   
    if pAdapt is the secondary of a bundle, promote pAdapt.
    If pAdapt is the primary of a bundle, promote the secondary miniport
   
    Now check to see if the new bundleId causes us to be a part of another bundle
    Walk through the list attach pAdapt to a miniport that has the same bundleId.
   
    If there is a Device Instantiated with the same bundle ID then we will become the secondary of that miniport

参数说明:

    ProtocolBindingContext指向adapter structure.
   
返回值:
   
    NDIS_STATUS_SUCCESS: 如果不在这里做很多处理。as we do not do much here

--*/
{
    NDIS_STATUS BundleStatus = NDIS_STATUS_SUCCESS;
    NDIS_STRING NewBundleUniString;


    if(pAdapt == NULL)
    {
        NdisReEnumerateProtocolBindings (ProtHandle);
        return BundleStatus;
    }

    if (pBundleString == NULL)
    {
        return BundleStatus;
    }

    NdisInitUnicodeString( &NewBundleUniString, pBundleString);


    do
    {
        //
        // If the bundle Identifier was not changed, do not do anything
        //
        if(NdisEqualUnicodeString(&NewBundleUniString, &pAdapt->BundleUniString, TRUE))
        {
            break;
        }

        //
        // We have a new bundle id , copy it and do the necessary bundling work
        //
        RtlCopyUnicodeString(&pAdapt->BundleUniString , &NewBundleUniString);

        //
        // If we are part of a bundle and our bundle id was changed, either the primary or the secondary
        // will get promoted
        // If we are the secondary of a bundle promote ourselves
        //
        if(pAdapt->isSecondary)
        {
            PADAPT pPrimaryAdapt = pAdapt->pPrimaryAdapt;

            BundleStatus = MPPromoteSecondary(pAdapt);

            if(BundleStatus != NDIS_STATUS_SUCCESS)
            {
                ASSERT(0);
                break;
            }

            //
            // resetting all the internal variables of the primary Adapter structure
            //
            pPrimaryAdapt->pPrimaryAdapt = pPrimaryAdapt;
            pPrimaryAdapt->pSecondaryAdapt = pPrimaryAdapt;
            pPrimaryAdapt->isSecondary = FALSE;
        }
        else
        {
            if(pAdapt->pSecondaryAdapt != pAdapt)
            {
                BundleStatus = MPPromoteSecondary(pAdapt->pSecondaryAdapt);
                if(BundleStatus != NDIS_STATUS_SUCCESS)
                {
                    ASSERT(0);
                    break;
                }

                //
                // resetting all our internal variables
                //
                pAdapt->pSecondaryAdapt = pAdapt;
                pAdapt->pPrimaryAdapt = pAdapt;
                pAdapt->isSecondary = FALSE ;
            }
        }

        BundleStatus = MPBundleSearchAndSetSecondary(pAdapt);

    } while(FALSE) ;

    DBGPRINT("<==PtPNPNetEventReconfigure/n");

    return BundleStatus;
}
//--------------------------------------------------------------------------------------
NDIS_STATUS
PtPnPNetEventSetPower(
    IN PADAPT pAdapt,
    IN PNET_PNP_EVENT pNetPnPEvent
    )
/*++
函数说明:
    把电源状态设置成请求水平。等待所有的正在处理的发送和请求
参数说明:
   
    pAdapt - adpater structure指针
    pNetPnpEvent - The Net Pnp Event. 包含新的设备状态。
   
返回值:
   
    NDIS_STATUS_SUCCESS: 如果设备成功的改变它的电源状态。
--*/
{
    PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
    NDIS_DEVICE_POWER_STATE PrevDeviceState = pAdapt->PTDeviceState;
    NDIS_STATUS Status ;

    //设置内部设备状态,这个支撑所有新的发送或接收。
    pAdapt->PTDeviceState = *pDeviceState;
    //如果正在被送到standby(if we are being sent to standby),阻塞正在处理的请求和发送
    if(*pDeviceState > NdisDeviceStateD0)
    {
        //如果物理微端口将要备用(standby),所有到来的请求无效。
        if (PrevDeviceState == NdisDeviceStateD0)
        {
            pAdapt->StandingBy = TRUE;
        }

        while(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) != 0)
        {
            //等待到正在处理的发送完成。
            NdisMSleep(10);
        }

        while(pAdapt->OutstandingRequests == TRUE)
        {
            //等待到正在处理的请求完成。
            NdisMSleep(10);
        }

        ASSERT(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) == 0);
        ASSERT(pAdapt->OutstandingRequests == FALSE);
    }
    else
    {
        //协议被打开,一个待处理请求必须结束
        if (pAdapt->QueuedRequest == TRUE)
        {

            pAdapt->QueuedRequest = FALSE;

            NdisRequest(&Status,
                pAdapt->BindingHandle,
                &pAdapt->Request);

            //下面的微端口同步地完成同步请求,IM需要完成它早期未决的请求。

            if (Status != NDIS_STATUS_PENDING)
            {
                PtRequestComplete(pAdapt,
                    &pAdapt->Request,
                    Status);
            }

        }
        //如果物理微端口功率正在增大(is powering up)(从低功率到D0),清空标志
        if (PrevDeviceState > NdisDeviceStateD0)
        {
            pAdapt->StandingBy = FALSE;
        }


    }

    Status = NDIS_STATUS_SUCCESS;

    return Status;
}