dshadow79
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2006-04-10
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望2点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
阅读:1998回复:7

如何用ndis实现包的转发?

楼主#
更多 发布于:2003-04-17 16:24
想做透明的防火墙,需要将一块网卡传来的数据发送到另外一块网卡上.我在PtReceive里调用下面这个过程,将包发送到其他网卡.可是在NdisSend调用的时候就死机,不知道是不是我的包建立错误,哪位大哥指教一下......

void IPF_BroadcastData
(
IN NDIS_HANDLE MiniportAdapterHandle,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize
)
{
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
PADAPT p = pAdaptList;

while( p )
{
if( p->MiniportHandle != MiniportAdapterHandle )
{
NdisDprAllocatePacket( &Status, &MyPacket, p->SendPacketPoolHandle );
if( Status == NDIS_STATUS_SUCCESS )
{
PSEND_RSVD Resvd;

PNDIS_BUFFER pHeaderBuffer, pDataBuffer;
NdisAllocateBuffer( &Status, &pHeaderBuffer, p->SendBufferPoolHandle, HeaderBuffer, HeaderBufferSize );
NdisChainBufferAtBack( MyPacket, pHeaderBuffer );
NdisAllocateBuffer( &Status, &pDataBuffer, p->SendBufferPoolHandle, LookAheadBuffer, LookAheadBufferSize );
NdisChainBufferAtBack( MyPacket, pDataBuffer );

MyPacket->Private.Head->Next = NULL;
MyPacket->Private.Tail = NULL;

Resvd = ( PSEND_RSVD )( MyPacket->MiniportReserved );
Resvd->OriginalPkt = NULL;
NDIS_SET_PACKET_HEADER_SIZE( MyPacket, HeaderBufferSize );
NdisSetPacketFlags( MyPacket, ( UINT )p->Medium );

NdisSend( &Status, p->BindingHandle, MyPacket );
DbgPrint(\"Receive on %X, send to %X ... status = %d\\n\",MiniportAdapterHandle,p->MiniportHandle,Status);

NdisFreeBuffer( pDataBuffer );
NdisFreeBuffer( pHeaderBuffer );
NdisDprFreePacket( MyPacket );
}
}

p = p->Next;
}
}

[编辑 -  4/17/03 by  dshadow79]
dshadow79
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2006-04-10
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望2点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2003-04-17 17:49
谁指点一下啊,急死了……
dshadow79
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2006-04-10
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望2点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-04-18 15:24
没有人知道吗?
zuozi
驱动牛犊
驱动牛犊
  • 注册日期2003-03-24
  • 最后登录2004-09-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-04-18 16:28
呵呵,以前有个哥们和你做过类似的工作,你去找一下吧,好象是说由于NDIS_SEND返回pending的时候需要调用ptSendComplete来释放你分配的各种资源,然而默认的ptSenComplete里面释放资源的方法是和MpSend里面的分配方法配套的,所以需要把这两个函数都改掉。

另外,我有一个弱智问题:为什么转发包的时候要用两块网卡呢,一块不可以么?
jinsun
驱动牛犊
驱动牛犊
  • 注册日期2003-11-30
  • 最后登录2003-12-14
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2003-12-01 21:56
老兄的问题解决了,我也遇到同样的问题,可以将你的代码与我一份吗?
SharpShooter
驱动小牛
驱动小牛
  • 注册日期2002-04-07
  • 最后登录2013-07-05
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望40点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2003-12-02 09:39
这种情况最好起个系统线程专门负责发送,而接收函数里只是把数据包挂在一个待处理的链上,这样不但可以从事务上分得很清楚,也会带来一些效率的提升,以及更好的出错处理机制.

发送线程从链上Pop数据包下来进行发送,考虑的更合理些,使用标准的生产者消费者模型是最好,简单点,一个双链表也没有什么问题.

如果允许丢包的话,可以在发送线程处理不过来而导致循环链表满的时候,将链表头的包丢弃,这样即便发送出现问题,也不会影响接收.
写驱动不如买足彩!!
SharpShooter
驱动小牛
驱动小牛
  • 注册日期2002-04-07
  • 最后登录2013-07-05
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望40点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2003-12-02 09:43
另外,个人经验,使用系统线程的时候最好自己起,使用ExInitializeWorkItem和ExQueueWorkItem处理好像不是什么好主意,效率会严重降低/参数使用CriticalWorkQueue的情况下/.
写驱动不如买足彩!!
dshadow79
驱动牛犊
驱动牛犊
  • 注册日期2002-09-29
  • 最后登录2006-04-10
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望2点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2003-12-03 00:17
这么老的帖子也能被翻出来……

那个东西是商业产品的一部分,代码不好公开,我只把自己遇到的问题说一下,实际代码还得自己写咯

先是发送包的时候,一定要设置包的标志,在xp下要设置NDIS_FLAGS_DONT_LOOPBACK标志,2k下的标志没有公开,得自己定义
#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x00000400。这些标志使得ndis不将这些包loopback(关于什么是loopback,自己查一下吧)
如果不设置这些标志,发送的包又返回提交上来,再发送再提交,会堆栈溢出的

再就是在PtReceive/PtReceivePacket里面,我推荐建立全新的包然后把数据拷贝出来,再发送,这样不会占用底层的rfd,而且统一处理起来也比较方便。如果直接使用底层提交上来的包,实际使用的也就是底层miniport的rfd(receive frame descriptor),这个数量是很有限的,发送释放不及的话不见得效率高,而且逻辑上n麻烦,得考虑n多因素。PtReceive/PtReceivePacket的返回值也值得注意,不然还得return packet

然后就是在PtSendComplete里释放返回的包,这个没啥说的了

还有,如果想做成透明方式,单单实现上面是不够的。驱动两边的主机互相发送信息,mac地址跟驱动绑定的网卡完全无关,所以不会提交上来由驱动转发--这个常规解决方法是来个路由,还有个偷懒的办法,就是把驱动绑定的网卡全设成混杂

说的很罗索,呵呵,都是自己摸索的,希望对你有用 :cool:
游客

返回顶部