Filter发送OID请求[解决蓝屏]

想从Filter发送一个OID请求到Miniport.

 case IOCTL_FILTER_CREATE_NEW_MAC: //Add by leyond to request miniport to create a new MAC
        InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
        InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
        OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
		InfoLength = sizeof(USHORT);

        if(InfoLength < InputBufferLength){
		  InfoLength =  InputBufferLength;
		}
		pInfo = InputBuffer;
		DEBUGP(DL_TEST,("The input length is %u, and inputdata is%s ",InputBufferLength,InputBuffer));
		
	    FILTER_ACQUIRE_LOCK(&FilterListLock, FALSE);
		Link = FilterModuleList.Flink;
        Oid = OID_DOT11_CREATE_MAC;//OID used to create a new MAC
		/*************************************************************************
		actually, I don't understand why the following code is a while structure.
        do we really need to send the request to miniport to crate a new MAC for each 
		each filter? But usually, I think there is only one filter in the FilterModulerLink.
		And we have a test the number of filter is 3! 
		Warn:
		     Miniport couldn't crate more than 3 MAC entities!
		*********************************************************************************/
		#if DBG
		   _asm int 3
		#endif
        pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
		//pFilter = (PMS_FILTER)IrpSp->FileObject->FsContext;
	    //DEBUGP(DL_TEST, ("IOCTL:FileObject %p, Open %p\n", IrpSp->FileObject, pFilter));
        Status = filterDoInternalRequest(pFilter,
	                                 NdisRequestMethod,
									 Oid,
									 &InformationBuffer,
									 sizeof(InformationBuffer),
									 sizeof(InformationBuffer),
									 MethodId,
									 &BytesProcessed); 		
		if(Status == NDIS_STATUS_SUCCESS){
          DEBUGP(DL_TEST,("Creae a new mac successfully!\n"));
		}else{
          DEBUGP(DL_TEST,("Creae a new mac Fail!\n"));
		} 
	    FILTER_RELEASE_LOCK(&FilterListLock, FALSE);
        break;
             
        default:
            break;
    }

 然后是filterDoInternalRequest函数体:

NDIS_STATUS
filterDoInternalRequest(
    IN PMS_FILTER                   FilterModuleContext,
    IN NDIS_REQUEST_TYPE            RequestType,
    IN NDIS_OID                     Oid,
    IN PVOID                        InformationBuffer,
    IN ULONG                        InformationBufferLength,
    IN ULONG                        OutputBufferLength, OPTIONAL
    IN ULONG                        MethodId, OPTIONAL
    OUT PULONG                      pBytesProcessed
    )

{
    FILTER_REQUEST              FilterRequest;
    PNDIS_OID_REQUEST           NdisRequest = &FilterRequest.Request;
    NDIS_STATUS                 Status = NDIS_STATUS_SUCCESS;

    DEBUGP(DL_TEST,("==>filterDoInternalRequest\n"));
    NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));

    NdisInitializeEvent(&FilterRequest.ReqEvent);
    
    NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
    NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
    NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
    NdisRequest->RequestType = RequestType;

    switch (RequestType)
    {
        case NdisRequestQueryInformation:
             NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
             NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
                                    InformationBuffer;
             NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
                                    InformationBufferLength;
            break;

        case NdisRequestSetInformation:
             NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
             NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
                                    InformationBuffer;
             NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
                                    InformationBufferLength;
            break;

        case NdisRequestMethod:
             NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
             NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
             NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer =
                                    InformationBuffer;
             NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength =
                                    InformationBufferLength;
             NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
             break;
             
                

        default:
            FILTER_ASSERT(FALSE);
            break;
    }
    DEBUGP(DL_TEST,("Everything is ok before NdisOidRequest!\n "));
    DEBUGP(DL_TEST,("FilterModululeContext->FilterHandle is%p\n",FilterModuleContext->FilterHandle));
    #if DBG
	    _asm int 3
    #endif
    NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;
    Status = NdisFOidRequest(FilterModuleContext->FilterHandle,
                           NdisRequest);
    
    if (Status == NDIS_STATUS_PENDING)
    {
       DEBUGP(DL_TEST,("Everything is NDIS_STATUS_PENDING!\n "));
       NdisWaitEvent(&FilterRequest.ReqEvent, 0);
       Status = FilterRequest.Status;
    }


    if (Status == NDIS_STATUS_SUCCESS)
    {
       if (RequestType == NdisRequestSetInformation)
       {
           *pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
       }

       if (RequestType == NdisRequestQueryInformation)
       {
           *pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
       }

       if (RequestType == NdisRequestMethod)
       {
           *pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
       }
       
       
       // The driver below should set the correct value to BytesWritten 
       // or BytesRead. But now, we just truncate the value to InformationBufferLength
       
       if (RequestType == NdisRequestMethod)
       {
           if (*pBytesProcessed > OutputBufferLength)
           {
               *pBytesProcessed = OutputBufferLength;
           }
       }
       else
       {
           
           if (*pBytesProcessed > InformationBufferLength)
           {
               *pBytesProcessed = InformationBufferLength;
           }
       }
    } 


    return (Status);
}

 现在问题来了:

        在函数NdisFOidRequest()发送OID到miniport之后,返回的状态为:NDIS_STATUS_PENDING。然后进阶进入执行:NdisWaitEvent(&FilterRequest.ReqEvent, 0); 之后就蓝屏了。下面是调试信息:

