/*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: ExCallbk.c Abstract: The routines in this module helps to solve driver load order dependency between this sample and NDISWDM sample. These routines are not required in a typical protocol driver. By default this module is not included in the sample. You include these routines by adding EX_CALLBACK defines to the 'sources' file. Read the NDISWDM samples readme file for more information on how ExCallback kernel interfaces are used to solve driver load order issue. Environment: Kernel mode Revision History: --*/ #include "precomp.h" #ifdef EX_CALLBACK #define __FILENUMBER 'LCxE' #define NDISPROT_CALLBACK_NAME L"//Callback//NdisProtCallbackObject" #define CALLBACK_SOURCE_NDISPROT 0 #define CALLBACK_SOURCE_NDISWDM 1 PCALLBACK_OBJECT CallbackObject = NULL; PVOID CallbackRegisterationHandle = NULL; typedef VOID (* NOTIFY_PRESENCE_CALLBACK)(OUT PVOID Source); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, ndisprotRegisterExCallBack) #pragma alloc_text(PAGE, ndisprotUnregisterExCallBack) #endif // ALLOC_PRAGMA BOOLEAN ndisprotRegisterExCallBack(VOID) /*++ Routine Description: Create or open an existing callback object and send a notification. Note that the system calls our notication callback routine in addition to notifying other registered clients. Arguments: Return Value: TRUE or FALSE --*/ { OBJECT_ATTRIBUTES ObjectAttr; UNICODE_STRING CallBackObjectName; NTSTATUS Status; BOOLEAN bResult = TRUE; DEBUGP(DL_LOUD, ("--> ndisprotRegisterExCallBack/n")); PAGED_CODE(); do { RtlInitUnicodeString(&CallBackObjectName, NDISPROT_CALLBACK_NAME); /* typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; #define InitializeObjectAttributes( p, n, a, r, s ) { / (p)->Length = sizeof( OBJECT_ATTRIBUTES ); / (p)->RootDirectory = r; / (p)->Attributes = a; / (p)->ObjectName = n; / (p)->SecurityDescriptor = s; / (p)->SecurityQualityOfService = NULL; / } */ InitializeObjectAttributes(&ObjectAttr, &CallBackObjectName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); // 这里是创建一个名字是//Callback//NdisProtCallbackObject的对象 // 调用后面注册的回调函数的条件不明? Status = ExCreateCallback(&CallbackObject, &ObjectAttr, TRUE, TRUE); if (!NT_SUCCESS(Status)) { DEBUGP(DL_ERROR, ("RegisterExCallBack: failed to create callback %lx/n", Status)); bResult = FALSE; break; } // 注册回调函数,什么条件下会调用这个注册的回调例程不明? CallbackRegisterationHandle = ExRegisterCallback(CallbackObject, ndisprotCallback, (PVOID)NULL); if (CallbackRegisterationHandle == NULL) { DEBUGP(DL_ERROR,("RegisterExCallBack: failed to register a Callback routine%lx/n", Status)); bResult = FALSE; break; } // 主动调用了一次 ExNotifyCallback(CallbackObject, (PVOID)CALLBACK_SOURCE_NDISPROT, (PVOID)NULL); }while(FALSE); if(!bResult) { // 失败的场合,做各种判断和对应的处理 if (CallbackRegisterationHandle) { // 如果已经注册了,就反注册 ExUnregisterCallback(CallbackRegisterationHandle); CallbackRegisterationHandle = NULL; } if (CallbackObject) { // 解引用对象,如果成功了,不用解引用,因为这个对象只有创建时引用计数加1,以后不会再次打开, // 反注册时会把引用计数减1,正好平衡 ObDereferenceObject(CallbackObject); CallbackObject = NULL; } } DEBUGP(DL_LOUD, ("<-- ndisprotRegisterExCallBack/n")); return bResult; } VOID ndisprotUnregisterExCallBack() /*++ Routine Description: Unregister out callback routine and also delete the object by removing the reference on it. Arguments: Return Value: VOID --*/ { DEBUGP(DL_LOUD, ("--> ndisprotUnregisterExCallBack/n")); PAGED_CODE(); if (CallbackRegisterationHandle) { ExUnregisterCallback(CallbackRegisterationHandle); CallbackRegisterationHandle = NULL; } if (CallbackObject) { // 引用计数减1,保证正常释放资源 ObDereferenceObject(CallbackObject); CallbackObject = NULL; } DEBUGP(DL_LOUD, ("<-- ndisprotUnregisterExCallBack/n")); } VOID ndisprotCallback( PVOID CallBackContext, PVOID Source, PVOID CallbackAddr ) /*++ Routine Description: This is the notification callback routine called by the executive subsystem in the context of the thread that make the notification on the object we have registered. This routine could be called by the NDISPROT driver or another instance of our own miniport. Arguments: CallBackContext - This is the context value specified in the ExRegisterCallback call. It's NULL. Source - First parameter specified in the call to ExNotifyCallback. This is used to indenty the caller. This could be either ourself or NDISWDM. CallbackAddr - Second parameter specified in the call to ExNotifyCallback. This is an additonal context the caller can specify. When it comes from NDISWDM, it's a routine to call as part of the notification. Return Value: VOID --*/ { NOTIFY_PRESENCE_CALLBACK func; DEBUGP(DL_LOUD, ("==>ndisprotoCallback: Source %lx, CallbackAddr %p/n", Source, CallbackAddr)); // // if we are the one issuing this notification, just return // // 防止重入 if (Source == CALLBACK_SOURCE_NDISPROT) { return; } // // Notification is coming from NDISWDM // let it know that you are here // ASSERT(Source == (PVOID)CALLBACK_SOURCE_NDISWDM); // 可能是做正在处理中的判断,处理完毕后会设置为CALLBACK_SOURCE_NDISPROT标志 if(Source == (PVOID)CALLBACK_SOURCE_NDISWDM) { ASSERT(CallbackAddr); if (CallbackAddr == NULL) { DEBUGP(DL_ERROR, ("Callback called with invalid address %p/n", CallbackAddr)); return; } func = CallbackAddr; // 调用真正做事情的例程,参数是CALLBACK_SOURCE_NDISPROT func(CALLBACK_SOURCE_NDISPROT); } DEBUGP(DL_LOUD, ("<==ndisprotoCallback: Source, %lx/n", Source)); } #endif