【转帖】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);
这个问题,大部分学习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中间层驱动自己发包的实现(经典问题)
- 【转帖】Ndis中间层驱动自己发包的实现(经典问题) 收藏
- 【转帖】NAT在NDIS中间层驱动中的实现
- 关于 NDIS 中间层驱动的实现方案。。。
- NAT在NDIS中间层驱动中的实现
- NAT在NDIS中间层驱动中的实现
- NAT在NDIS中间层驱动中的实现
- NDIS中间层驱动实现截获数据包、包过滤功能
- 经典线程同步问题(生产者&消费者)--Java实现
- java 自己实现项目一键全转码 解决文件乱码问题
- trim方法(自己实现,存在问题tab留下的空格无法去掉)
- 用NUnit2.1简单实现.net的测试驱动开发(TDD)---转帖
- 经典排序算法c++实现,自己复习,不断更新
- NDIS 中间层驱动的任何注意事项
- 如何实现调用自己实现的网络驱动?
- 经典面试编程题--atoi()函数的实现(就是模拟手算,核心代码就一句total = 10 * total + (c - '0'); 但是要注意正负号、溢出等问题)
- 4clojure第55个问题:实现自己的序列频率统计函数
- NDIS中间层驱动开发在Win7系统下和Windows XP系统下的区别
- NDIS中间层驱动开发在Win7系统下和Windows XP系统下的区别
- java多线程总结六:经典生产者消费者问题实现