kkkhmy
驱动牛犊
驱动牛犊
  • 注册日期2008-04-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分23分
  • 威望198点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
阅读:4049回复:8

passthru中自定义发送函数 到ndissend蓝屏 实在想不出哪里问题 版主大人响应下吧……

楼主#
更多 发布于:2008-12-25 18:08
实现了数据从驱动传递上应用层,在应用层修改后的数据返回给驱动层。

为了处理从应用层传入的数据所以定义了两个函数,通过应用层传入的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周了……
zhaock
驱动太牛
驱动太牛
  • 注册日期2002-01-26
  • 最后登录2018-06-02
  • 粉丝3
  • 关注2
  • 积分73328分
  • 威望362317点
  • 贡献值1点
  • 好评度226点
  • 原创分0分
  • 专家分0分
  • 社区居民
沙发#
发布于:2008-12-26 11:04
在sendcomplete的时候,应该先NdisFreeBuffer( wodebaocunchuqi );在NdisFreeMemory,其他的没看出问题。改过来试试看
kkkhmy
驱动牛犊
驱动牛犊
  • 注册日期2008-04-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分23分
  • 威望198点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
板凳#
发布于: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之类的错误?
            
zhaock
驱动太牛
驱动太牛
  • 注册日期2002-01-26
  • 最后登录2018-06-02
  • 粉丝3
  • 关注2
  • 积分73328分
  • 威望362317点
  • 贡献值1点
  • 好评度226点
  • 原创分0分
  • 专家分0分
  • 社区居民
地板#
发布于:2008-12-29 17:22
1.先去掉这个标志看看NDIS_FLAGS_DONT_LOOPBACK
2.释放资源的顺序是先NdisFreeBuffer,后NdisFreeMemory, 这个肯定不能相反
3.蓝屏后windbg !analyze -v 分析转储文件,把内容贴出来
kkkhmy
驱动牛犊
驱动牛犊
  • 注册日期2008-04-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分23分
  • 威望198点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
地下室#
发布于: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 );

这个顺序也能够正常释放而不蓝屏……  不知道是怎么回事……
zhaock
驱动太牛
驱动太牛
  • 注册日期2002-01-26
  • 最后登录2018-06-02
  • 粉丝3
  • 关注2
  • 积分73328分
  • 威望362317点
  • 贡献值1点
  • 好评度226点
  • 原创分0分
  • 专家分0分
  • 社区居民
5楼#
发布于:2008-12-29 21:49
1.呵呵,我也被误导了,没有留意你可能是ndis 5.1那部分代码出的问题,发包蓝屏几乎都是sendcomplete的时候,没有判断是不是自己的包,都往上层协议送导致的。
2.另外NdisFreeBuffer就是IoFreeMdl,这部分其实没有实际操作你分配的nonpaged 内存,所以颠倒顺序也没有问题。但是如果你不知道mdl内部是如何实现的,还是按照顺序做,肯定不会出问题
kkkhmy
驱动牛犊
驱动牛犊
  • 注册日期2008-04-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分23分
  • 威望198点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2008-12-31 10:25
原来如此。多谢版主大人解惑。呵呵
aajuu
驱动牛犊
驱动牛犊
  • 注册日期2009-01-08
  • 最后登录2009-07-14
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望81点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2009-04-28 09:27
哇,太感谢了,
也解决了我做nat时遇到同样问题的困扰,
真是非常感谢楼上的前辈们啊
cricketol
驱动牛犊
驱动牛犊
  • 注册日期2010-03-07
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分17分
  • 威望121点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2010-03-16 21:45
楼主就是救世主啊
拯救了无数新手,include me
游客

返回顶部