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

    技术2026-01-20  4

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

    最新回复(0)