FOLLOWUP_IP:
ndislwf!filterDoInternalRequest+1c1
[c:\users\leyond\desktop\filter_leyond_beta\src\filter\filter.c @ 2012]
93b882f1 8b4df4          mov     ecx,dword ptr [ebp-0Ch]

FAULTING_SOURCE_CODE: 
  2008:     if (Status == NDIS_STATUS_PENDING)
  2009:     {
  2010:       
  2011:        NdisWaitEvent(&FilterRequest.ReqEvent, 0);//应该着这里返回错误了
> 2012:        Status = FilterRequest.Status;
  2013:     }
  2014:
  2015:
  2016:     if (Status == NDIS_STATUS_SUCCESS)
  2017:     {

接着看:

Debug Mesage:
 *** Fatal System Error: 0x0000007c
        (0x00000014,0x00000002,0x00000000,0x00000000)

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.
BugCheck 7C, {14, 2, 0, 0}
..BUGCODE_NDIS_DRIVER (7c)
注意那四个参数:

0x14The current IRQL value00 An NDIS driver called NdisWaitEvent at IRQL > PASSIVE_LEVEL. The function must be called at IRQL = PASSIVE_LEVEL.

这里我们找到了蓝屏的真正理由:是 NdisWaitEvent 的IRQl>期望的PASSIVE_LEVEL. 为什么会这样的呢?我也没有找到理由。

从某位大牛Thomas Divine得到的回复是:

   Since this is in a NDIS driver one of the most common mistakes is to make a call to NdisOidRequest (or some other function with a completion routine...) and immediately wait for completion - at raised IRQL. The solution to this is NOT to wait. Instead, do the work in the completion routine when it is called.

 MSDN上面说NdisWaitEvent()函数的作用在于puts the caller into a wait state until the given event is set to the Signaled state or the wait times out.如果是因为等待参数为0,而需要提高IRQL。那么改成手动调用FilterOidRequestComplete函数看看了...结果未知。

还有一位大牛Tim Roberts的回复:

This is a relatively common misunderstanding, so I want to make sure
it's clear.  A lot of people come up against this restriction and say to
themselves "I need to wait in a DISPATCH_LEVEL function, so I'll just
temporarily change myself to non-dispatch," but that's the wrong way to
think about it.  As soon as you drop yourself below dispatch, you lose
the guarantees that you needed to be dispatch in the first place.
Spinlocks and synchronization will break, for example.

The solution is to remember that, in Windows, DISPATCH_LEVEL routines
cannot block, for any reason.  If you need to wait for something, you
need to spin off separate code at PASSIVE_LEVEL to do the wait.  That
means you have to think about WHY the routine was dispatch in the first
place.  Are you holding a spinlock?  If so, you'll have to find some
other way to protect the resource.

 所以他认为问题在于调用NdisFoidRequest时是否已经拿到spinLock.这下我恍然大悟。 FILTER_ACQUIRE_LOCK(&FilterListLock, FALSE); 就是这一句还有对应的释放lock的一句导致了后面返回 NDIS_STATUS_PENDING 的时候,调用NdisWaitEvent,由于无法及时返回就无法释放锁,导致其他进程无法访问某些资源,迫使增加IRQL值,一边第一时间执行。所以注释掉这两句就没有问题了。 非常感谢 Roberts.

-----------------------------------------------------------------------------

DDK文档中明确指出支持例程的IRQL限定。例如,KeWaitForSingleObject 例程有两个限 定:

  • 调用者必须运行在低于或等于DISPATCH_LEVEL级上。
  • 如果调用中指定了非0的超时,那么调用者必须严格地运行在低于DISPATCH_LEVEL的IRQL上。

上面这两行想要说明的是:如果KeWaitForSingleObject真的被阻塞了指定长的时间(你指定的非0超时),那么你必定运行在低于 DISPATCH_LEVEL的IRQL上,因为只有在这样的IRQL上线程阻塞才是允许的.

-----------------------------------------------------------------------------

附: Bug Check 0x7C: BUGCODE_NDIS_DRIVER

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值