分享

【转帖】Ndis中间层驱动自己发包的实现(经典问题)

 tuohuang0303 2011-04-19
 这个问题,大部分学习Ndis中间层的人都会去思考,算是一个比较经典的问题了。
到论坛上问,别人只会告诉你大概的方法和步骤,这里贴出具体的代码,希望对研究Ndis中间层的哥们有些帮助:

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);
       }

http://blog.csdn.net/floweronwarmbed/archive/2008/11/01/3202065.aspx

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多