NDIS IM 驱动那些事情

  最近不知道为什么开始学习windows NDIS驱动开发,用的是寒江独钓的例子,其实他的改的代码也就一点点,说的有用的东西也就那么多,不过还是感谢他出了这么一本书,不然这真的就没有一本稍微好一点的书籍来说windows 的NDIS书籍了。

  这方面的知识貌似大家都不太愿意说,我在网上找了好久无非就是那几篇经典的例子,不过网上代码有点错误有点问题,而且核心都不原因讲解。。

比喻大家都会遇到问题,怎么在NDIS中间层发送自定义数据包的问题? 一般我们发送都会蓝屏,网上有类似的文章。

http://blog.csdn.net/floweronwarmbed/article/details/3202065

 

NDIS_STATUS

MySendPacket (

   NDIS_HANDLE     NdisBindingHandle,

   NDIS_HANDLE     NdisSendPacketPool,

   PVOID           pBuffer,

   ULONG           dwBufferLength

   )

{

   NDIS_STATUS     status;

   PNDIS_PACKET    pSendPacket = NULL;

   PNDIS_BUFFER    pSendPacketBuffer = NULL;

   PUCHAR          pSendBuffer = NULL;

   ULONG           dwSendBufferLength; 

   NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress;

   PSEND_RSVD      SendRsvd = NULL;



   if (!NdisBindingHandle)

       return NDIS_STATUS_FAILURE;



   if (!pBuffer)

       return NDIS_STATUS_FAILURE;



   if (dwBufferLength > ETH_MAX_PACKET_SIZE)

       return NDIS_STATUS_FAILURE;



   HighestAcceptableAddress.QuadPart = -1;

   dwSendBufferLength = max(dwBufferLength, ETH_MIN_PACKET_SIZE);



   status = NdisAllocateMemory(&pSendBuffer, dwSendBufferLength, 0, HighestAcceptableAddress);

   if (status != NDIS_STATUS_SUCCESS)

   {

       return status;

   }



   RtlZeroMemory(pSendBuffer, dwSendBufferLength);

   RtlMoveMemory(pSendBuffer, pBuffer, dwSendBufferLength);



   NdisAllocatePacket(&status, &pSendPacket, NdisSendPacketPool);

   if (status != NDIS_STATUS_SUCCESS)

   {

       NdisFreeMemory(pSendBuffer, dwSendBufferLength, 0);

       

       return status;

   }



   NdisAllocateBuffer( &status, 

                       &pSendPacketBuffer, 

                       NdisSendPacketPool, 

                       pSendBuffer, 

                       dwSendBufferLength );

   if (status != NDIS_STATUS_SUCCESS)

   {

       NdisFreeMemory(pSendBuffer, dwSendBufferLength, 0);

       NdisDprFreePacket(pSendPacket);



       return status;

   }



   NdisChainBufferAtFront(pSendPacket, pSendPacketBuffer);



   SendRsvd = (PSEND_RSVD)(pSendPacket->ProtocolReserved); 

   SendRsvd->OriginalPkt = NULL; //注意这里



   pSendPacket->Private.Head->Next=NULL; 

   pSendPacket->Private.Tail=NULL; 



   //NDIS_SET_PACKET_HEADER_SIZE(pSendPacket, 14);

   NdisSetPacketFlags(pSendPacket, NDIS_FLAGS_DONT_LOOPBACK);



   NdisSend(&status, NdisBindingHandle, pSendPacket);

   if (status != STATUS_PENDING)

   {

       NdisUnchainBufferAtFront(pSendPacket ,&pSendPacketBuffer); 

       NdisQueryBufferSafe( pSendPacketBuffer, 

                            (PVOID *)&pSendBuffer, 

                            &dwSendBufferLength, 

                            HighPagePriority );

       NdisFreeBuffer(pSendPacketBuffer); 

       NdisFreeMemory(pSendBuffer, dwSendBufferLength, 0); 

       NdisDprFreePacket(pSendPacket);

   }



   return status;

}





注意:NdisSend如果是立刻完成,没有Pending的话,你需要在NdisSend返回后释放掉刚才分配的资源,否则是Pending的话,我们就要等发生包这个事件真正完成是的Complete例程里面去释放分配的资源。



在函数PtSendComplete中:

PSEND_RSVD        SendRsvd;

SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);

Pkt = SendRsvd->OriginalPkt;

