阅读:4049回复:8
passthru中自定义发送函数 到ndissend蓝屏 实在想不出哪里问题 版主大人响应下吧……
实现了数据从驱动传递上应用层,在应用层修改后的数据返回给驱动层。
为了处理从应用层传入的数据所以定义了两个函数,通过应用层传入的irp控制, 一个用于接收并按照正常流程向上传递,一个用于接收并向外发送 接收函数用NdisMIndicateReceivePacket很简单就达到目的。 但是在发送的时候一到ndissend就蓝屏, 曾经尝试过修改irql,不过还是蓝屏。 使用的系统是win2003 //添加发送函数 int Sev_Ndissend(int num) /*主要实现存入缓冲区包的外发送 输入:应用层提供的缓冲区编号 返回值: */ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PADAPT pAdapt; //适配器句柄通过系统的接收发送函数来的 PNDIS_PACKET MyPacket = NULL; PNDIS_BUFFER MyPacketcache = NULL; PUCHAR Mypacketbuf = NULL; int Sev_User_Cache_num_s; int Sev_Data_Provisional_s; PZoDatshuju Sev_Data_Send_cache; PNDIS_PACKET_EXTENSION Sev_extension = NULL; PRECV_RSVD RecvRsvd; unsigned long i; //KIRQL Sev_Irql = 0;//这个是看了论坛里某位前辈的文章,以为是irql问题 pAdapt = Sev_Data_pAdaptList; Sev_Data_Send_cache = (PZoDatshuju)SystemVirtualAddress; Sev_User_Cache_num_s = num; if(Sev_User_Cache_num_s > 1) Sev_Data_Provisional_s = Sev_User_Cache_num_s - 1; if(Sev_User_Cache_num_s == 1) Sev_Data_Provisional_s = 9998;//上面几行是处理应用层传入的数据编号 Status = NdisAllocateMemory(&Mypacketbuf, 2000, 0, HighestAcceptableMax);//分配内存 RtlZeroMemory(Mypacketbuf,2000);//初始化内存 if (Status != NDIS_STATUS_SUCCESS) return Status; NdisMoveMemory(Mypacketbuf, Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].yitaihead, Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].datasizeofall); //这个是长度 //将自己的数据复制出来,整包,没有问题,包括校验,IP,MAC都解开看过。 NdisAllocatePacket(&Status, &MyPacket, pAdapt->SendPacketPoolHandle); if (Status != NDIS_STATUS_SUCCESS) { NdisFreeMemory(Mypacketbuf, Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].datasizeofal, 0); return Status; }//没成功就释放 NdisAllocateBuffer(&Status, &MyPacketcache, pAdapt->SendPacketPoolHandle, Mypacketbuf, Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].datasizeofall); i = Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].datasizeofall; if (Status != NDIS_STATUS_SUCCESS) { NdisFreeMemory(Mypacketbuf, Sev_Data_Send_cache->datshuju[Sev_User_Cache_num_s].datasizeofall, 0); NdisFreePacket(MyPacket); return Status; }//同上 NdisChainBufferAtFront(MyPacket, MyPacketcache); if(pAdaptList->MPDeviceState>NdisDeviceStateD0)//如果微端口处于低能状态,不能发送此包 { NdisReleaseSpinLock(&pAdaptList->Lock); Status = NDIS_STATUS_FAILURE; DBGPRINT(("如果微端口处于低能状态,不能发送此包\n")); return 0; }//本来是没有这段的不过后来看了些例子还是加上了 RecvRsvd = (PRECV_RSVD)(MyPacket->ProtocolReserved); RecvRsvd->OriginalPkt = (PNDIS_PACKET)1; //给自己的包一个标志 MyPacket->Private.Head->Next = NULL; MyPacket->Private.Tail = NULL; NdisGetPacketFlags(MyPacket) = NDIS_FLAGS_DONT_LOOPBACK; //KeRaiseIrql(DISPATCH_LEVEL,&Sev_Irql);//提升级别,级别是提升了,不过后来看了下貌似没用? //DbgPrint("查看自定义发送函数irql级别:%d",KeGetCurrentIrql()); NdisSend(&Status, pAdapt->BindingHandle, MyPacket);//到这里就蓝屏了…………想了很多办法,统统无效 //有点想吐血的冲动…… //KeLowerIrql(Sev_Irql); // NdisMIndicateReceivePacket(pAdapt->MiniportHandle,&MyPacket,1); //本来打算是修改了IP和MAC地址,看看能不能 //直接传到上层去,让系统直接转发走,结果是,上层确实收到了,但是没有转发。 if (Status != NDIS_STATUS_PENDING) { NdisUnchainBufferAtFront(MyPacket ,&MyPacketcache); NdisQueryBufferSafe( MyPacketcache, (PVOID *)&Mypacketbuf, &i, 32 ); NdisFreeBuffer(MyPacketcache); NdisFreeMemory(Mypacketbuf, i, 0); NdisFreePacket(MyPacket); } return Status;//其实返回值是没有作用的,只是方便出错退出…… } 下面是PtSendComplete VOID PtSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status ) { PADAPT pAdapt = (PADAPT)ProtocolBindingContext; PNDIS_PACKET Pkt; NDIS_HANDLE PoolHandle; PNDIS_BUFFER wodebaocunchuqi=NULL; PUCHAR wodecunchuqi=NULL; ULONG wodecunchuqichangdu; #ifdef NDIS51 PoolHandle = NdisGetPoolFromPacket(Packet); if (PoolHandle != pAdapt->SendPacketPoolHandle) { NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); } else #endif // NDIS51 { PSEND_RSVD SendRsvd; SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved); Pkt = SendRsvd->OriginalPkt; #ifndef WIN9X NdisIMCopySendCompletePerPacketInfo (Pkt, Packet); #endif //上面的是系统的,下面的是自己改的 if(Pkt != (PNDIS_PACKET)1) { NdisDprFreePacket(Packet); NdisMSendComplete(pAdapt->MiniportHandle, Pkt, Status); }else { DbgPrint("已经进入到ptsendcomplete"); NdisUnchainBufferAtFront(Packet, &wodebaocunchuqi); if(wodebaocunchuqi) { NdisQueryBufferSafe( wodebaocunchuqi, &wodecunchuqi, &wodecunchuqichangdu, 32); if(wodecunchuqi&&wodecunchuqichangdu) { NdisFreeMemory(wodecunchuqi, wodecunchuqichangdu, 0); } NdisFreeBuffer( wodebaocunchuqi ); } NdisDprFreePacket(Packet); } } } 整个程序除了ndissend发送自组包出问题以外,其他都能正常使用…… 版主大人,诸位高手~快上线来指点下吧,我被这个问题恶心了2周了…… |
|
沙发#
发布于:2008-12-26 11:04
在sendcomplete的时候,应该先NdisFreeBuffer( wodebaocunchuqi );在NdisFreeMemory,其他的没看出问题。改过来试试看
|
|
板凳#
发布于:2008-12-29 11:02
if(wodecunchuqi&&wodecunchuqichangdu)
{ NdisFreeBuffer( wodebaocunchuqi ); NdisFreeMemory(wodecunchuqi, wodecunchuqichangdu, 0); }else { NdisFreeBuffer( wodebaocunchuqi ); } 这样改对不对啊?版主大人…… 这样改要蓝屏…… 我是在DispatchTable[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl; 的MydrvDispatchIoctl函数里面调用这个发包函数的,通过应用层传入的IRP控制的,会不会出现诸如irql之类的错误? |
|
地板#
发布于:2008-12-29 17:22
1.先去掉这个标志看看NDIS_FLAGS_DONT_LOOPBACK
2.释放资源的顺序是先NdisFreeBuffer,后NdisFreeMemory, 这个肯定不能相反 3.蓝屏后windbg !analyze -v 分析转储文件,把内容贴出来 |
|
地下室#
发布于:2008-12-29 19:32
多谢版主大人关注
问题已经解决,如下: 在2003系统,多网卡情况下,PtSendComplete执行的下面这段内容,而没有执行到后面的分析自定义包标志的地方,所以必然蓝屏………… #ifdef NDIS51 PoolHandle = NdisGetPoolFromPacket(Packet); if (PoolHandle != pAdapt->SendPacketPoolHandle) { NdisMSendComplete(pAdapt->MiniportHandle, Packet, Status); } else #endif // NDIS51 解决办法也很简单,只需要在函数开头分辨是否自定义包,分别采用自己的和系统的释放语句就可以了…… 语句本身是没有问题的…… 还有一点,版主大人,按照 NdisQueryBufferSafe( wodebaocunchuqi, &wodecunchuqi, &wodecunchuqichangdu, 32); if(wodecunchuqi&&wodecunchuqichangdu) { NdisFreeMemory(wodecunchuqi, wodecunchuqichangdu, 0); } NdisFreeBuffer( wodebaocunchuqi ); 这个顺序也能够正常释放而不蓝屏…… 不知道是怎么回事…… |
|
5楼#
发布于:2008-12-29 21:49
1.呵呵,我也被误导了,没有留意你可能是ndis 5.1那部分代码出的问题,发包蓝屏几乎都是sendcomplete的时候,没有判断是不是自己的包,都往上层协议送导致的。
2.另外NdisFreeBuffer就是IoFreeMdl,这部分其实没有实际操作你分配的nonpaged 内存,所以颠倒顺序也没有问题。但是如果你不知道mdl内部是如何实现的,还是按照顺序做,肯定不会出问题 |
|
6楼#
发布于:2008-12-31 10:25
原来如此。多谢版主大人解惑。呵呵
|
|
7楼#
发布于:2009-04-28 09:27
哇,太感谢了,
也解决了我做nat时遇到同样问题的困扰, 真是非常感谢楼上的前辈们啊 |
|
8楼#
发布于:2010-03-16 21:45
楼主就是救世主啊
拯救了无数新手,include me |
|