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

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

 

这个问题,大部分学习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);

你可能感兴趣的:(【转帖】Ndis中间层驱动自己发包的实现(经典问题))