// ProtocolReserved是个可以自己放自己数据的地方, passthru用这个存放原始包的地址, 而我们自己构造包的时候把SendRsvd->OriginalPkt设为了NULL,所以很容易判断出那个已完成发送的包是passtru的,哪些是我们构造的



       if (!Pkt )

       {

           NdisUnchainBufferAtFront(Packet, &pMySendPacketBuffer);



           if (pMySendPacketBuffer)

           {

               NdisQueryBufferSafe( pMySendPacketBuffer, 

                                    (PVOID *)&pMySendBuffer, 

                                    &dwMySendBufferLength, 

                                    HighPagePriority ); 

               if (pMySendBuffer && dwMySendBufferLength)

               {

                   NdisFreeMemory(pMySendBuffer, dwMySendBufferLength, 0);

               }



               NdisFreeBuffer( pMySendPacketBuffer );

           }



            NdisDprFreePacket(Packet);

但这里代码比较模糊也没有说明蓝屏的本质,只是PtSendComplete里面要释放原因。。。

其实这里我测试得出,其实你释放不释放最多内存泄漏,比喻你的程序内存泄漏基本不会马上崩溃,应用程序崩溃一般是我们内存越界,类似系统不过是一个最大的应用程序。然后自己也在网上看到类似不要调用NdisMSendComplete类似的东西,这个API 通知上层驱动释放资源 等等问题,显然我NidsSend是在自己中间层调用根本没有上层,那么上层怎么释放呢!!显然就报错嘛?蓝屏还用说吗??我发现驱动蓝屏比较恐怖的事情,这2周学习感觉还好,只要你内存操作注意点时候,基本上不会蓝屏,内存泄漏感觉只会影响驱动稳定性。

  貌似上面的MySendPacket 里面那个

NdisAllocateBuffer( &status, 

                       &pSendPacketBuffer, 

                       NdisSendPacketPool, 

                       pSendBuffer, 

                       dwSendBufferLength );
这里应该是错误,
NdisSendPacketPool 这个句柄明显是分配Packet。
我看一下NdisAllocateBuffer 句柄应该是自己调用的VOID
NdisAllocateBufferPool(
OUT PNDIS_STATUS Status,
OUT PNDIS_HANDLE PoolHandle,
IN UINT NumberOfDescriptors
);
。。
我不知道是不是他们估计要把代码写错,如果能混用的话感觉微软就没有必要提供NdisSendPacketPool的函数了。
等我自己一个项目整体完成了,然后把代码分享出来。-----------》实现那种局域网管理软件使用ARP欺骗进行管理的核心功能。

前几天看到一个厉害人吧,感觉能力比较强,看他的文章他非常熟悉linux的内核。然后开发起windows驱动非常顺手,看来linux真是c/c++的乐园吧。。。
有时间还得仔细学习学习。



最后我贴一下我写的ptComple的函数的API 其实很简单了。。
VOID

PtSendComplete(

    IN  NDIS_HANDLE            ProtocolBindingContext,

    IN  PNDIS_PACKET           Packet,

    IN  NDIS_STATUS            Status

    )

/*++



Routine Description:



    Called by NDIS when the miniport below had completed a send. We should

    complete the corresponding upper-edge send this represents.



Arguments:



    ProtocolBindingContext - Points to ADAPT structure

    Packet - Low level packet being completed

    Status - status of send



Return Value:



    None



--*/

{

    PADAPT            pAdapt = (PADAPT)ProtocolBindingContext;

    PNDIS_PACKET      Pkt; 

    NDIS_HANDLE       PoolHandle;



    PSEND_RSVD        tempRsvd;

    PNDIS_BUFFER      pMySendPacketBuffer = NULL;

    UINT              dwMySendBufferLength = 0;

    PVOID              pMySendBuffer = NULL;



    tempRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);

    Pkt = tempRsvd->OriginalPkt;



    if (Pkt == (PNDIS_PACKET)1 )

    {

        NdisUnchainBufferAtFront(Packet, &pMySendPacketBuffer);

        if (pMySendPacketBuffer)

        {

            NdisQueryBufferSafe( pMySendPacketBuffer, 

                (PVOID *)&pMySendBuffer, 

                &dwMySendBufferLength, 

                HighPagePriority ); 

            if (pMySendBuffer && dwMySendBufferLength)

            {

                NdisFreeMemory(pMySendBuffer, dwMySendBufferLength, 0);

            }



            NdisFreeBuffer( pMySendPacketBuffer );



            NdisFreePacket(Packet);

        }

        return;

    }







#ifdef NDIS51

    //

    // Packet stacking:

    //

    // Determine if the packet we are completing is the one we allocated. If so, then

    // get the original packet from the reserved area and completed it and free the

    // allocated packet. If this is the packet that was sent down to us, then just

    // complete it

    //

    //DbgPrint("我在NDIS51发送完了");

    PoolHandle = NdisGetPoolFromPacket(Packet);

    if (PoolHandle != pAdapt->SendPacketPoolHandle)

    {

        //

        // We had passed down a packet belonging to the protocol above us.

        //

        // DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));



        

        NdisMSendComplete(pAdapt->MiniportHandle,

                          Packet,

                          Status);

    }

    else

#endif // NDIS51

    {



        

        PSEND_RSVD        SendRsvd;



        SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);

        Pkt = SendRsvd->OriginalPkt;



        //DbgPrint("我没有在NDIS51调用哦,熊熊你知道了蓝屏是为什么了");

    

#ifndef WIN9X

        NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);

#endif



    

        NdisDprFreePacket(Packet);



        NdisMSendComplete(pAdapt->MiniportHandle,

                                 Pkt,

                                 Status);

    }

    //

    // Decrease the outstanding send count

    //

    ADAPT_DECR_PENDING_SENDS(pAdapt);

}       

 

你可能感兴趣的:(DI)