Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

836 lines
34 KiB

  1. /*++
  2. Copyright(c) 1998,99 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. Windows Load Balancing Service (WLBS)
  7. Driver - initialization implementation
  8. Author:
  9. kyrilf
  10. shouse
  11. --*/
  12. #define NDIS51_MINIPORT 1
  13. #define NDIS_MINIPORT_DRIVER 1
  14. #define NDIS50 1
  15. #define NDIS51 1
  16. #include <stdio.h>
  17. #include <ndis.h>
  18. #include "main.h"
  19. #if defined (NLB_TCP_NOTIFICATION)
  20. #include "load.h"
  21. #endif
  22. #include "init.h"
  23. #include "prot.h"
  24. #include "nic.h"
  25. #include "univ.h"
  26. #include "wlbsparm.h"
  27. #include "log.h"
  28. #include "trace.h"
  29. #include "nlbwmi.h"
  30. #include "init.tmh"
  31. #if defined (NLB_TCP_NOTIFICATION)
  32. /* For TCP connection notifications. */
  33. #include <tcpinfo.h>
  34. #endif
  35. static ULONG log_module_id = LOG_MODULE_INIT;
  36. /* Added for NDIS51. */
  37. extern VOID Nic_pnpevent_notify (
  38. NDIS_HANDLE adapter_handle,
  39. NDIS_DEVICE_PNP_EVENT pnp_event,
  40. PVOID info_buf,
  41. ULONG info_len);
  42. /* Mark code that is used only during initialization. */
  43. #pragma alloc_text (INIT, DriverEntry)
  44. NDIS_STATUS DriverEntry (
  45. PVOID driver_obj,
  46. PVOID registry_path)
  47. {
  48. NDIS_PROTOCOL_CHARACTERISTICS prot_char;
  49. NDIS_MINIPORT_CHARACTERISTICS nic_char;
  50. NDIS_STRING prot_name = UNIV_NDIS_PROTOCOL_NAME;
  51. NTSTATUS status;
  52. PUNICODE_STRING reg_path = (PUNICODE_STRING) registry_path;
  53. WCHAR params [] = L"\\Parameters\\Interface\\";
  54. ULONG i;
  55. //
  56. // Initialize WMI event tracing
  57. //
  58. Trace_Initialize( driver_obj, registry_path );
  59. /* Register Convoy protocol with NDIS. */
  60. UNIV_PRINT_INFO(("DriverEntry: Loading the driver, driver_obj=0x%p", driver_obj));
  61. TRACE_INFO("->%!FUNC! Loading the driver, driver_obj=0x%p", driver_obj);
  62. univ_driver_ptr = driver_obj;
  63. /* Initialize the array of bindings. */
  64. univ_adapters_count = 0;
  65. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  66. {
  67. univ_adapters [i] . code = MAIN_ADAPTER_CODE;
  68. univ_adapters [i] . announced = FALSE;
  69. univ_adapters [i] . inited = FALSE;
  70. univ_adapters [i] . bound = FALSE;
  71. univ_adapters [i] . used = FALSE;
  72. univ_adapters [i] . ctxtp = NULL;
  73. univ_adapters [i] . device_name_len = 0;
  74. univ_adapters [i] . device_name = NULL;
  75. }
  76. #if defined (NLB_TCP_NOTIFICATION)
  77. /* Initialize the TCP connection callback object. */
  78. univ_tcp_callback_object = NULL;
  79. /* Initialize the TCP connection callback function. */
  80. univ_tcp_callback_function = NULL;
  81. /* Initialize the NLB public connection callback object. */
  82. univ_alternate_callback_object = NULL;
  83. /* Initialize the NLB public connection callback function. */
  84. univ_alternate_callback_function = NULL;
  85. #endif
  86. #if defined (NLB_HOOK_ENABLE)
  87. /* Allocate the spin lock for filter hook registration. */
  88. NdisAllocateSpinLock(&univ_hooks.FilterHook.Lock);
  89. /* Set the state to none. */
  90. univ_hooks.FilterHook.Operation = HOOK_OPERATION_NONE;
  91. /* Initially, no filter hook interface is registered. */
  92. Main_hook_interface_init(&univ_hooks.FilterHook.Interface);
  93. /* Reset the send filter hook information. */
  94. Main_hook_init(&univ_hooks.FilterHook.SendHook);
  95. /* Reset the query filter hook information. */
  96. Main_hook_init(&univ_hooks.FilterHook.QueryHook);
  97. /* Reset the receive filter hook information. */
  98. Main_hook_init(&univ_hooks.FilterHook.ReceiveHook);
  99. #endif
  100. /* create UNICODE name for the protocol */
  101. /* Store the registry path as passed, into a unicode string */
  102. status = NdisAllocateMemoryWithTag (&(DriverEntryRegistryPath.Buffer), reg_path -> Length + sizeof(UNICODE_NULL), UNIV_POOL_TAG);
  103. if (status != NDIS_STATUS_SUCCESS)
  104. {
  105. UNIV_PRINT_CRIT(("DriverEntry: Error allocating memory %x", status));
  106. TRACE_CRIT("%!FUNC! Error allocating memory 0x%x", status);
  107. goto error;
  108. }
  109. RtlCopyMemory (DriverEntryRegistryPath.Buffer, reg_path -> Buffer, reg_path -> Length);
  110. DriverEntryRegistryPath.Buffer[reg_path->Length / sizeof(WCHAR)] = UNICODE_NULL;
  111. DriverEntryRegistryPath.Length = reg_path -> Length;
  112. DriverEntryRegistryPath.MaximumLength = reg_path -> Length + sizeof(UNICODE_NULL);
  113. univ_reg_path_len = reg_path -> Length + wcslen (params) * sizeof (WCHAR) + sizeof (WCHAR);
  114. status = NdisAllocateMemoryWithTag (& univ_reg_path, univ_reg_path_len, UNIV_POOL_TAG);
  115. if (status != NDIS_STATUS_SUCCESS)
  116. {
  117. UNIV_PRINT_CRIT(("DriverEntry: Error allocating memory %x", status));
  118. __LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, univ_reg_path_len, status);
  119. TRACE_CRIT("%!FUNC! Error allocating memory 0x%x", status);
  120. /* Free previously allocated registry path unicode string */
  121. NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
  122. RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
  123. goto error;
  124. }
  125. RtlZeroMemory (univ_reg_path, reg_path -> Length + wcslen (params) * sizeof (WCHAR) + sizeof (WCHAR));
  126. RtlCopyMemory (univ_reg_path, reg_path -> Buffer, reg_path -> Length);
  127. RtlCopyMemory (((PCHAR) univ_reg_path) + reg_path -> Length, params, wcslen (params) * sizeof (WCHAR));
  128. /* Initialize miniport wrapper. */
  129. NdisMInitializeWrapper (& univ_wrapper_handle, driver_obj, registry_path, NULL);
  130. /* Initialize miniport characteristics. */
  131. RtlZeroMemory (& nic_char, sizeof (NDIS_MINIPORT_CHARACTERISTICS));
  132. nic_char . MajorNdisVersion = UNIV_NDIS_MAJOR_VERSION;
  133. nic_char . MinorNdisVersion = UNIV_NDIS_MINOR_VERSION;
  134. nic_char . HaltHandler = Nic_halt;
  135. nic_char . InitializeHandler = Nic_init;
  136. nic_char . QueryInformationHandler = Nic_info_query;
  137. nic_char . SetInformationHandler = Nic_info_set;
  138. nic_char . ResetHandler = Nic_reset;
  139. nic_char . ReturnPacketHandler = Nic_return;
  140. nic_char . SendPacketsHandler = Nic_packets_send;
  141. nic_char . TransferDataHandler = Nic_transfer;
  142. /* For NDIS51, define 3 new handlers. These handlers do nothing for now, but stuff will be added later. */
  143. nic_char . CancelSendPacketsHandler = Nic_cancel_send_packets;
  144. nic_char . PnPEventNotifyHandler = Nic_pnpevent_notify;
  145. nic_char . AdapterShutdownHandler = Nic_adapter_shutdown;
  146. UNIV_PRINT_INFO(("DriverEntry: Registering miniport"));
  147. TRACE_INFO("%!FUNC! Registering miniport");
  148. status = NdisIMRegisterLayeredMiniport (univ_wrapper_handle, & nic_char, sizeof (nic_char), & univ_driver_handle);
  149. if (status != NDIS_STATUS_SUCCESS)
  150. {
  151. UNIV_PRINT_CRIT(("DriverEntry: Error registering layered miniport with NDIS %x", status));
  152. __LOG_MSG1 (MSG_ERROR_REGISTERING, MSG_NONE, status);
  153. TRACE_CRIT("%!FUNC! Error registering layered miniport with NDIS 0x%x", status);
  154. NdisTerminateWrapper (univ_wrapper_handle, NULL);
  155. NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
  156. RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
  157. NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
  158. goto error;
  159. }
  160. /* Initialize protocol characteristics. */
  161. RtlZeroMemory (& prot_char, sizeof (NDIS_PROTOCOL_CHARACTERISTICS));
  162. /* This value needs to be 0, otherwise error registering protocol */
  163. prot_char . MinorNdisVersion = 0;
  164. prot_char . MajorNdisVersion = UNIV_NDIS_MAJOR_VERSION;
  165. prot_char . BindAdapterHandler = Prot_bind;
  166. prot_char . UnbindAdapterHandler = Prot_unbind;
  167. prot_char . OpenAdapterCompleteHandler = Prot_open_complete;
  168. prot_char . CloseAdapterCompleteHandler = Prot_close_complete;
  169. prot_char . StatusHandler = Prot_status;
  170. prot_char . StatusCompleteHandler = Prot_status_complete;
  171. prot_char . ResetCompleteHandler = Prot_reset_complete;
  172. prot_char . RequestCompleteHandler = Prot_request_complete;
  173. prot_char . SendCompleteHandler = Prot_send_complete;
  174. prot_char . TransferDataCompleteHandler = Prot_transfer_complete;
  175. prot_char . ReceiveHandler = Prot_recv_indicate;
  176. prot_char . ReceiveCompleteHandler = Prot_recv_complete;
  177. prot_char . ReceivePacketHandler = Prot_packet_recv;
  178. prot_char . PnPEventHandler = Prot_PNP_handle;
  179. prot_char . Name = prot_name;
  180. UNIV_PRINT_INFO(("DriverEntry: Registering protocol"));
  181. TRACE_INFO("%!FUNC! Registering protocol");
  182. NdisRegisterProtocol(& status, & univ_prot_handle, & prot_char, sizeof (prot_char));
  183. if (status != NDIS_STATUS_SUCCESS)
  184. {
  185. UNIV_PRINT_CRIT(("DriverEntry: Error registering protocol with NDIS %x", status));
  186. __LOG_MSG1 (MSG_ERROR_REGISTERING, MSG_NONE, status);
  187. TRACE_CRIT("%!FUNC! Error registering protocol with NDIS 0x%x", status);
  188. NdisTerminateWrapper (univ_wrapper_handle, NULL);
  189. NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
  190. RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
  191. NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
  192. goto error;
  193. }
  194. NdisIMAssociateMiniport (univ_driver_handle, univ_prot_handle);
  195. NdisMRegisterUnloadHandler (univ_wrapper_handle, Init_unload);
  196. NdisAllocateSpinLock (& univ_bind_lock);
  197. /* Allocate the global spin lock to protect the list of bi-directional affinity teams. */
  198. NdisAllocateSpinLock(&univ_bda_teaming_lock);
  199. #if defined (NLB_TCP_NOTIFICATION)
  200. /* Check to see if the registry key to over-ride notifications is there. If
  201. so, use its value to determine whether or not we're using notifications
  202. to track our TCP connection state. By default, the key does not exist
  203. and we will use TCP notifications. */
  204. (VOID)Params_read_notification();
  205. /* Perform the one-time intialization of the load module. */
  206. LoadEntry();
  207. #endif
  208. UNIV_PRINT_INFO(("DriverEntry: return=NDIS_STATUS_SUCCESS"));
  209. TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_SUCCESS");
  210. return NDIS_STATUS_SUCCESS;
  211. error:
  212. UNIV_PRINT_INFO(("DriverEntry: return=0x%x", status));
  213. TRACE_INFO("<-%!FUNC! return=0x%x", status);
  214. return status;
  215. } /* end DriverEntry */
  216. VOID Init_unload (
  217. PVOID driver_obj)
  218. {
  219. NDIS_STATUS status;
  220. ULONG i;
  221. UNIV_PRINT_INFO(("Init_unload: Unloading the driver, driver_obj=0x%p", driver_obj));
  222. TRACE_INFO("->%!FUNC! Unloading the driver, driver_obj=0x%p", driver_obj);
  223. /* If we failed to deallocate the context during unbind (both halt and unbind
  224. were not called for example) - do it now before unloading the driver. */
  225. for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
  226. {
  227. NdisAcquireSpinLock(& univ_bind_lock);
  228. if (univ_adapters [i] . inited && univ_adapters [i] . ctxtp != NULL)
  229. {
  230. univ_adapters [i] . used = FALSE;
  231. univ_adapters [i] . inited = FALSE;
  232. univ_adapters [i] . announced = FALSE;
  233. univ_adapters [i] . bound = FALSE;
  234. NdisReleaseSpinLock(& univ_bind_lock);
  235. if (univ_adapters [i] . ctxtp) {
  236. Main_cleanup (univ_adapters [i] . ctxtp);
  237. NdisFreeMemory (univ_adapters [i] . ctxtp, sizeof (MAIN_CTXT), 0);
  238. }
  239. univ_adapters [i] . ctxtp = NULL;
  240. if (univ_adapters [i] . device_name)
  241. NdisFreeMemory (univ_adapters [i] . device_name, univ_adapters [i] . device_name_len, 0);
  242. univ_adapters [i] . device_name = NULL;
  243. univ_adapters [i] . device_name_len = 0;
  244. }
  245. else
  246. {
  247. NdisReleaseSpinLock(& univ_bind_lock);
  248. }
  249. }
  250. #if defined (NLB_TCP_NOTIFICATION)
  251. /* Perform the last minute cleanup of the load module. */
  252. LoadUnload();
  253. #endif
  254. /* Free the global spin lock to protect the list of bi-directional affinity teams. */
  255. NdisFreeSpinLock(&univ_bda_teaming_lock);
  256. #if defined (NLB_HOOK_ENABLE)
  257. /* Free the spin lock for filter hook registration. */
  258. NdisFreeSpinLock(&univ_hooks.FilterHook.Lock);
  259. #endif
  260. NdisFreeSpinLock (& univ_bind_lock);
  261. if (univ_prot_handle == NULL)
  262. {
  263. status = NDIS_STATUS_FAILURE;
  264. UNIV_PRINT_CRIT(("Init_unload: NULL protocol handle. status set to NDIS_STATUS_FAILURE"));
  265. TRACE_CRIT("%!FUNC! NULL protocol handle. status set to NDIS_STATUS_FAILURE");
  266. }
  267. else
  268. {
  269. NdisDeregisterProtocol (& status, univ_prot_handle);
  270. UNIV_PRINT_INFO(("Init_unload: Deregistered protocol. univ_prot_handle=0x%p, status=0x%x", univ_prot_handle, status));
  271. TRACE_INFO("%!FUNC! Deregistered protocol. univ_prot_handle=0x%p, status=0x%x", univ_prot_handle, status);
  272. }
  273. NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
  274. NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
  275. RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
  276. UNIV_PRINT_INFO(("Init_unload: return"));
  277. TRACE_INFO("<-%!FUNC! return");
  278. //
  279. // Deinitialize WMI event tracing
  280. //
  281. Trace_Deinitialize();
  282. } /* end Init_unload */
  283. #if defined (NLB_HOOK_ENABLE)
  284. /*
  285. * Function: Init_deregister_hooks
  286. * Description: This function forcefully de-registers any hooks that are registered with
  287. * NLB. This function is called when the last instance of NLB is being
  288. * destroyed and the device driver may be about to be unloaded. Here, we
  289. * remove the hooks and notify whoever registered them that we are going
  290. * away. At that point, the registrar should close any open file handles on
  291. * the NLB driver so the driver can be properly unloaded.
  292. * Parameters: None.
  293. * Returns: Nothing.
  294. * Author: shouse, 12.17.01
  295. * Notes: There is a lot of code here to handle the case where we have to wait for references
  296. * on the filter hooks to go away before we can complete de-registration, but note that
  297. * because of guarantees that NDIS makes concerning when an unbind handler will be called,
  298. * this should never actually be necessary here - it is included for correctness and
  299. * completeness, not out of necessity.
  300. */
  301. VOID Init_deregister_hooks (VOID)
  302. {
  303. /* Grab the filter hook spin lock to protect access to the filter hook. */
  304. NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
  305. /* Make sure that another (de)register operation isn't in progress before proceeding. */
  306. while (univ_hooks.FilterHook.Operation != HOOK_OPERATION_NONE) {
  307. /* Release the filter hook spin lock. */
  308. NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
  309. /* Sleep while some other operation is in progress. */
  310. Nic_sleep(10);
  311. /* Grab the filter hook spin lock to protect access to the filter hook. */
  312. NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
  313. }
  314. if (univ_hooks.FilterHook.Interface.Registered) {
  315. /* Save the current owner of the filter hook interface. */
  316. HANDLE Owner = univ_hooks.FilterHook.Interface.Owner;
  317. /* Set the state to de-registering. */
  318. univ_hooks.FilterHook.Operation = HOOK_OPERATION_DEREGISTERING;
  319. /* Mark these hooks as NOT registered to keep any more references from accumulating. */
  320. univ_hooks.FilterHook.SendHook.Registered = FALSE;
  321. univ_hooks.FilterHook.QueryHook.Registered = FALSE;
  322. univ_hooks.FilterHook.ReceiveHook.Registered = FALSE;
  323. /* Release the filter hook spin lock. */
  324. NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
  325. /* Wait for all references on the filter hook interface to disappear. */
  326. while (univ_hooks.FilterHook.Interface.References) {
  327. /* Sleep while there are references on the interface we're de-registering. */
  328. Nic_sleep(10);
  329. }
  330. /* Assert that the de-register callback MUST be non-NULL. */
  331. UNIV_ASSERT(univ_hooks.FilterHook.Interface.Deregister);
  332. /* Call the provided de-register callback to notify the de-registering component
  333. that we have indeed de-registered the specified hook. */
  334. (*univ_hooks.FilterHook.Interface.Deregister)(NLB_FILTER_HOOK_INTERFACE, univ_hooks.FilterHook.Interface.Owner, NLB_HOOK_DEREGISTER_FLAGS_FORCED);
  335. /* Grab the filter hook spin lock to protect access to the filter hook. */
  336. NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
  337. /* Reset the send filter hook information. */
  338. Main_hook_init(&univ_hooks.FilterHook.SendHook);
  339. /* Reset the query filter hook information. */
  340. Main_hook_init(&univ_hooks.FilterHook.QueryHook);
  341. /* Reset the receive filter hook information. */
  342. Main_hook_init(&univ_hooks.FilterHook.ReceiveHook);
  343. /* Reset the hook interface information. */
  344. Main_hook_interface_init(&univ_hooks.FilterHook.Interface);
  345. /* Remember the current owner in the hook interface. When we invoke the forced
  346. de-register callback, the hook owner is supposed to close their handle on our
  347. IOCTL interface. If they do not close it before we try to de-register our
  348. IOCTL device, we will fail and the NLB driver will not get unloaded. Not a
  349. big deal, but in that case, we should ensure that we do NOT allow the mis-
  350. behaved hook to re-register with the same IOCTL handle. If the driver IS
  351. successfully unloaded, this re-set when the driver re-loads, in effect erasing
  352. our memory of the previous owner. */
  353. univ_hooks.FilterHook.Interface.Owner = Owner;
  354. /* Set the state to de-registering. */
  355. univ_hooks.FilterHook.Operation = HOOK_OPERATION_NONE;
  356. UNIV_PRINT_INFO(("Init_deregister_hooks: (NLB_FILTER_HOOK_INTERFACE) The filter hook interface was successfully de-registered"));
  357. TRACE_INFO("%!FUNC! (NLB_FILTER_HOOK_INTERFACE) The filter hook interface was successfullly de-registered");
  358. }
  359. /* Release the filter hook spin lock. */
  360. NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
  361. }
  362. #endif
  363. #if defined (NLB_TCP_NOTIFICATION)
  364. /*
  365. * Function: Init_register_tcp_callback
  366. * Description: This function registers our callback function with the TCP connection
  367. * notification callback object. We will begin receiving notifications
  368. * as soon as TCP is up and running. TCP will fire these events regardless
  369. * of who is listening (even if nobody is listening).
  370. * Parameters: None.
  371. * Returns: NTSTATUS - STATUS_SUCCESS if successful; an error code otherwise.
  372. * Author: shouse, 4.15.02
  373. * Notes:
  374. */
  375. NTSTATUS Init_register_tcp_callback ()
  376. {
  377. OBJECT_ATTRIBUTES ObjectAttributes;
  378. UNICODE_STRING CallbackName;
  379. NTSTATUS Status;
  380. /* Initialize the name of the TCP connection notification object. */
  381. RtlInitUnicodeString(&CallbackName, TCP_CCB_NAME);
  382. /* Initialize the object attributes. */
  383. InitializeObjectAttributes(&ObjectAttributes, &CallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
  384. /* Create (or open) the callback. */
  385. Status = ExCreateCallback(&univ_tcp_callback_object, &ObjectAttributes, TRUE, TRUE);
  386. if (Status == STATUS_SUCCESS)
  387. {
  388. /* Register our callback function, which will be invoked by TCP as TCP connections
  389. are created, established and subsequently torn-down, */
  390. univ_tcp_callback_function = ExRegisterCallback(univ_tcp_callback_object, Main_tcp_callback, NULL);
  391. /* A return value of NULL indicates a failure to register our callback function.
  392. Translate to an error code and relay the failure back to our caller. */
  393. if (univ_tcp_callback_function == NULL)
  394. Status = STATUS_UNSUCCESSFUL;
  395. }
  396. return Status;
  397. }
  398. /*
  399. * Function: Init_deregister_tcp_callback
  400. * Description: If the TCP connection notification callback is registered, this
  401. * function de-registers our callback function and dereferences the
  402. * TCP connection notification callback object. Note that by the
  403. * time the ExUnregisterCallback function returns, we are GUARANTEED
  404. * that our callback function will never be invoked again.
  405. * Parameters: None.
  406. * Returns: Nothing.
  407. * Author: shouse, 4.15.02
  408. * Notes: ExUnregisterCallback ensures that any in-progress invocations of the callback
  409. * complete before it returns, so upon return, our callback will never be invoked
  410. * again.
  411. */
  412. VOID Init_deregister_tcp_callback ()
  413. {
  414. /* If we successfully registered a callback function, deregister it now. */
  415. if (univ_tcp_callback_function != NULL)
  416. ExUnregisterCallback(univ_tcp_callback_function);
  417. /* Clean up the TCP connection notification callback function. */
  418. univ_tcp_callback_function = NULL;
  419. /* If we succeeded in creating/opening the callback object, dereference it now. */
  420. if (univ_tcp_callback_object != NULL)
  421. ObDereferenceObject(univ_tcp_callback_object);
  422. /* Clean up our TCP connection notification callback object. */
  423. univ_tcp_callback_object = NULL;
  424. }
  425. /*
  426. * Function: Init_register_alternate_callback
  427. * Description: This function registers our callback function with the NLB public connection
  428. * notification callback object. We will begin receiving notifications as soon
  429. * as other protocols begin sending them.
  430. * Parameters: None.
  431. * Returns: NTSTATUS - STATUS_SUCCESS if successful; an error code otherwise.
  432. * Author: shouse, 8.1.02
  433. * Notes:
  434. */
  435. NTSTATUS Init_register_alternate_callback ()
  436. {
  437. OBJECT_ATTRIBUTES ObjectAttributes;
  438. UNICODE_STRING CallbackName;
  439. NTSTATUS Status;
  440. /* Initialize the name of the NLB public connection notification object. */
  441. RtlInitUnicodeString(&CallbackName, NLB_CONNECTION_CALLBACK_NAME);
  442. /* Initialize the object attributes. */
  443. InitializeObjectAttributes(&ObjectAttributes, &CallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
  444. /* Create (or open) the callback. */
  445. Status = ExCreateCallback(&univ_alternate_callback_object, &ObjectAttributes, TRUE, TRUE);
  446. if (Status == STATUS_SUCCESS)
  447. {
  448. /* Register our callback function, which will be invoked by protocols as connections
  449. are created, established and subsequently torn-down, */
  450. univ_alternate_callback_function = ExRegisterCallback(univ_alternate_callback_object, Main_alternate_callback, NULL);
  451. /* A return value of NULL indicates a failure to register our callback function.
  452. Translate to an error code and relay the failure back to our caller. */
  453. if (univ_alternate_callback_function == NULL)
  454. Status = STATUS_UNSUCCESSFUL;
  455. }
  456. return Status;
  457. }
  458. /*
  459. * Function: Init_deregister_alternate_callback
  460. * Description: If the NLB public connection notification callback is registered,
  461. * this function de-registers our callback function and dereferences
  462. * the connection notification callback object. Note that by the
  463. * time the ExUnregisterCallback function returns, we are GUARANTEED
  464. * that our callback function will never be invoked again.
  465. * Parameters: None.
  466. * Returns: Nothing.
  467. * Author: shouse, 4.15.02
  468. * Notes: ExUnregisterCallback ensures that any in-progress invocations of the callback
  469. * complete before it returns, so upon return, our callback will never be invoked
  470. * again.
  471. */
  472. VOID Init_deregister_alternate_callback ()
  473. {
  474. /* If we successfully registered a callback function, deregister it now. */
  475. if (univ_alternate_callback_function != NULL)
  476. ExUnregisterCallback(univ_alternate_callback_function);
  477. /* Clean up the NLB public connection notification callback function. */
  478. univ_alternate_callback_function = NULL;
  479. /* If we succeeded in creating/opening the callback object, dereference it now. */
  480. if (univ_alternate_callback_object != NULL)
  481. ObDereferenceObject(univ_alternate_callback_object);
  482. /* Clean up our NLB public connection notification callback object. */
  483. univ_alternate_callback_object = NULL;
  484. }
  485. #endif
  486. ULONG NLBMiniportCount = 0;
  487. enum _DEVICE_STATE {
  488. PS_DEVICE_STATE_READY = 0, // ready for create/delete
  489. PS_DEVICE_STATE_CREATING, // create operation in progress
  490. PS_DEVICE_STATE_DELETING // delete operation in progress
  491. } NLBControlDeviceState = PS_DEVICE_STATE_READY;
  492. /*
  493. * Function:
  494. * Purpose: This function is called by Prot_bind and registers the IOCTL interface for WLBS.
  495. * The device is registered only when binding to the first network adapter.
  496. * Author: shouse, 3.1.01 - Copied largely from the sample IM driver net\ndis\samples\im\
  497. * Revision : karthicn, 12.17.01 - Added call to initialize WMI for event support
  498. */
  499. NDIS_STATUS Init_register_device (BOOL *pbFirstMiniport) {
  500. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  501. UNICODE_STRING DeviceName;
  502. UNICODE_STRING DeviceLinkUnicodeString;
  503. PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION];
  504. UINT i;
  505. UNIV_PRINT_INFO(("Init_register_device: Entering, NLBMiniportCount=%u", NLBMiniportCount));
  506. TRACE_INFO("->%!FUNC! Entering, NLBMiniportCount=%u", NLBMiniportCount);
  507. *pbFirstMiniport = FALSE;
  508. NdisAcquireSpinLock(&univ_bind_lock);
  509. ++NLBMiniportCount;
  510. if (1 == NLBMiniportCount)
  511. {
  512. ASSERT(NLBControlDeviceState != PS_DEVICE_STATE_CREATING);
  513. *pbFirstMiniport = TRUE;
  514. UNIV_PRINT_INFO(("Init_register_device: Registering IOCTL interface"));
  515. TRACE_INFO("%!FUNC! Registering IOCTL interface");
  516. /* Another thread could be running Init_Deregister_device() on behalf
  517. of another miniport instance. If so, wait for it to exit. */
  518. while (NLBControlDeviceState != PS_DEVICE_STATE_READY)
  519. {
  520. NdisReleaseSpinLock(&univ_bind_lock);
  521. NdisMSleep(1);
  522. NdisAcquireSpinLock(&univ_bind_lock);
  523. }
  524. NLBControlDeviceState = PS_DEVICE_STATE_CREATING;
  525. NdisReleaseSpinLock(&univ_bind_lock);
  526. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
  527. DispatchTable[i] = Main_dispatch;
  528. NdisInitUnicodeString(&DeviceName, CVY_DEVICE_NAME);
  529. NdisInitUnicodeString(&DeviceLinkUnicodeString, CVY_DOSDEVICE_NAME);
  530. /* Create a device object and register our dispatch handlers. */
  531. Status = NdisMRegisterDevice(univ_wrapper_handle, &DeviceName, &DeviceLinkUnicodeString,
  532. &DispatchTable[0], &univ_device_object, &univ_device_handle);
  533. if (Status != NDIS_STATUS_SUCCESS)
  534. {
  535. UNIV_PRINT_CRIT((" ** Error registering device with NDIS %x", Status));
  536. __LOG_MSG1(MSG_ERROR_REGISTERING, MSG_NONE, Status);
  537. TRACE_INFO("%!FUNC! Error registering device with NDIS 0x%x", Status);
  538. univ_device_object = NULL;
  539. univ_device_handle = NULL;
  540. }
  541. else
  542. {
  543. /*
  544. Even if NdisMRegisterDevice( ) returned NDIS_STATUS_SUCCESS, we used to
  545. check if univ_device_handle was null. If it was null, it was considered
  546. an error and we did not call NdisMDeRegisterDevice(). Per DDK & verified
  547. by AliD, we only need to check for the return value. So, I removed the
  548. additional check. However, since we are not aware of the reasons for the
  549. introduction of the additional check, I am adding the following ASSERTs,
  550. just in case.
  551. --KarthicN, 03-07-02
  552. */
  553. ASSERT(univ_device_object != NULL);
  554. ASSERT(univ_device_handle != NULL);
  555. }
  556. /* Initialize WMI */
  557. NlbWmi_Initialize(); // If non-null, it uses univ_device_object to register with WMI
  558. #if defined (NLB_TCP_NOTIFICATION)
  559. /* If TCP connection notification is turned on, then register our callback function. */
  560. if (NLB_TCP_NOTIFICATION_ON())
  561. {
  562. /* Initialize the TCP connection notification callback. */
  563. Status = Init_register_tcp_callback();
  564. if (Status != STATUS_SUCCESS)
  565. {
  566. UNIV_PRINT_CRIT(("Init_register_device: Could not create/open TCP connection notification callback, Status=0x%08x", Status));
  567. TRACE_CRIT("%!FUNC! Could not create/open TCP connection notification callback, Status=0x%08x", Status);
  568. __LOG_MSG1(MSG_WARN_TCP_CALLBACK_OPEN_FAILED, MSG_NONE, Status);
  569. }
  570. /* If NLB public connection notification is turned on, then register our callback function. */
  571. }
  572. else if (NLB_ALTERNATE_NOTIFICATION_ON())
  573. {
  574. /* Initialize the NLB public connection notification callback. */
  575. Status = Init_register_alternate_callback();
  576. if (Status != STATUS_SUCCESS)
  577. {
  578. UNIV_PRINT_CRIT(("Init_register_device: Could not create/open NLB public connection notification callback, Status=0x%08x", Status));
  579. TRACE_CRIT("%!FUNC! Could not create/open NLB public connection notification callback, Status=0x%08x", Status);
  580. __LOG_MSG1(MSG_WARN_ALTERNATE_CALLBACK_OPEN_FAILED, MSG_NONE, Status);
  581. }
  582. }
  583. #endif
  584. NdisAcquireSpinLock(&univ_bind_lock);
  585. NLBControlDeviceState = PS_DEVICE_STATE_READY;
  586. }
  587. NdisReleaseSpinLock(&univ_bind_lock);
  588. UNIV_PRINT_INFO(("Init_register_device: return=0x%x", Status));
  589. TRACE_INFO("<-%!FUNC! return=0x%x", Status);
  590. return (Status);
  591. }
  592. /*
  593. * Function:
  594. * Purpose: This function is called by Prot_unbind and deregisters the IOCTL interface for WLBS.
  595. * The device is deregistered only when we unbind from the last network adapter
  596. * Author: shouse, 3.1.01 - Copied largely from the sample IM driver net\ndis\samples\im\
  597. * Revision : karthicn, 12.17.01 - Added call to de-initialize from WMI for event support
  598. */
  599. NDIS_STATUS Init_deregister_device (VOID) {
  600. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  601. UNIV_PRINT_INFO(("Init_deregister_device: Entering, NLBMiniportCount=%u", NLBMiniportCount));
  602. TRACE_INFO("->%!FUNC! Entering, NLBMiniportCount=%u", NLBMiniportCount);
  603. NdisAcquireSpinLock(&univ_bind_lock);
  604. ASSERT(NLBMiniportCount > 0);
  605. --NLBMiniportCount;
  606. if (0 == NLBMiniportCount)
  607. {
  608. /* All miniport instances have been halted. Deregisterthe control device. */
  609. ASSERT(NLBControlDeviceState == PS_DEVICE_STATE_READY);
  610. /* Block Init_register_device() while we release the control
  611. device lock and deregister the device. */
  612. NLBControlDeviceState = PS_DEVICE_STATE_DELETING;
  613. NdisReleaseSpinLock(&univ_bind_lock);
  614. #if defined (NLB_HOOK_ENABLE)
  615. /* If the last miniport instance is going away, forcefully de-register all
  616. registered global hooks now, before we remove the IOCTL interface. */
  617. Init_deregister_hooks();
  618. #endif
  619. // Fire wmi event to indicate NLB unbinding from the last nic
  620. if (NlbWmiEvents[ShutdownEvent].Enable)
  621. {
  622. NlbWmi_Fire_Event(ShutdownEvent, NULL, 0);
  623. }
  624. else
  625. {
  626. TRACE_VERB("%!FUNC! NOT generating Shutdown event 'cos its generation is disabled");
  627. }
  628. #if defined (NLB_TCP_NOTIFICATION)
  629. /* If TCP connection notification is turned on, then de-register our callback function. */
  630. if (NLB_TCP_NOTIFICATION_ON())
  631. {
  632. /* Initialize the TCP connection notification callback. */
  633. Init_deregister_tcp_callback();
  634. }
  635. /* If NLB public connection notification is turned on, then de-register our callback function. */
  636. else if (NLB_ALTERNATE_NOTIFICATION_ON())
  637. {
  638. /* Initialize the NLB public connection notification callback. */
  639. Init_deregister_alternate_callback();
  640. }
  641. #endif
  642. /* DeRegister with WMI */
  643. NlbWmi_Shutdown();
  644. UNIV_PRINT_INFO(("Init_deregister_device: Deleting IOCTL interface"));
  645. TRACE_INFO("%!FUNC! Deleting IOCTL interface");
  646. if (univ_device_handle != NULL)
  647. {
  648. Status = NdisMDeregisterDevice(univ_device_handle);
  649. univ_device_object = NULL;
  650. univ_device_handle = NULL;
  651. }
  652. NdisAcquireSpinLock(&univ_bind_lock);
  653. NLBControlDeviceState = PS_DEVICE_STATE_READY;
  654. }
  655. NdisReleaseSpinLock(&univ_bind_lock);
  656. UNIV_PRINT_INFO(("Init_deregister_Device: return=0x%x", Status));
  657. TRACE_INFO("<-%!FUNC! return=0x%x", Status);
  658. return Status;
  659. }