您的位置:首页 > 其它

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

2011-02-17 16:55 465 查看
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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: