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

/*++
Copyright(c) 1998,99 Microsoft Corporation
Module Name:
init.c
Abstract:
Windows Load Balancing Service (WLBS)
Driver - initialization implementation
Author:
kyrilf
shouse
--*/
#define NDIS51_MINIPORT 1
#define NDIS_MINIPORT_DRIVER 1
#define NDIS50 1
#define NDIS51 1
#include <stdio.h>
#include <ndis.h>
#include "main.h"
#if defined (NLB_TCP_NOTIFICATION)
#include "load.h"
#endif
#include "init.h"
#include "prot.h"
#include "nic.h"
#include "univ.h"
#include "wlbsparm.h"
#include "log.h"
#include "trace.h"
#include "nlbwmi.h"
#include "init.tmh"
#if defined (NLB_TCP_NOTIFICATION)
/* For TCP connection notifications. */
#include <tcpinfo.h>
#endif
static ULONG log_module_id = LOG_MODULE_INIT;
/* Added for NDIS51. */
extern VOID Nic_pnpevent_notify (
NDIS_HANDLE adapter_handle,
NDIS_DEVICE_PNP_EVENT pnp_event,
PVOID info_buf,
ULONG info_len);
/* Mark code that is used only during initialization. */
#pragma alloc_text (INIT, DriverEntry)
NDIS_STATUS DriverEntry (
PVOID driver_obj,
PVOID registry_path)
{
NDIS_PROTOCOL_CHARACTERISTICS prot_char;
NDIS_MINIPORT_CHARACTERISTICS nic_char;
NDIS_STRING prot_name = UNIV_NDIS_PROTOCOL_NAME;
NTSTATUS status;
PUNICODE_STRING reg_path = (PUNICODE_STRING) registry_path;
WCHAR params [] = L"\\Parameters\\Interface\\";
ULONG i;
//
// Initialize WMI event tracing
//
Trace_Initialize( driver_obj, registry_path );
/* Register Convoy protocol with NDIS. */
UNIV_PRINT_INFO(("DriverEntry: Loading the driver, driver_obj=0x%p", driver_obj));
TRACE_INFO("->%!FUNC! Loading the driver, driver_obj=0x%p", driver_obj);
univ_driver_ptr = driver_obj;
/* Initialize the array of bindings. */
univ_adapters_count = 0;
for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
{
univ_adapters [i] . code = MAIN_ADAPTER_CODE;
univ_adapters [i] . announced = FALSE;
univ_adapters [i] . inited = FALSE;
univ_adapters [i] . bound = FALSE;
univ_adapters [i] . used = FALSE;
univ_adapters [i] . ctxtp = NULL;
univ_adapters [i] . device_name_len = 0;
univ_adapters [i] . device_name = NULL;
}
#if defined (NLB_TCP_NOTIFICATION)
/* Initialize the TCP connection callback object. */
univ_tcp_callback_object = NULL;
/* Initialize the TCP connection callback function. */
univ_tcp_callback_function = NULL;
/* Initialize the NLB public connection callback object. */
univ_alternate_callback_object = NULL;
/* Initialize the NLB public connection callback function. */
univ_alternate_callback_function = NULL;
#endif
#if defined (NLB_HOOK_ENABLE)
/* Allocate the spin lock for filter hook registration. */
NdisAllocateSpinLock(&univ_hooks.FilterHook.Lock);
/* Set the state to none. */
univ_hooks.FilterHook.Operation = HOOK_OPERATION_NONE;
/* Initially, no filter hook interface is registered. */
Main_hook_interface_init(&univ_hooks.FilterHook.Interface);
/* Reset the send filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.SendHook);
/* Reset the query filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.QueryHook);
/* Reset the receive filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.ReceiveHook);
#endif
/* create UNICODE name for the protocol */
/* Store the registry path as passed, into a unicode string */
status = NdisAllocateMemoryWithTag (&(DriverEntryRegistryPath.Buffer), reg_path -> Length + sizeof(UNICODE_NULL), UNIV_POOL_TAG);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("DriverEntry: Error allocating memory %x", status));
TRACE_CRIT("%!FUNC! Error allocating memory 0x%x", status);
goto error;
}
RtlCopyMemory (DriverEntryRegistryPath.Buffer, reg_path -> Buffer, reg_path -> Length);
DriverEntryRegistryPath.Buffer[reg_path->Length / sizeof(WCHAR)] = UNICODE_NULL;
DriverEntryRegistryPath.Length = reg_path -> Length;
DriverEntryRegistryPath.MaximumLength = reg_path -> Length + sizeof(UNICODE_NULL);
univ_reg_path_len = reg_path -> Length + wcslen (params) * sizeof (WCHAR) + sizeof (WCHAR);
status = NdisAllocateMemoryWithTag (& univ_reg_path, univ_reg_path_len, UNIV_POOL_TAG);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("DriverEntry: Error allocating memory %x", status));
__LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, univ_reg_path_len, status);
TRACE_CRIT("%!FUNC! Error allocating memory 0x%x", status);
/* Free previously allocated registry path unicode string */
NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
goto error;
}
RtlZeroMemory (univ_reg_path, reg_path -> Length + wcslen (params) * sizeof (WCHAR) + sizeof (WCHAR));
RtlCopyMemory (univ_reg_path, reg_path -> Buffer, reg_path -> Length);
RtlCopyMemory (((PCHAR) univ_reg_path) + reg_path -> Length, params, wcslen (params) * sizeof (WCHAR));
/* Initialize miniport wrapper. */
NdisMInitializeWrapper (& univ_wrapper_handle, driver_obj, registry_path, NULL);
/* Initialize miniport characteristics. */
RtlZeroMemory (& nic_char, sizeof (NDIS_MINIPORT_CHARACTERISTICS));
nic_char . MajorNdisVersion = UNIV_NDIS_MAJOR_VERSION;
nic_char . MinorNdisVersion = UNIV_NDIS_MINOR_VERSION;
nic_char . HaltHandler = Nic_halt;
nic_char . InitializeHandler = Nic_init;
nic_char . QueryInformationHandler = Nic_info_query;
nic_char . SetInformationHandler = Nic_info_set;
nic_char . ResetHandler = Nic_reset;
nic_char . ReturnPacketHandler = Nic_return;
nic_char . SendPacketsHandler = Nic_packets_send;
nic_char . TransferDataHandler = Nic_transfer;
/* For NDIS51, define 3 new handlers. These handlers do nothing for now, but stuff will be added later. */
nic_char . CancelSendPacketsHandler = Nic_cancel_send_packets;
nic_char . PnPEventNotifyHandler = Nic_pnpevent_notify;
nic_char . AdapterShutdownHandler = Nic_adapter_shutdown;
UNIV_PRINT_INFO(("DriverEntry: Registering miniport"));
TRACE_INFO("%!FUNC! Registering miniport");
status = NdisIMRegisterLayeredMiniport (univ_wrapper_handle, & nic_char, sizeof (nic_char), & univ_driver_handle);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("DriverEntry: Error registering layered miniport with NDIS %x", status));
__LOG_MSG1 (MSG_ERROR_REGISTERING, MSG_NONE, status);
TRACE_CRIT("%!FUNC! Error registering layered miniport with NDIS 0x%x", status);
NdisTerminateWrapper (univ_wrapper_handle, NULL);
NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
goto error;
}
/* Initialize protocol characteristics. */
RtlZeroMemory (& prot_char, sizeof (NDIS_PROTOCOL_CHARACTERISTICS));
/* This value needs to be 0, otherwise error registering protocol */
prot_char . MinorNdisVersion = 0;
prot_char . MajorNdisVersion = UNIV_NDIS_MAJOR_VERSION;
prot_char . BindAdapterHandler = Prot_bind;
prot_char . UnbindAdapterHandler = Prot_unbind;
prot_char . OpenAdapterCompleteHandler = Prot_open_complete;
prot_char . CloseAdapterCompleteHandler = Prot_close_complete;
prot_char . StatusHandler = Prot_status;
prot_char . StatusCompleteHandler = Prot_status_complete;
prot_char . ResetCompleteHandler = Prot_reset_complete;
prot_char . RequestCompleteHandler = Prot_request_complete;
prot_char . SendCompleteHandler = Prot_send_complete;
prot_char . TransferDataCompleteHandler = Prot_transfer_complete;
prot_char . ReceiveHandler = Prot_recv_indicate;
prot_char . ReceiveCompleteHandler = Prot_recv_complete;
prot_char . ReceivePacketHandler = Prot_packet_recv;
prot_char . PnPEventHandler = Prot_PNP_handle;
prot_char . Name = prot_name;
UNIV_PRINT_INFO(("DriverEntry: Registering protocol"));
TRACE_INFO("%!FUNC! Registering protocol");
NdisRegisterProtocol(& status, & univ_prot_handle, & prot_char, sizeof (prot_char));
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("DriverEntry: Error registering protocol with NDIS %x", status));
__LOG_MSG1 (MSG_ERROR_REGISTERING, MSG_NONE, status);
TRACE_CRIT("%!FUNC! Error registering protocol with NDIS 0x%x", status);
NdisTerminateWrapper (univ_wrapper_handle, NULL);
NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
goto error;
}
NdisIMAssociateMiniport (univ_driver_handle, univ_prot_handle);
NdisMRegisterUnloadHandler (univ_wrapper_handle, Init_unload);
NdisAllocateSpinLock (& univ_bind_lock);
/* Allocate the global spin lock to protect the list of bi-directional affinity teams. */
NdisAllocateSpinLock(&univ_bda_teaming_lock);
#if defined (NLB_TCP_NOTIFICATION)
/* Check to see if the registry key to over-ride notifications is there. If
so, use its value to determine whether or not we're using notifications
to track our TCP connection state. By default, the key does not exist
and we will use TCP notifications. */
(VOID)Params_read_notification();
/* Perform the one-time intialization of the load module. */
LoadEntry();
#endif
UNIV_PRINT_INFO(("DriverEntry: return=NDIS_STATUS_SUCCESS"));
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_SUCCESS");
return NDIS_STATUS_SUCCESS;
error:
UNIV_PRINT_INFO(("DriverEntry: return=0x%x", status));
TRACE_INFO("<-%!FUNC! return=0x%x", status);
return status;
} /* end DriverEntry */
VOID Init_unload (
PVOID driver_obj)
{
NDIS_STATUS status;
ULONG i;
UNIV_PRINT_INFO(("Init_unload: Unloading the driver, driver_obj=0x%p", driver_obj));
TRACE_INFO("->%!FUNC! Unloading the driver, driver_obj=0x%p", driver_obj);
/* If we failed to deallocate the context during unbind (both halt and unbind
were not called for example) - do it now before unloading the driver. */
for (i = 0 ; i < CVY_MAX_ADAPTERS; i++)
{
NdisAcquireSpinLock(& univ_bind_lock);
if (univ_adapters [i] . inited && univ_adapters [i] . ctxtp != NULL)
{
univ_adapters [i] . used = FALSE;
univ_adapters [i] . inited = FALSE;
univ_adapters [i] . announced = FALSE;
univ_adapters [i] . bound = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
if (univ_adapters [i] . ctxtp) {
Main_cleanup (univ_adapters [i] . ctxtp);
NdisFreeMemory (univ_adapters [i] . ctxtp, sizeof (MAIN_CTXT), 0);
}
univ_adapters [i] . ctxtp = NULL;
if (univ_adapters [i] . device_name)
NdisFreeMemory (univ_adapters [i] . device_name, univ_adapters [i] . device_name_len, 0);
univ_adapters [i] . device_name = NULL;
univ_adapters [i] . device_name_len = 0;
}
else
{
NdisReleaseSpinLock(& univ_bind_lock);
}
}
#if defined (NLB_TCP_NOTIFICATION)
/* Perform the last minute cleanup of the load module. */
LoadUnload();
#endif
/* Free the global spin lock to protect the list of bi-directional affinity teams. */
NdisFreeSpinLock(&univ_bda_teaming_lock);
#if defined (NLB_HOOK_ENABLE)
/* Free the spin lock for filter hook registration. */
NdisFreeSpinLock(&univ_hooks.FilterHook.Lock);
#endif
NdisFreeSpinLock (& univ_bind_lock);
if (univ_prot_handle == NULL)
{
status = NDIS_STATUS_FAILURE;
UNIV_PRINT_CRIT(("Init_unload: NULL protocol handle. status set to NDIS_STATUS_FAILURE"));
TRACE_CRIT("%!FUNC! NULL protocol handle. status set to NDIS_STATUS_FAILURE");
}
else
{
NdisDeregisterProtocol (& status, univ_prot_handle);
UNIV_PRINT_INFO(("Init_unload: Deregistered protocol. univ_prot_handle=0x%p, status=0x%x", univ_prot_handle, status));
TRACE_INFO("%!FUNC! Deregistered protocol. univ_prot_handle=0x%p, status=0x%x", univ_prot_handle, status);
}
NdisFreeMemory(univ_reg_path, univ_reg_path_len, 0);
NdisFreeMemory(DriverEntryRegistryPath.Buffer, DriverEntryRegistryPath.MaximumLength, 0);
RtlZeroMemory (&DriverEntryRegistryPath, sizeof(UNICODE_STRING));
UNIV_PRINT_INFO(("Init_unload: return"));
TRACE_INFO("<-%!FUNC! return");
//
// Deinitialize WMI event tracing
//
Trace_Deinitialize();
} /* end Init_unload */
#if defined (NLB_HOOK_ENABLE)
/*
* Function: Init_deregister_hooks
* Description: This function forcefully de-registers any hooks that are registered with
* NLB. This function is called when the last instance of NLB is being
* destroyed and the device driver may be about to be unloaded. Here, we
* remove the hooks and notify whoever registered them that we are going
* away. At that point, the registrar should close any open file handles on
* the NLB driver so the driver can be properly unloaded.
* Parameters: None.
* Returns: Nothing.
* Author: shouse, 12.17.01
* Notes: There is a lot of code here to handle the case where we have to wait for references
* on the filter hooks to go away before we can complete de-registration, but note that
* because of guarantees that NDIS makes concerning when an unbind handler will be called,
* this should never actually be necessary here - it is included for correctness and
* completeness, not out of necessity.
*/
VOID Init_deregister_hooks (VOID)
{
/* Grab the filter hook spin lock to protect access to the filter hook. */
NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
/* Make sure that another (de)register operation isn't in progress before proceeding. */
while (univ_hooks.FilterHook.Operation != HOOK_OPERATION_NONE) {
/* Release the filter hook spin lock. */
NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
/* Sleep while some other operation is in progress. */
Nic_sleep(10);
/* Grab the filter hook spin lock to protect access to the filter hook. */
NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
}
if (univ_hooks.FilterHook.Interface.Registered) {
/* Save the current owner of the filter hook interface. */
HANDLE Owner = univ_hooks.FilterHook.Interface.Owner;
/* Set the state to de-registering. */
univ_hooks.FilterHook.Operation = HOOK_OPERATION_DEREGISTERING;
/* Mark these hooks as NOT registered to keep any more references from accumulating. */
univ_hooks.FilterHook.SendHook.Registered = FALSE;
univ_hooks.FilterHook.QueryHook.Registered = FALSE;
univ_hooks.FilterHook.ReceiveHook.Registered = FALSE;
/* Release the filter hook spin lock. */
NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
/* Wait for all references on the filter hook interface to disappear. */
while (univ_hooks.FilterHook.Interface.References) {
/* Sleep while there are references on the interface we're de-registering. */
Nic_sleep(10);
}
/* Assert that the de-register callback MUST be non-NULL. */
UNIV_ASSERT(univ_hooks.FilterHook.Interface.Deregister);
/* Call the provided de-register callback to notify the de-registering component
that we have indeed de-registered the specified hook. */
(*univ_hooks.FilterHook.Interface.Deregister)(NLB_FILTER_HOOK_INTERFACE, univ_hooks.FilterHook.Interface.Owner, NLB_HOOK_DEREGISTER_FLAGS_FORCED);
/* Grab the filter hook spin lock to protect access to the filter hook. */
NdisAcquireSpinLock(&univ_hooks.FilterHook.Lock);
/* Reset the send filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.SendHook);
/* Reset the query filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.QueryHook);
/* Reset the receive filter hook information. */
Main_hook_init(&univ_hooks.FilterHook.ReceiveHook);
/* Reset the hook interface information. */
Main_hook_interface_init(&univ_hooks.FilterHook.Interface);
/* Remember the current owner in the hook interface. When we invoke the forced
de-register callback, the hook owner is supposed to close their handle on our
IOCTL interface. If they do not close it before we try to de-register our
IOCTL device, we will fail and the NLB driver will not get unloaded. Not a
big deal, but in that case, we should ensure that we do NOT allow the mis-
behaved hook to re-register with the same IOCTL handle. If the driver IS
successfully unloaded, this re-set when the driver re-loads, in effect erasing
our memory of the previous owner. */
univ_hooks.FilterHook.Interface.Owner = Owner;
/* Set the state to de-registering. */
univ_hooks.FilterHook.Operation = HOOK_OPERATION_NONE;
UNIV_PRINT_INFO(("Init_deregister_hooks: (NLB_FILTER_HOOK_INTERFACE) The filter hook interface was successfully de-registered"));
TRACE_INFO("%!FUNC! (NLB_FILTER_HOOK_INTERFACE) The filter hook interface was successfullly de-registered");
}
/* Release the filter hook spin lock. */
NdisReleaseSpinLock(&univ_hooks.FilterHook.Lock);
}
#endif
#if defined (NLB_TCP_NOTIFICATION)
/*
* Function: Init_register_tcp_callback
* Description: This function registers our callback function with the TCP connection
* notification callback object. We will begin receiving notifications
* as soon as TCP is up and running. TCP will fire these events regardless
* of who is listening (even if nobody is listening).
* Parameters: None.
* Returns: NTSTATUS - STATUS_SUCCESS if successful; an error code otherwise.
* Author: shouse, 4.15.02
* Notes:
*/
NTSTATUS Init_register_tcp_callback ()
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING CallbackName;
NTSTATUS Status;
/* Initialize the name of the TCP connection notification object. */
RtlInitUnicodeString(&CallbackName, TCP_CCB_NAME);
/* Initialize the object attributes. */
InitializeObjectAttributes(&ObjectAttributes, &CallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
/* Create (or open) the callback. */
Status = ExCreateCallback(&univ_tcp_callback_object, &ObjectAttributes, TRUE, TRUE);
if (Status == STATUS_SUCCESS)
{
/* Register our callback function, which will be invoked by TCP as TCP connections
are created, established and subsequently torn-down, */
univ_tcp_callback_function = ExRegisterCallback(univ_tcp_callback_object, Main_tcp_callback, NULL);
/* A return value of NULL indicates a failure to register our callback function.
Translate to an error code and relay the failure back to our caller. */
if (univ_tcp_callback_function == NULL)
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}
/*
* Function: Init_deregister_tcp_callback
* Description: If the TCP connection notification callback is registered, this
* function de-registers our callback function and dereferences the
* TCP connection notification callback object. Note that by the
* time the ExUnregisterCallback function returns, we are GUARANTEED
* that our callback function will never be invoked again.
* Parameters: None.
* Returns: Nothing.
* Author: shouse, 4.15.02
* Notes: ExUnregisterCallback ensures that any in-progress invocations of the callback
* complete before it returns, so upon return, our callback will never be invoked
* again.
*/
VOID Init_deregister_tcp_callback ()
{
/* If we successfully registered a callback function, deregister it now. */
if (univ_tcp_callback_function != NULL)
ExUnregisterCallback(univ_tcp_callback_function);
/* Clean up the TCP connection notification callback function. */
univ_tcp_callback_function = NULL;
/* If we succeeded in creating/opening the callback object, dereference it now. */
if (univ_tcp_callback_object != NULL)
ObDereferenceObject(univ_tcp_callback_object);
/* Clean up our TCP connection notification callback object. */
univ_tcp_callback_object = NULL;
}
/*
* Function: Init_register_alternate_callback
* Description: This function registers our callback function with the NLB public connection
* notification callback object. We will begin receiving notifications as soon
* as other protocols begin sending them.
* Parameters: None.
* Returns: NTSTATUS - STATUS_SUCCESS if successful; an error code otherwise.
* Author: shouse, 8.1.02
* Notes:
*/
NTSTATUS Init_register_alternate_callback ()
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING CallbackName;
NTSTATUS Status;
/* Initialize the name of the NLB public connection notification object. */
RtlInitUnicodeString(&CallbackName, NLB_CONNECTION_CALLBACK_NAME);
/* Initialize the object attributes. */
InitializeObjectAttributes(&ObjectAttributes, &CallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
/* Create (or open) the callback. */
Status = ExCreateCallback(&univ_alternate_callback_object, &ObjectAttributes, TRUE, TRUE);
if (Status == STATUS_SUCCESS)
{
/* Register our callback function, which will be invoked by protocols as connections
are created, established and subsequently torn-down, */
univ_alternate_callback_function = ExRegisterCallback(univ_alternate_callback_object, Main_alternate_callback, NULL);
/* A return value of NULL indicates a failure to register our callback function.
Translate to an error code and relay the failure back to our caller. */
if (univ_alternate_callback_function == NULL)
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}
/*
* Function: Init_deregister_alternate_callback
* Description: If the NLB public connection notification callback is registered,
* this function de-registers our callback function and dereferences
* the connection notification callback object. Note that by the
* time the ExUnregisterCallback function returns, we are GUARANTEED
* that our callback function will never be invoked again.
* Parameters: None.
* Returns: Nothing.
* Author: shouse, 4.15.02
* Notes: ExUnregisterCallback ensures that any in-progress invocations of the callback
* complete before it returns, so upon return, our callback will never be invoked
* again.
*/
VOID Init_deregister_alternate_callback ()
{
/* If we successfully registered a callback function, deregister it now. */
if (univ_alternate_callback_function != NULL)
ExUnregisterCallback(univ_alternate_callback_function);
/* Clean up the NLB public connection notification callback function. */
univ_alternate_callback_function = NULL;
/* If we succeeded in creating/opening the callback object, dereference it now. */
if (univ_alternate_callback_object != NULL)
ObDereferenceObject(univ_alternate_callback_object);
/* Clean up our NLB public connection notification callback object. */
univ_alternate_callback_object = NULL;
}
#endif
ULONG NLBMiniportCount = 0;
enum _DEVICE_STATE {
PS_DEVICE_STATE_READY = 0, // ready for create/delete
PS_DEVICE_STATE_CREATING, // create operation in progress
PS_DEVICE_STATE_DELETING // delete operation in progress
} NLBControlDeviceState = PS_DEVICE_STATE_READY;
/*
* Function:
* Purpose: This function is called by Prot_bind and registers the IOCTL interface for WLBS.
* The device is registered only when binding to the first network adapter.
* Author: shouse, 3.1.01 - Copied largely from the sample IM driver net\ndis\samples\im\
* Revision : karthicn, 12.17.01 - Added call to initialize WMI for event support
*/
NDIS_STATUS Init_register_device (BOOL *pbFirstMiniport) {
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
UNICODE_STRING DeviceName;
UNICODE_STRING DeviceLinkUnicodeString;
PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION];
UINT i;
UNIV_PRINT_INFO(("Init_register_device: Entering, NLBMiniportCount=%u", NLBMiniportCount));
TRACE_INFO("->%!FUNC! Entering, NLBMiniportCount=%u", NLBMiniportCount);
*pbFirstMiniport = FALSE;
NdisAcquireSpinLock(&univ_bind_lock);
++NLBMiniportCount;
if (1 == NLBMiniportCount)
{
ASSERT(NLBControlDeviceState != PS_DEVICE_STATE_CREATING);
*pbFirstMiniport = TRUE;
UNIV_PRINT_INFO(("Init_register_device: Registering IOCTL interface"));
TRACE_INFO("%!FUNC! Registering IOCTL interface");
/* Another thread could be running Init_Deregister_device() on behalf
of another miniport instance. If so, wait for it to exit. */
while (NLBControlDeviceState != PS_DEVICE_STATE_READY)
{
NdisReleaseSpinLock(&univ_bind_lock);
NdisMSleep(1);
NdisAcquireSpinLock(&univ_bind_lock);
}
NLBControlDeviceState = PS_DEVICE_STATE_CREATING;
NdisReleaseSpinLock(&univ_bind_lock);
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
DispatchTable[i] = Main_dispatch;
NdisInitUnicodeString(&DeviceName, CVY_DEVICE_NAME);
NdisInitUnicodeString(&DeviceLinkUnicodeString, CVY_DOSDEVICE_NAME);
/* Create a device object and register our dispatch handlers. */
Status = NdisMRegisterDevice(univ_wrapper_handle, &DeviceName, &DeviceLinkUnicodeString,
&DispatchTable[0], &univ_device_object, &univ_device_handle);
if (Status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT((" ** Error registering device with NDIS %x", Status));
__LOG_MSG1(MSG_ERROR_REGISTERING, MSG_NONE, Status);
TRACE_INFO("%!FUNC! Error registering device with NDIS 0x%x", Status);
univ_device_object = NULL;
univ_device_handle = NULL;
}
else
{
/*
Even if NdisMRegisterDevice( ) returned NDIS_STATUS_SUCCESS, we used to
check if univ_device_handle was null. If it was null, it was considered
an error and we did not call NdisMDeRegisterDevice(). Per DDK & verified
by AliD, we only need to check for the return value. So, I removed the
additional check. However, since we are not aware of the reasons for the
introduction of the additional check, I am adding the following ASSERTs,
just in case.
--KarthicN, 03-07-02
*/
ASSERT(univ_device_object != NULL);
ASSERT(univ_device_handle != NULL);
}
/* Initialize WMI */
NlbWmi_Initialize(); // If non-null, it uses univ_device_object to register with WMI
#if defined (NLB_TCP_NOTIFICATION)
/* If TCP connection notification is turned on, then register our callback function. */
if (NLB_TCP_NOTIFICATION_ON())
{
/* Initialize the TCP connection notification callback. */
Status = Init_register_tcp_callback();
if (Status != STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Init_register_device: Could not create/open TCP connection notification callback, Status=0x%08x", Status));
TRACE_CRIT("%!FUNC! Could not create/open TCP connection notification callback, Status=0x%08x", Status);
__LOG_MSG1(MSG_WARN_TCP_CALLBACK_OPEN_FAILED, MSG_NONE, Status);
}
/* If NLB public connection notification is turned on, then register our callback function. */
}
else if (NLB_ALTERNATE_NOTIFICATION_ON())
{
/* Initialize the NLB public connection notification callback. */
Status = Init_register_alternate_callback();
if (Status != STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Init_register_device: Could not create/open NLB public connection notification callback, Status=0x%08x", Status));
TRACE_CRIT("%!FUNC! Could not create/open NLB public connection notification callback, Status=0x%08x", Status);
__LOG_MSG1(MSG_WARN_ALTERNATE_CALLBACK_OPEN_FAILED, MSG_NONE, Status);
}
}
#endif
NdisAcquireSpinLock(&univ_bind_lock);
NLBControlDeviceState = PS_DEVICE_STATE_READY;
}
NdisReleaseSpinLock(&univ_bind_lock);
UNIV_PRINT_INFO(("Init_register_device: return=0x%x", Status));
TRACE_INFO("<-%!FUNC! return=0x%x", Status);
return (Status);
}
/*
* Function:
* Purpose: This function is called by Prot_unbind and deregisters the IOCTL interface for WLBS.
* The device is deregistered only when we unbind from the last network adapter
* Author: shouse, 3.1.01 - Copied largely from the sample IM driver net\ndis\samples\im\
* Revision : karthicn, 12.17.01 - Added call to de-initialize from WMI for event support
*/
NDIS_STATUS Init_deregister_device (VOID) {
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
UNIV_PRINT_INFO(("Init_deregister_device: Entering, NLBMiniportCount=%u", NLBMiniportCount));
TRACE_INFO("->%!FUNC! Entering, NLBMiniportCount=%u", NLBMiniportCount);
NdisAcquireSpinLock(&univ_bind_lock);
ASSERT(NLBMiniportCount > 0);
--NLBMiniportCount;
if (0 == NLBMiniportCount)
{
/* All miniport instances have been halted. Deregisterthe control device. */
ASSERT(NLBControlDeviceState == PS_DEVICE_STATE_READY);
/* Block Init_register_device() while we release the control
device lock and deregister the device. */
NLBControlDeviceState = PS_DEVICE_STATE_DELETING;
NdisReleaseSpinLock(&univ_bind_lock);
#if defined (NLB_HOOK_ENABLE)
/* If the last miniport instance is going away, forcefully de-register all
registered global hooks now, before we remove the IOCTL interface. */
Init_deregister_hooks();
#endif
// Fire wmi event to indicate NLB unbinding from the last nic
if (NlbWmiEvents[ShutdownEvent].Enable)
{
NlbWmi_Fire_Event(ShutdownEvent, NULL, 0);
}
else
{
TRACE_VERB("%!FUNC! NOT generating Shutdown event 'cos its generation is disabled");
}
#if defined (NLB_TCP_NOTIFICATION)
/* If TCP connection notification is turned on, then de-register our callback function. */
if (NLB_TCP_NOTIFICATION_ON())
{
/* Initialize the TCP connection notification callback. */
Init_deregister_tcp_callback();
}
/* If NLB public connection notification is turned on, then de-register our callback function. */
else if (NLB_ALTERNATE_NOTIFICATION_ON())
{
/* Initialize the NLB public connection notification callback. */
Init_deregister_alternate_callback();
}
#endif
/* DeRegister with WMI */
NlbWmi_Shutdown();
UNIV_PRINT_INFO(("Init_deregister_device: Deleting IOCTL interface"));
TRACE_INFO("%!FUNC! Deleting IOCTL interface");
if (univ_device_handle != NULL)
{
Status = NdisMDeregisterDevice(univ_device_handle);
univ_device_object = NULL;
univ_device_handle = NULL;
}
NdisAcquireSpinLock(&univ_bind_lock);
NLBControlDeviceState = PS_DEVICE_STATE_READY;
}
NdisReleaseSpinLock(&univ_bind_lock);
UNIV_PRINT_INFO(("Init_deregister_Device: return=0x%x", Status));
TRACE_INFO("<-%!FUNC! return=0x%x", Status);
return Status;
}