Windows-Server-2003/net/wlbs/driver/prot.c

2012 lines
65 KiB
C

/*++
Copyright(c) 1998,99 Microsoft Corporation
Module Name:
prot.c
Abstract:
Windows Load Balancing Service (WLBS)
Driver - lower-level (protocol) layer of intermediate miniport
Author:
kyrilf
--*/
#define NDIS50 1
#define NDIS51 1
#include <ndis.h>
#include <strsafe.h>
#include "prot.h"
#include "nic.h"
#include "main.h"
#include "util.h"
#include "univ.h"
#include "log.h"
#include "nlbwmi.h"
#include "init.h"
#include "prot.tmh"
/* GLOBALS */
NTHALAPI KIRQL KeGetCurrentIrql();
static ULONG log_module_id = LOG_MODULE_PROT;
/* PROCEDURES */
VOID Prot_bind ( /* PASSIVE_IRQL */
PNDIS_STATUS statusp,
NDIS_HANDLE bind_handle,
PNDIS_STRING device_name,
PVOID reg_path,
PVOID reserved)
{
NDIS_STATUS status;
NDIS_STATUS error_status;
PMAIN_CTXT ctxtp;
ULONG ret;
UINT medium_index;
ULONG i;
ULONG peek_size;
ULONG tmp;
ULONG xferred;
ULONG needed;
ULONG result;
PNDIS_REQUEST request;
MAIN_ACTION act;
INT adapter_index;
PMAIN_ADAPTER adapterp = NULL;
NDIS_HANDLE ctxt_handle;
NDIS_HANDLE config_handle;
PNDIS_CONFIGURATION_PARAMETER param;
NDIS_STRING device_str = NDIS_STRING_CONST ("UpperBindings");
BOOL bFirstMiniport = FALSE;
/* make sure we are not attempting to bind to ourselves */
/* PASSIVE_LEVEL - %ls is OK. */
UNIV_PRINT_INFO(("Prot_bind: Binding to %ls", device_name -> Buffer));
adapter_index = Main_adapter_get (device_name -> Buffer);
if (adapter_index != MAIN_ADAPTER_NOT_FOUND)
{
UNIV_PRINT_CRIT(("Prot_bind: Already bound to this device 0x%x", adapter_index));
TRACE_CRIT("%!FUNC! Already bound to this device 0x%x", adapter_index);
*statusp = NDIS_STATUS_FAILURE;
UNIV_PRINT_INFO(("Prot_bind: return=NDIS_STATUS_FAILURE"));
TRACE_INFO("%!FUNC! return=NDIS_STATUS_FAILURE");
return;
}
adapter_index = Main_adapter_selfbind (device_name -> Buffer);
if (adapter_index != MAIN_ADAPTER_NOT_FOUND)
{
UNIV_PRINT_CRIT(("Prot_bind: Attempting to bind to ourselves 0x%x", adapter_index));
TRACE_CRIT("%!FUNC! Attempting to bind to ourselves 0x%x", adapter_index);
*statusp = NDIS_STATUS_FAILURE;
UNIV_PRINT_INFO(("Prot_bind: return=NDIS_STATUS_FAILURE"));
TRACE_INFO("%!FUNC! return=NDIS_STATUS_FAILURE");
return;
}
adapter_index = Main_adapter_alloc (device_name);
if (adapter_index == MAIN_ADAPTER_NOT_FOUND)
{
UNIV_PRINT_CRIT(("Prot_bind: Unable to allocate memory for adapter 0x%x", univ_adapters_count));
TRACE_CRIT("%!FUNC! Unable to allocate memory for adapter 0x%x", univ_adapters_count);
*statusp = NDIS_STATUS_FAILURE;
UNIV_PRINT_INFO(("Prot_bind: return=NDIS_STATUS_FAILURE"));
TRACE_INFO("%!FUNC! return=NDIS_STATUS_FAILURE");
return;
}
adapterp = &(univ_adapters [adapter_index]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
NdisAcquireSpinLock(& univ_bind_lock);
adapterp -> bound = TRUE;
NdisReleaseSpinLock(& univ_bind_lock);
UNIV_PRINT_VERB(("Prot_bind: Devicename length %d max length %d",
device_name -> Length, device_name -> MaximumLength));
TRACE_VERB("%!FUNC! Devicename length %d max length %d",
device_name -> Length, device_name -> MaximumLength);
/* This memory is allocated by Main_adapter_alloc(). */
UNIV_ASSERT(adapterp->device_name);
NdisMoveMemory (adapterp -> device_name,
device_name -> Buffer,
device_name -> Length);
adapterp -> device_name_len = device_name -> MaximumLength;
adapterp -> device_name [(device_name -> Length)/sizeof (WCHAR)] = UNICODE_NULL;
/* This memory is allocated by Main_adapter_alloc(). */
UNIV_ASSERT(adapterp->ctxtp);
/* initialize context */
ctxtp = adapterp -> ctxtp;
NdisZeroMemory (ctxtp, sizeof (MAIN_CTXT));
NdisAcquireSpinLock (& univ_bind_lock);
ctxtp -> code = MAIN_CTXT_CODE;
ctxtp -> bind_handle = bind_handle;
ctxtp -> adapter_id = adapter_index;
ctxtp -> requests_pending = 0;
NdisReleaseSpinLock (& univ_bind_lock);
/* karthicn, 11.28.01 - If it is the first nic that we are binding to, Create the IOCTL interface.
This was previously done in Nic_init. It is moved here just to maintain consistency with the
removal of the IOCTL interface. The IOCTL interface is now removed from Prot_unbind (used
to be in Nic_halt).
DO NOT call this function with the univ_bind_lock acquired. */
Init_register_device(&bFirstMiniport);
NdisInitializeEvent (& ctxtp -> completion_event);
NdisResetEvent (& ctxtp -> completion_event);
/* bind to specified adapter */
ctxt_handle = (NDIS_HANDLE) ctxtp;
NdisOpenAdapter (& status, & error_status, & ctxtp -> mac_handle,
& medium_index, univ_medium_array, UNIV_NUM_MEDIUMS,
univ_prot_handle, ctxtp, device_name, 0, NULL);
/* if pending - wait for Prot_open_complete to set the completion event */
if (status == NDIS_STATUS_PENDING)
{
/* We can't wait at DISPATCH_LEVEL. */
UNIV_ASSERT(KeGetCurrentIrql() <= PASSIVE_LEVEL);
ret = NdisWaitEvent(& ctxtp -> completion_event, UNIV_WAIT_TIME);
if (! ret)
{
UNIV_PRINT_CRIT(("Prot_bind: Error waiting for event"));
TRACE_CRIT("%!FUNC! Error waiting for event");
__LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status);
* statusp = status;
NdisAcquireSpinLock(& univ_bind_lock);
adapterp -> bound = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
Main_adapter_put (adapterp);
UNIV_PRINT_INFO(("Prot_bind: return=0x%x", status));
TRACE_INFO("%!FUNC! return=0x%x", status);
return;
}
status = ctxtp -> completion_status;
}
/* check binding status */
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error openning adapter %x", status));
TRACE_CRIT("%!FUNC! Error openning adapter 0x%x", status);
__LOG_MSG1 (MSG_ERROR_OPEN, device_name -> Buffer + (wcslen(L"\\DEVICE\\") * sizeof(WCHAR)), status);
/* If the failure was because the medium was not supported, log this. */
if (status == NDIS_STATUS_UNSUPPORTED_MEDIA) {
UNIV_PRINT_CRIT(("Prot_bind: Unsupported medium"));
TRACE_CRIT("%!FUNC! Unsupported medium");
__LOG_MSG (MSG_ERROR_MEDIA, MSG_NONE);
}
* statusp = status;
NdisAcquireSpinLock(& univ_bind_lock);
adapterp -> bound = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
Main_adapter_put (adapterp);
UNIV_PRINT_INFO(("Prot_bind: return=0x%x", status));
TRACE_INFO("%!FUNC! return=0x%x", status);
return;
}
ctxtp -> medium = univ_medium_array [medium_index];
/* V1.3.1b make sure that underlying adapter is of the supported medium */
if (ctxtp -> medium != NdisMedium802_3)
{
/* This should never happen because this error should be caught earlier
by NdisOpenAdapter, but we'll put another check here just in case. */
UNIV_PRINT_CRIT(("Prot_bind: Unsupported medium %d", ctxtp -> medium));
TRACE_CRIT("%!FUNC! Unsupported medium %d", ctxtp -> medium);
__LOG_MSG1 (MSG_ERROR_MEDIA, MSG_NONE, ctxtp -> medium);
goto error;
}
/* V1.3.0b extract current MAC address from the NIC - note that main is not
inited yet so we have to create a local action */
act.code = MAIN_ACTION_CODE;
act.ctxtp = ctxtp;
act.op.request.xferred = &xferred;
act.op.request.needed = &needed;
act.op.request.external = FALSE;
act.op.request.buffer_len = 0;
act.op.request.buffer = NULL;
NdisInitializeEvent(&act.op.request.event);
NdisResetEvent(&act.op.request.event);
NdisZeroMemory(&act.op.request.req, sizeof(NDIS_REQUEST));
request = &act.op.request.req;
request -> RequestType = NdisRequestQueryInformation;
request -> DATA . QUERY_INFORMATION . Oid = OID_802_3_CURRENT_ADDRESS;
request -> DATA . QUERY_INFORMATION . InformationBuffer = & ctxtp -> ded_mac_addr;
request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (CVY_MAC_ADR);
act.status = NDIS_STATUS_FAILURE;
status = Prot_request (ctxtp, & act, FALSE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error %x requesting station address %d %d", status, xferred, needed));
TRACE_CRIT("%!FUNC! Error 0x%x requesting station address %d %d", status, xferred, needed);
goto error;
}
/* V1.3.1b get MAC options */
request -> RequestType = NdisRequestQueryInformation;
request -> DATA . QUERY_INFORMATION . Oid = OID_GEN_MAC_OPTIONS;
request -> DATA . QUERY_INFORMATION . InformationBuffer = & result;
request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG);
act.status = NDIS_STATUS_FAILURE;
status = Prot_request (ctxtp, & act, FALSE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error %x requesting MAC options %d %d", status, xferred, needed));
TRACE_CRIT("%!FUNC! Error 0x%x requesting MAC options %d %d", status, xferred, needed);
goto error;
}
ctxtp -> mac_options = result;
/* Make sure the 802.3 adapter supports dynamically changing the MAC address of the NIC. */
if (!(ctxtp -> mac_options & NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE)) {
UNIV_PRINT_CRIT(("Prot_bind: Unsupported network adapter MAC options %x", ctxtp -> mac_options));
__LOG_MSG (MSG_ERROR_DYNAMIC_MAC, MSG_NONE);
TRACE_CRIT("%!FUNC! Unsupported network adapter MAC options 0x%x", ctxtp -> mac_options);
goto error;
}
status = Params_init (ctxtp, univ_reg_path, adapterp -> device_name + 8, & (ctxtp -> params));
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error retrieving registry parameters %x", status));
TRACE_CRIT("%!FUNC! Error retrieving registry parameters 0x%x", status);
ctxtp -> convoy_enabled = ctxtp -> params_valid = FALSE;
}
else
{
ctxtp -> convoy_enabled = ctxtp -> params_valid = TRUE;
}
/* Now, cat the cluster IP address onto the log message string to complete it. */
status = StringCbCat(ctxtp->log_msg_str, sizeof(ctxtp->log_msg_str), (PWSTR)ctxtp->params.cl_ip_addr);
if (FAILED(status)) {
UNIV_PRINT_INFO(("Prot_bind: Error 0x%08x -> Unable to cat the cluster IP address onto the log message string...", status));
TRACE_INFO("%!FUNC! Error 0x%08x -> Unable to cat the cluster IP address onto the log message string...", status);
}
/* Reset status, regardless of whether or not concatenating the string succeeded or failed. */
status = NDIS_STATUS_SUCCESS;
/* V1.3.2b figure out MTU of the medium */
request -> RequestType = NdisRequestQueryInformation;
request -> DATA . QUERY_INFORMATION . Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
request -> DATA . QUERY_INFORMATION . InformationBuffer = & result;
request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG);
act.status = NDIS_STATUS_FAILURE;
status = Prot_request (ctxtp, & act, FALSE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error %x requesting max frame size %d %d", status, xferred, needed));
TRACE_CRIT("%!FUNC! Error 0x%x requesting max frame size %d %d", status, xferred, needed);
ctxtp -> max_frame_size = CVY_MAX_FRAME_SIZE;
}
else
{
ctxtp -> max_frame_size = result;
}
/* figure out maximum multicast list size */
request -> RequestType = NdisRequestQueryInformation;
request -> DATA . QUERY_INFORMATION . Oid = OID_802_3_MAXIMUM_LIST_SIZE;
request -> DATA . QUERY_INFORMATION . InformationBufferLength = sizeof (ULONG);
request -> DATA . QUERY_INFORMATION . InformationBuffer = & ctxtp->max_mcast_list_size;
act.status = NDIS_STATUS_FAILURE;
status = Prot_request (ctxtp, & act, FALSE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error %x setting multicast address %d %d", status, xferred, needed));
TRACE_CRIT("%!FUNC! Error 0x%x setting multicast address %d %d", status, xferred, needed);
goto error;
}
/* initialize main context now */
status = Main_init (ctxtp);
/* Note: if Main_init fails, it calls Main_cleanup itself in order to un-do
any allocation it had successfully completed before the failure. */
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error initializing main module %x", status));
TRACE_CRIT("%!FUNC! Error initializing main module 0x%x", status);
goto error;
}
NdisAcquireSpinLock(& univ_bind_lock);
adapterp -> inited = TRUE;
/* Mark the operation in progress flag. This MUST be re-set upon exit from this bind
function. We set this flag to prevent IOCTL control operations from proceeding
before we're done binding. Once we set the inited flag above, IOCTLs will be allowed
to proceed (i.e., Main_ioctl and Main_ctrl will let them pass). Because we have not
yet quite finished initializing and setting cluster state, etc., we don't want IOCTLs
to go through. Marking the control operation in progress flag will ensure that any
incoming IOCTLs (and remote control, although at this point, remote control packets
cannot be received) fail until we're done binding and we re-set the flag. */
ctxtp->ctrl_op_in_progress = TRUE;
NdisReleaseSpinLock(& univ_bind_lock);
/* WLBS 2.3 start off by opening the config section and reading our instance
which we want to export for this binding */
NdisOpenProtocolConfiguration (& status, & config_handle, reg_path);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error openning protocol configuration %x", status));
TRACE_CRIT("%!FUNC! Error openning protocol configuration 0x%x", status);
goto error;
}
NdisReadConfiguration (& status, & param, config_handle, & device_str,
NdisParameterString);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error reading binding configuration %x", status));
TRACE_CRIT("%!FUNC! Error reading binding configuration 0x%x", status);
goto error;
}
/* free up whatever params allocated and get a new string to fit the
device name */
if (param -> ParameterData . StringData . Length >=
sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR))
{
UNIV_PRINT_CRIT(("Prot_bind: Nic name string too big %d %d\n", param -> ParameterData . StringData . Length, sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR)));
TRACE_CRIT("%!FUNC! Nic name string too big %d %d", param -> ParameterData . StringData . Length, sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR));
}
NdisMoveMemory (ctxtp -> virtual_nic_name,
param -> ParameterData . StringData . Buffer,
param -> ParameterData . StringData . Length <
sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR) ?
param -> ParameterData . StringData . Length :
sizeof (ctxtp -> virtual_nic_name) - sizeof (WCHAR));
* (PWSTR) ((PCHAR) ctxtp -> virtual_nic_name +
param -> ParameterData . StringData . Length) = UNICODE_NULL;
/* PASSIVE_LEVEL - %ls is OK. */
UNIV_PRINT_VERB(("Prot_bind: Read binding name %ls\n", ctxtp -> virtual_nic_name));
TRACE_VERB("%!FUNC! Read binding name %ls", ctxtp -> virtual_nic_name);
/* By default, we assume that the NIC is connected. This will be changed by
Nic_init and/or Prot_status later by querying the NIC miniport. */
ctxtp->media_connected = TRUE;
/* we should be all inited at this point! during announcement, Nic_init
will be called and it will start ping timer */
/* announce ourselves to the protocol above */
UNIV_PRINT_VERB(("Prot_bind: Calling nic_announce"));
TRACE_VERB("%!FUNC! Calling nic_announce");
status = Nic_announce (ctxtp);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_bind: Error announcing driver %x", status));
TRACE_CRIT("%!FUNC! Error announcing driver 0x%x", status);
goto error;
}
/* PASSIVE_LEVEL - %ls is OK. */
UNIV_PRINT_INFO(("Prot_bind: Bound to %ls with mac_handle=0x%p", device_name -> Buffer, ctxtp -> mac_handle));
TRACE_INFO("%!FUNC! Bound to %ls with mac_handle=0x%p", device_name -> Buffer, ctxtp -> mac_handle);
//
// If it is the first miniport that NLB is binding to, fire "Startup" wmi event.
// Ideally, this event should be fired from Init_register_device(), where the
// determination of, if it is the first miniport that NLB is binding to, is made.
// It is not being fired from Init_register_device() for the following reason:
// The request for registration with WMI happens in Init_register_device().
// WMI, in response to our request, sends down Ioctls to help us register with WMI,
// tell us of the events that any subscriber may be interested in.
// Only after these Ioctls are sent down, can we start firing the events.
// I have observed that the delay between our request for registration and the reception
// of Ioctls from WMI could sometimes be big. Ie. big enough to preclude us
// from firing this event from Init_register_device().
//
// Why did I choose this point in the function to fire the event ?
// This is logically the furthest point (thereby giving us the best possible chance that the Ioctls
// have come down and we are ready to fire events) in the function that we could fire this event from.
// Now, it is possible that even at this point, we have not yet received the Ioctls. We can not do
// much about that.
//
// Are there any side-effects of firing the Startup event from here instead of Init_register_device( ) ?
// There is one side-effect. If we encountered an error in the steps (above) after the call to
// Init_register_device(), we do a "goto error" whic calls Prot_unbind(). Prot_unbind() will
// fire a "Shutdown" event (if subscribed, ofcourse). So, in this case, a "Shutdown" event will
// have been fired without a preceding "Startup" event. This could confuse the subscriber.
// I have decided to live this side-effect for the following reasons:
// 1. Chances of encountering error in the steps after the call to Init_register_device() is quite rare.
// 2. A "Shutdown" event without a "Startup" event does NOT necessarily have to be confusing. It could
// be construed as "Attempted to start, but had problems, so shutting down". Yeah, that may be a
// bit of a copout.
//
// --KarthicN, 03-06-02
//
if (bFirstMiniport)
{
if(NlbWmiEvents[StartupEvent].Enable)
{
NlbWmi_Fire_Event(StartupEvent, NULL, 0);
}
else
{
TRACE_VERB("%!FUNC! NOT generating Startup event 'cos its generation is disabled");
}
}
/* at this point TCP/IP should have bound to us after we announced ourselves
to it and we are all done binding to NDIS below - all set! */
if (! ctxtp -> convoy_enabled)
{
LOG_MSG (MSG_ERROR_DISABLED, MSG_NONE);
TRACE_INFO("%!FUNC! Cluster mode cannot be enabled due to NLB parameters not being set, or set to incorrect values");
// If enabled, fire wmi event indicating binding & stopping of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_BOUND_AND_STOPPED);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_BOUND_AND_STOPPED 'cos NodeControlEvent generation disabled");
}
}
else
{
switch (ctxtp->params.init_state) {
case CVY_HOST_STATE_STARTED:
{
WCHAR num[20];
Univ_ulong_to_str(ctxtp->params.host_priority, num, 10);
LOG_MSG(MSG_INFO_STARTED, num);
TRACE_INFO("%!FUNC! Cluster mode started");
// If enabled, fire wmi event indicating binding & starting of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_BOUND_AND_STARTED);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_BOUND_AND_STARTED 'cos NodeControlEvent generation disabled");
}
// Assuming start of convergence
if (NlbWmiEvents[ConvergingEvent].Enable)
{
NlbWmi_Fire_ConvergingEvent(ctxtp,
NLB_EVENT_CONVERGING_NEW_MEMBER,
ctxtp->params.ded_ip_addr,
ctxtp->params.host_priority);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_CONVERGING_NEW_MEMBER, Convergnce NOT Initiated by Load_start() OR ConvergingEvent generation disabled");
}
ctxtp->convoy_enabled = TRUE;
break;
}
case CVY_HOST_STATE_STOPPED:
{
LOG_MSG(MSG_INFO_STOPPED, MSG_NONE);
TRACE_INFO("%!FUNC! Cluster mode stopped");
ctxtp->convoy_enabled = FALSE;
// If enabled, fire wmi event indicating binding & stopping of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_BOUND_AND_STOPPED);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_BOUND_AND_STOPPED 'cos NodeControlEvent generation disabled");
}
break;
}
case CVY_HOST_STATE_SUSPENDED:
{
LOG_MSG(MSG_INFO_SUSPENDED, MSG_NONE);
TRACE_INFO("%!FUNC! Cluster mode suspended");
ctxtp->convoy_enabled = FALSE;
// If enabled, fire wmi event indicating binding & suspending of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_BOUND_AND_SUSPENDED);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_BOUND_AND_SUSPENDED 'cos NodeControlEvent generation disabled");
}
break;
}
default:
LOG_MSG(MSG_INFO_STOPPED, MSG_NONE);
TRACE_CRIT("%!FUNC! Cluster mode invalid - cluster has been stopped");
ctxtp->convoy_enabled = FALSE;
// If enabled, fire wmi event indicating binding & stopping of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_BOUND_AND_STOPPED);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_BOUND_AND_STOPPED 'cos NodeControlEvent generation disabled");
}
break;
}
}
/* Re-set the operation in progress flag to begin allowing IOCTLs to proceed.
Note that it is not strictly necessary to hold the lock while resetting the
flag, but a condition may arise that an IOCTL that could have proceeded into
the critical section may fail unnecessarily. To prevent that possibility,
hold the univ_bind_lock while resetting the flag. Note that in "error" cases
(goto error;), it is not necessary to re-set the flag, as it will result in
a call to Prot_unbind and a failure of the bind anyway. */
ctxtp->ctrl_op_in_progress = FALSE;
UNIV_PRINT_INFO(("Prot_bind: return=0x%x", status));
TRACE_INFO("%!FUNC! return=0x%x", status);
* statusp = status;
return;
error:
* statusp = status;
Prot_unbind (& status, ctxtp, ctxtp);
UNIV_PRINT_INFO(("Prot_bind: return=0x%x", status));
TRACE_INFO("%!FUNC! return=0x%x", status);
return;
} /* end Prot_bind */
VOID Prot_unbind ( /* PASSIVE_IRQL */
PNDIS_STATUS statusp,
NDIS_HANDLE adapter_handle,
NDIS_HANDLE unbind_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
PMAIN_ACTION actp;
PMAIN_ADAPTER adapterp;
INT adapter_index;
UNIV_PRINT_INFO(("Prot_unbind: Unbinding, adapter_handle=0x%p", adapter_handle));
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapter_index = ctxtp -> adapter_id;
adapterp = & (univ_adapters [adapter_index]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
ctxtp -> unbind_handle = unbind_handle;
if (ctxtp->out_request != NULL)
{
actp = ctxtp->out_request;
ctxtp->out_request = NULL;
Prot_request_complete(ctxtp, & actp->op.request.req, NDIS_STATUS_FAILURE);
/* Note: No need to decrement the pending request counter for the second
time here, because we only ended up incrementing it once (in the initial
call to Prot_request). Prot_request_complete will effectively cancel
the request and decrement the counter appropriately. */
}
/* unannounce the nic now if it was announced before */
status = Nic_unannounce (ctxtp);
UNIV_PRINT_INFO(("Prot_unbind: Unannounced, status=0x%x", status));
TRACE_INFO("%!FUNC! Unannounced, status=0x%x", status);
/* if still bound (Prot_close was not called from Nic_halt) then close now */
status = Prot_close (adapterp);
UNIV_PRINT_INFO(("Prot_unbind: Closed, status=0x%x", status));
TRACE_INFO("%!FUNC! Closed, status=0x%x", status);
/* karthicn, 11.28.01 - If it is the last nic that we are unbinding from, remove the IOCTL interface.
This was previously done at the beginning of Nic_halt, which prevented firing of wmi events after
Nic_halt was called. This move allows us to fire events from Prot_close() (which is called at the
end of Nic_halt() & after as well)
DO NOT call this function with the univ_bind_lock acquired. */
Init_deregister_device();
Main_adapter_put (adapterp);
* statusp = status;
UNIV_PRINT_INFO(("Prot_unbind: return=0x%x", status));
TRACE_INFO("%!FUNC! return=0x%x", status);
return;
} /* end Prot_unbind */
VOID Prot_open_complete ( /* PASSIVE_IRQL */
NDIS_HANDLE adapter_handle,
NDIS_STATUS open_status,
NDIS_STATUS error_status)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
UNIV_PRINT_VERB(("Prot_open_complete: Called %x", ctxtp));
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
ctxtp -> completion_status = open_status;
NdisSetEvent (& ctxtp -> completion_event);
} /* end Prot_open_complete */
VOID Prot_close_complete ( /* PASSIVE_IRQL */
NDIS_HANDLE adapter_handle,
NDIS_STATUS status)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
UNIV_PRINT_VERB(("Prot_close_complete: Called %x %x", ctxtp, status));
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
ctxtp -> completion_status = status;
NdisSetEvent (& ctxtp -> completion_event);
} /* end Prot_close_complete */
VOID Prot_request_complete (
NDIS_HANDLE adapter_handle,
PNDIS_REQUEST request,
NDIS_STATUS status)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PMAIN_ACTION actp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
actp = CONTAINING_RECORD (request, MAIN_ACTION, op . request . req);
UNIV_ASSERT (actp -> code == MAIN_ACTION_CODE);
/* if request came from above - pass completion up */
if (actp -> op . request . external)
{
actp -> status = status;
Nic_request_complete (ctxtp -> prot_handle, actp);
}
/* handle internal request completion */
else
{
if (request -> RequestType == NdisRequestSetInformation)
{
* actp -> op . request . xferred =
request -> DATA . SET_INFORMATION . BytesRead;
* actp -> op . request . needed =
request -> DATA . SET_INFORMATION . BytesNeeded;
}
else
{
* actp -> op . request . xferred =
request -> DATA . QUERY_INFORMATION . BytesWritten;
* actp -> op . request . needed =
request -> DATA . QUERY_INFORMATION . BytesNeeded;
}
actp->status = status;
NdisSetEvent(&actp->op.request.event);
}
NdisInterlockedDecrement(&ctxtp->requests_pending);
} /* end Prot_request_complete */
#ifdef PERIODIC_RESET
extern ULONG resetting;
#endif
VOID Prot_reset_complete (
NDIS_HANDLE adapter_handle,
NDIS_STATUS status)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized");
return;
}
#ifdef PERIODIC_RESET
if (resetting)
{
resetting = FALSE;
TRACE_INFO("%!FUNC! resetting");
return;
}
#endif
Nic_reset_complete (ctxtp, status);
} /* end Prot_reset_complete */
VOID Prot_send_complete (
NDIS_HANDLE adapter_handle,
PNDIS_PACKET packet,
NDIS_STATUS status)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PNDIS_PACKET oldp;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
PMAIN_PROTOCOL_RESERVED resp;
LONG lock_value;
PMAIN_ADAPTER adapterp;
BOOLEAN set = FALSE;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized");
return;
}
MAIN_RESP_FIELD(packet, stack_left, pktstk, resp, TRUE);
if (resp -> type == MAIN_PACKET_TYPE_PING ||
resp -> type == MAIN_PACKET_TYPE_IGMP ||
resp -> type == MAIN_PACKET_TYPE_IDHB)
{
Main_send_done (ctxtp, packet, status);
return;
}
if (resp -> type == MAIN_PACKET_TYPE_CTRL)
{
UNIV_PRINT_VERB(("Prot_send_complete: Control packet send complete\n"));
Main_packet_put (ctxtp, packet, TRUE, status);
return;
}
UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_PASS, resp -> type);
oldp = Main_packet_put (ctxtp, packet, TRUE, status);
if (ctxtp -> packets_exhausted)
{
ctxtp -> packets_exhausted = FALSE;
}
Nic_send_complete (ctxtp, status, oldp);
} /* end Prot_send_complete */
NDIS_STATUS Prot_recv_indicate (
NDIS_HANDLE adapter_handle,
NDIS_HANDLE recv_handle,
PVOID head_buf,
UINT head_len,
PVOID look_buf,
UINT look_len,
UINT packet_len)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT)adapter_handle;
PMAIN_ADAPTER adapterp;
PNDIS_PACKET packet;
UNIV_ASSERT(ctxtp->code == MAIN_CTXT_CODE);
adapterp = &(univ_adapters[ctxtp->adapter_id]);
UNIV_ASSERT(adapterp->code == MAIN_ADAPTER_CODE);
UNIV_ASSERT(adapterp->ctxtp == ctxtp);
/* Check whether the driver has been announced to tcpip before processing any packets. */
if (!adapterp->inited || !adapterp->announced)
{
TRACE_CRIT("%!FUNC! Adapter not initialized or not announced");
return NDIS_STATUS_NOT_ACCEPTED;
}
/* Do not accept frames if the card below is resetting. */
if (ctxtp->reset_state != MAIN_RESET_NONE)
{
TRACE_CRIT("%!FUNC! Adapter is resetting");
return NDIS_STATUS_NOT_ACCEPTED;
}
/* Get the received packet from NDIS, if there is one. */
packet = NdisGetReceivedPacket(ctxtp->mac_handle, recv_handle);
/* If we successfully got a packet from NDIS, process the packet. */
if (packet != NULL)
{
INT references = 0;
/* Get the status from the received packet. */
NDIS_STATUS original_status = NDIS_GET_PACKET_STATUS(packet);
/* Set the status to be STATUS_RESOURCES to make sure the packet is
processed synchonrously within the context of this function call. */
NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_RESOURCES);
/* Call our packet receive handler. */
references = Prot_packet_recv(ctxtp, packet);
/* The remaining references on the packet MUST be zero, as enforced
by setting the packet status to STATUS_RESOURCES. */
UNIV_ASSERT(references == 0);
/* Restore the original packet status. */
NDIS_SET_PACKET_STATUS(packet, original_status);
}
/* If there was no associated packet, drop it - we don't handle this case anymore. */
else
{
UNIV_ASSERT(0);
/* Only warn the user if we haven't done so already. */
if (!ctxtp->recv_indicate_warned)
{
TRACE_CRIT("%!FUNC! Indicated receives with no corresponding packet are NOT supported");
/* Log an event to warn the user that this NIC is not supported by NLB. */
LOG_MSG(MSG_ERROR_RECEIVE_INDICATE, MSG_NONE);
/* Note that we have warned the user about this so we don't log an event
every time we receive a packet via this code path. */
ctxtp->recv_indicate_warned = TRUE;
}
return NDIS_STATUS_NOT_ACCEPTED;
}
/* Always return success, whether we accepted or dropped the packet
in the call to Prot_packet_recv. */
return NDIS_STATUS_SUCCESS;
}
VOID Prot_recv_complete (
NDIS_HANDLE adapter_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
UNIV_ASSERT(ctxtp->code == MAIN_CTXT_CODE);
Nic_recv_complete(ctxtp);
}
VOID Prot_transfer_complete (
NDIS_HANDLE adapter_handle,
PNDIS_PACKET packet,
NDIS_STATUS status,
UINT xferred)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PNDIS_PACKET oldp;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
PMAIN_PROTOCOL_RESERVED resp;
LONG lock_value;
PNDIS_BUFFER bufp;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized");
return;
}
MAIN_RESP_FIELD (packet, stack_left, pktstk, resp, FALSE);
UNIV_ASSERT_VAL (resp -> type == MAIN_PACKET_TYPE_TRANSFER, resp -> type);
if (status == NDIS_STATUS_SUCCESS)
{
MAIN_PACKET_INFO PacketInfo;
/* Call Main_recv_frame_parse merely to extract the packet length and "group". */
if (Main_recv_frame_parse(ctxtp, packet, &PacketInfo))
{
resp->len = PacketInfo.Length;
resp->group = PacketInfo.Group;
}
/* If we fail to fill in the group and length, just populate these
parameters with values that will not affect the statistics that
are updated in Main_packet_put. */
else
{
resp->len = 0;
resp->group = MAIN_FRAME_DIRECTED;
}
}
oldp = Main_packet_put (ctxtp, packet, FALSE, status);
Nic_transfer_complete (ctxtp, status, packet, xferred);
} /* end Prot_transfer_complete */
NDIS_STATUS Prot_PNP_handle (
NDIS_HANDLE adapter_handle,
PNET_PNP_EVENT pnp_event)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PNDIS_DEVICE_POWER_STATE device_state;
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
IOCTL_CVY_BUF ioctl_buf;
PMAIN_ACTION actp;
/* can happen when first initializing */
switch (pnp_event -> NetEvent)
{
case NetEventSetPower:
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
device_state = (PNDIS_DEVICE_POWER_STATE) (pnp_event -> Buffer);
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventSetPower %x", * device_state));
TRACE_VERB("%!FUNC! NetEventSetPower 0x%x", * device_state);
// If the specified device state is D0, then handle it first,
// else notify the protocols first and then handle it.
if (*device_state != NdisDeviceStateD0)
{
status = Nic_PNP_handle (ctxtp, pnp_event);
}
//
// Is the protocol transitioning from an On (D0) state to an Low Power State (>D0)
// If so, then set the standby_state Flag - (Block all incoming requests)
//
if (ctxtp->prot_pnp_state == NdisDeviceStateD0 &&
*device_state > NdisDeviceStateD0)
{
ctxtp->standby_state = TRUE;
}
//
// If the protocol is transitioning from a low power state to ON (D0), then clear the standby_state flag
// All incoming requests will be pended until the physical miniport turns ON.
//
if (ctxtp->prot_pnp_state > NdisDeviceStateD0 &&
*device_state == NdisDeviceStateD0)
{
ctxtp->standby_state = FALSE;
}
ctxtp -> prot_pnp_state = *device_state;
/* if we are being sent to standby, block outstanding requests and
sends */
if (*device_state > NdisDeviceStateD0)
{
/* sleep till outstanding sends complete */
while (1)
{
ULONG i;
/* #ps# -- ramkrish */
while (1)
{
NDIS_STATUS hide_status;
ULONG count;
hide_status = NdisQueryPendingIOCount (ctxtp -> mac_handle, & count);
if (hide_status != NDIS_STATUS_SUCCESS || count == 0)
break;
Nic_sleep (10);
}
// ASSERT - NdisQueryPendingIOCount should handle this
for (i = 0; i < ctxtp->num_send_packet_allocs; i++)
{
if (NdisPacketPoolUsage(ctxtp->send_pool_handle[i]) != 0)
break;
}
if (i >= ctxtp->num_send_packet_allocs)
break;
Nic_sleep(10);
}
/* sleep till outstanding requests complete */
while (ctxtp->requests_pending > 0)
{
Nic_sleep(10);
}
}
else
{
if (ctxtp->out_request != NULL)
{
NDIS_STATUS hide_status;
actp = ctxtp->out_request;
ctxtp->out_request = NULL;
hide_status = Prot_request(ctxtp, actp, actp->op.request.external);
if (hide_status != NDIS_STATUS_PENDING)
Prot_request_complete(ctxtp, & actp->op.request.req, hide_status);
/* Upon pending this request initially, we incremented the request pending
counter. Now that we have processed it, and in the process incremented
the pending request counter for the second time, we need to decrement it
here once. The second decrement is done in Prot_request_complete, which
either we just called explicitly, or will be called subsequently when
NDIS completes the request asynchronously. */
NdisInterlockedDecrement(&ctxtp->requests_pending);
}
}
if (*device_state == NdisDeviceStateD0)
{
status = Nic_PNP_handle (ctxtp, pnp_event);
}
break;
case NetEventReconfigure:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventReconfigure"));
TRACE_VERB("%!FUNC! NetEventReconfigure");
if (adapter_handle == NULL) // This happens if the device is being enabled through the device manager.
{
UNIV_PRINT_VERB(("Prot_PNP_handle: Enumerate protocol bindings"));
NdisReEnumerateProtocolBindings (univ_prot_handle);
TRACE_VERB("%!FUNC! Enumerate protocol bindings");
return NDIS_STATUS_SUCCESS;
}
/* gets called when something changes in our setup from notify
object */
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
Main_ctrl (ctxtp, IOCTL_CVY_RELOAD, &ioctl_buf, NULL, NULL, NULL);
status = Nic_PNP_handle (ctxtp, pnp_event);
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventReconfigure done %d %x", ioctl_buf . ret_code, status));
TRACE_VERB("%!FUNC! NetEventReconfigure done %d 0x%x", ioctl_buf . ret_code, status);
break;
case NetEventQueryPower:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventQueryPower"));
TRACE_VERB("%!FUNC! NetEventQueryPower");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
case NetEventQueryRemoveDevice:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventQueryRemoveDevice"));
TRACE_VERB("%!FUNC! NetEventQueryRemoveDevice");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
case NetEventCancelRemoveDevice:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventCancelRemoveDevice"));
TRACE_VERB("%!FUNC! NetEventCancelRemoveDevice");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
case NetEventBindList:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventBindList"));
TRACE_VERB("%!FUNC! NetEventBindList");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
case NetEventBindsComplete:
UNIV_PRINT_VERB(("Prot_PNP_handle: NetEventBindComplete"));
TRACE_VERB("%!FUNC! NetEventBindComplete");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
default:
UNIV_PRINT_VERB(("Prot_PNP_handle: New event"));
TRACE_VERB("%!FUNC! New event");
if (adapter_handle == NULL)
{
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Nic_PNP_handle (ctxtp, pnp_event);
break;
}
return status; /* Always return NDIS_STATUS_SUCCESS or
the return value of NdisIMNotifyPnPEvent */
} /* end Nic_PNP_handle */
VOID Prot_status (
NDIS_HANDLE adapter_handle,
NDIS_STATUS status,
PVOID stat_buf,
UINT stat_len)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
KIRQL irql;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
UNIV_PRINT_VERB(("Prot_status: Called for adapter %d for notification %d: inited=%d, announced=%d", ctxtp -> adapter_id, status, adapterp->inited, adapterp->announced));
TRACE_VERB("%!FUNC! Adapter %d for notification %d: inited=%d, announced=%d", ctxtp -> adapter_id, status, adapterp->inited, adapterp->announced);
if (! adapterp -> inited || ! adapterp -> announced)
{
TRACE_CRIT("%!FUNC! adapter not initialized or not announced");
return;
}
switch (status)
{
case NDIS_STATUS_WAN_LINE_UP:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_WAN_LINE_UP"));
break;
case NDIS_STATUS_WAN_LINE_DOWN:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_WAN_LINE_DOWN"));
break;
case NDIS_STATUS_MEDIA_CONNECT:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_MEDIA_CONNECT"));
/* V1.3.2b */
ctxtp -> media_connected = TRUE;
break;
case NDIS_STATUS_MEDIA_DISCONNECT:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_MEDIA_DISCONNECT"));
/* V1.3.2b */
ctxtp -> media_connected = FALSE;
break;
case NDIS_STATUS_HARDWARE_LINE_UP:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_HARDWARE_LINE_UP"));
break;
case NDIS_STATUS_HARDWARE_LINE_DOWN:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_HARDWARE_LINE_DOWN"));
break;
case NDIS_STATUS_INTERFACE_UP:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_INTERFACE_UP"));
break;
case NDIS_STATUS_INTERFACE_DOWN:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_INTERFACE_DOWN"));
break;
/* V1.1.2 */
case NDIS_STATUS_RESET_START:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_RESET_START"));
ctxtp -> reset_state = MAIN_RESET_START;
ctxtp -> recv_indicated = FALSE;
break;
case NDIS_STATUS_RESET_END:
UNIV_PRINT_VERB(("Prot_status: NDIS_STATUS_RESET_END"));
// apparently alteon adapter does not call status complete function,
// so need to transition to none state here in order to prevent hangs
//ctxtp -> reset_state = MAIN_RESET_END;
ctxtp -> reset_state = MAIN_RESET_NONE;
break;
default:
break;
}
if (! MAIN_PNP_DEV_ON(ctxtp))
{
TRACE_CRIT("%!FUNC! return pnp device not on");
return;
}
Nic_status (ctxtp, status, stat_buf, stat_len);
} /* end Prot_status */
VOID Prot_status_complete (
NDIS_HANDLE adapter_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized");
return;
}
/* V1.1.2 */
if (ctxtp -> reset_state == MAIN_RESET_END)
{
ctxtp -> reset_state = MAIN_RESET_NONE;
UNIV_PRINT_VERB(("Prot_status_complete: NDIS_STATUS_RESET_END completed"));
}
else if (ctxtp -> reset_state == MAIN_RESET_START)
{
ctxtp -> reset_state = MAIN_RESET_START_DONE;
UNIV_PRINT_VERB(("Prot_status_complete: NDIS_STATUS_RESET_START completed"));
}
if (! MAIN_PNP_DEV_ON(ctxtp))
{
TRACE_CRIT("%!FUNC! return pnp device not on");
return;
}
Nic_status_complete (ctxtp);
} /* end Prot_status_complete */
/* helpers for nic layer */
NDIS_STATUS Prot_close ( /* PASSIVE_IRQL */
PMAIN_ADAPTER adapterp
)
{
NDIS_STATUS status;
ULONG ret;
PMAIN_CTXT ctxtp;
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
ctxtp = adapterp -> ctxtp;
/* close binding */
NdisAcquireSpinLock(& univ_bind_lock);
if ( ! adapterp -> bound || ctxtp->mac_handle == NULL)
{
/* cleanup only on the second time we are entering Prot_close, which
is called by both Nic_halt and Prot_unbind. the last one to be
called will cleanup the context since they both use it. if both
do not get called, then it will be cleaned up by Prot_bind before
allocating a new one of Init_unload before unloading the driver. */
if (adapterp -> inited)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp -> inited = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
Main_cleanup (ctxtp);
}
else
NdisReleaseSpinLock(& univ_bind_lock);
Main_adapter_put (adapterp);
return NDIS_STATUS_SUCCESS;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp -> bound = FALSE;
ctxtp -> convoy_enabled = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
LOG_MSG (MSG_INFO_STOPPED, MSG_NONE);
// If enabled, fire wmi event indicating unbinding of nlb
if (NlbWmiEvents[NodeControlEvent].Enable)
{
NlbWmi_Fire_NodeControlEvent(ctxtp, NLB_EVENT_NODE_UNBOUND);
}
else
{
TRACE_VERB("%!FUNC! NOT generating NLB_EVENT_NODE_UNBOUND 'cos NodeControlEvent generation disabled");
}
NdisResetEvent (& ctxtp -> completion_event);
NdisCloseAdapter (& status, ctxtp -> mac_handle);
/* if pending - wait for Prot_close_complete to set the completion event */
if (status == NDIS_STATUS_PENDING)
{
/* We can't wait at DISPATCH_LEVEL. */
UNIV_ASSERT(KeGetCurrentIrql() <= PASSIVE_LEVEL);
ret = NdisWaitEvent(& ctxtp -> completion_event, UNIV_WAIT_TIME);
if (! ret)
{
UNIV_PRINT_CRIT(("Prot_close: Error waiting for event"));
LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status);
TRACE_CRIT("%!FUNC! Error waiting for event");
return NDIS_STATUS_FAILURE;
}
status = ctxtp -> completion_status;
}
/* At this point,wait for all pending recvs to be completed and then return */
ctxtp -> mac_handle = NULL;
ctxtp -> prot_handle = NULL;
/* check binding status */
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Prot_close: Error closing adapter %x", status));
LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status);
TRACE_CRIT("%!FUNC! Error closing adapter 0x%x", status);
}
/* if nic level is not announced anymore - safe to remove context now */
NdisAcquireSpinLock(& univ_bind_lock);
if (! adapterp -> announced || ctxtp -> prot_handle == NULL)
{
if (adapterp -> inited)
{
adapterp -> inited = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
Main_cleanup (ctxtp);
}
else
NdisReleaseSpinLock(& univ_bind_lock);
Main_adapter_put (adapterp);
}
else
NdisReleaseSpinLock(& univ_bind_lock);
return status;
} /* end Prot_close */
NDIS_STATUS Prot_request (
PMAIN_CTXT ctxtp,
PMAIN_ACTION actp,
ULONG external)
{
NDIS_STATUS status;
PNDIS_REQUEST request = &actp->op.request.req;
ULONG ret;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
actp->op.request.external = external;
if (ctxtp -> unbind_handle) // Prot_unbind was called
{
return NDIS_STATUS_FAILURE;
}
// if the Protocol device state is OFF, then the IM driver cannot send the
// request below and must pend it
if (ctxtp->prot_pnp_state > NdisDeviceStateD0)
{
if (external) {
/* If the request was external (from the protocol bound to our miniport,
then pend the request. Ndis serializes requests such that only one
request can ever be outstanding at a given time. Therefore, a queue
is not necessary. */
UNIV_ASSERT (ctxtp->out_request == NULL);
if (ctxtp->out_request == NULL)
{
/* If there are no outstanding requests as of yet, store a pointer
to the request so that we can complete it later. */
ctxtp->out_request = actp;
}
else
{
/* Otherwise, if a request is already pending, fail this new one.
This should never happen, as NDIS serializes miniport requests. */
return NDIS_STATUS_FAILURE;
}
/* Note: this counter will also be incremented when we call Prot_request
again later to continue processing the request. We have to ensure,
then, that it is likewise decremented twice whenever serviced. */
NdisInterlockedIncrement(&ctxtp->requests_pending);
return NDIS_STATUS_PENDING;
} else {
/* If the request was internal, then fail it - if we return PENDING, it
will fail anyway, as it expects us to wait for the request to complete
before returning. */
return NDIS_STATUS_FAILURE;
}
}
NdisResetEvent(&actp->op.request.event);
NdisInterlockedIncrement(&ctxtp->requests_pending);
NdisRequest(&status, ctxtp->mac_handle, request);
/* if pending - wait for Prot_request_complete to set the completion event */
if (status != NDIS_STATUS_PENDING)
{
NdisInterlockedDecrement(&ctxtp->requests_pending);
if (request -> RequestType == NdisRequestSetInformation)
{
* actp -> op . request . xferred =
request -> DATA . SET_INFORMATION . BytesRead;
* actp -> op . request . needed =
request -> DATA . SET_INFORMATION . BytesNeeded;
}
else
{
* actp -> op . request . xferred =
request -> DATA . QUERY_INFORMATION . BytesWritten;
* actp -> op . request . needed =
request -> DATA . QUERY_INFORMATION . BytesNeeded;
}
}
else if (! external)
{
/* We can't wait at DISPATCH_LEVEL. */
UNIV_ASSERT(KeGetCurrentIrql() <= PASSIVE_LEVEL);
ret = NdisWaitEvent(&actp->op.request.event, UNIV_WAIT_TIME);
if (! ret)
{
UNIV_PRINT_CRIT(("Prot_request: Error waiting for event"));
TRACE_CRIT("%!FUNC! Error=0x%x waiting for event", status);
LOG_MSG1 (MSG_ERROR_INTERNAL, MSG_NONE, status);
status = NDIS_STATUS_FAILURE;
return status;
}
status = actp->status;
}
return status;
} /* end Prot_request */
NDIS_STATUS Prot_reset (
PMAIN_CTXT ctxtp)
{
NDIS_STATUS status;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
NdisReset (& status, ctxtp -> mac_handle);
return status;
} /* end Prot_reset */
VOID Prot_packets_send (
PMAIN_CTXT ctxtp,
PPNDIS_PACKET packets,
UINT num_packets)
{
PNDIS_PACKET array[CVY_MAX_SEND_PACKETS];
PNDIS_PACKET filtered_array[CVY_MAX_SEND_PACKETS];
UINT count = 0, filtered_count = 0, i;
NDIS_STATUS status;
PNDIS_PACKET newp;
LONG lock_value;
PMAIN_ACTION actp;
ULONG exhausted;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
/* Do not accept frames if the card below is resetting. */
if (ctxtp->reset_state != MAIN_RESET_NONE || ! MAIN_PNP_DEV_ON(ctxtp))
{
TRACE_CRIT("%!FUNC! card is resetting");
ctxtp->cntr_xmit_err++;
status = NDIS_STATUS_FAILURE;
goto fail;
}
for (count = i = 0;
count < (num_packets > CVY_MAX_SEND_PACKETS ? CVY_MAX_SEND_PACKETS : num_packets);
count ++)
{
/* Figure out if we need to handle this packet. */
newp = Main_send(ctxtp, packets[count], &exhausted);
if (newp == NULL)
{
/* If we ran out of packets, get out of the loop. */
if (exhausted)
{
UNIV_PRINT_CRIT(("Prot_packets_send: Error xlating packet"));
TRACE_CRIT("%!FUNC! Error xlating packet");
ctxtp->packets_exhausted = TRUE;
break;
}
/* If the packet was filtered out, set status to success
to calm TCP/IP down and go on to the next one. */
else
{
/* Mark the packet as success. */
NDIS_SET_PACKET_STATUS(packets[count], NDIS_STATUS_SUCCESS);
/* Store a pointer to the filtered packet in the filtered
packet array. */
filtered_array[filtered_count] = packets[count];
/* Increment the array index. */
filtered_count++;
// ctxtp->sends_filtered ++;
continue;
}
}
/* Mark the packet as pending send. */
NDIS_SET_PACKET_STATUS(packets[count], NDIS_STATUS_PENDING);
/* Store a pointer to this packet in the array of packets to send. */
array[i] = newp;
/* Increment the array index. */
i++;
}
/* If there are packets to send, send them. */
if (i > 0)
NdisSendPackets(ctxtp->mac_handle, array, i);
/* For those packets we've filtered out, notify the protocol that
the send is "complete". */
for (i = 0; i < filtered_count; i++)
Nic_send_complete(ctxtp, NDIS_STATUS_SUCCESS, filtered_array[i]);
fail:
/* Any remaining packets cannot be handled; there is no space in the
pending queue, which is limited to CVY_MAX_SEND_PACKETS packets. */
for (i = count; i < num_packets; i++)
{
/* Mark the packet as failed. */
NDIS_SET_PACKET_STATUS(packets[i], NDIS_STATUS_FAILURE);
/* Notify the protocol that the send is "complete". */
Nic_send_complete(ctxtp, NDIS_STATUS_FAILURE, packets[i]);
}
}
INT Prot_packet_recv (
NDIS_HANDLE adapter_handle,
PNDIS_PACKET packet)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
PMAIN_ADAPTER adapterp;
PNDIS_PACKET newp;
NDIS_STATUS status;
PMAIN_PROTOCOL_RESERVED resp;
LONG lock_value;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
UNIV_ASSERT(ctxtp->code == MAIN_CTXT_CODE);
adapterp = &(univ_adapters[ctxtp->adapter_id]);
UNIV_ASSERT(adapterp->code == MAIN_ADAPTER_CODE);
UNIV_ASSERT(adapterp->ctxtp == ctxtp);
/* Check whether the driver has been announced to tcpip before processing any packets. */
if (!adapterp->inited || !adapterp->announced)
{
TRACE_CRIT("%!FUNC! Adapter not initialized or not announced");
return 0;
}
/* Do not accept frames if the card below is resetting. */
if (ctxtp->reset_state != MAIN_RESET_NONE)
{
TRACE_CRIT("%!FUNC! Adapter is resetting");
return 0;
}
/* Figure out if we need to handle this packet. */
newp = Main_recv(ctxtp, packet);
/* A return value of NULL indicates rejection of the packet - return zero to
indicate that no references remain on the packet (it can be dropped). */
if (newp == NULL)
{
return 0;
}
MAIN_RESP_FIELD(newp, stack_left, pktstk, resp, FALSE);
/* Process remote control. */
if (resp->type == MAIN_PACKET_TYPE_CTRL)
{
/* Handle remote control request now. */
(VOID)Main_ctrl_process(ctxtp, newp);
/* Packet has been copied into our own packet; return zero to
indicate that no references remain on the original packet. */
return 0;
}
UNIV_ASSERT_VAL(resp->type == MAIN_PACKET_TYPE_PASS, resp->type);
/* Pass packet up. Note reference counting to determine who will
be disposing of the packet. */
resp->data = 2;
Nic_recv_packet(ctxtp, newp);
lock_value = InterlockedDecrement(&resp->data);
UNIV_ASSERT_VAL(lock_value == 0 || lock_value == 1, lock_value);
if (lock_value == 0)
{
/* If we're done with the packet, reverse any changes we've made
to it and return zero to indication no lingering references. */
Main_packet_put(ctxtp, newp, FALSE, NDIS_STATUS_SUCCESS);
return 0;
}
/* Otherwise, the packet is still being processed, so return 1 to make
sure that the packet is not immediately released. */
return 1;
}
VOID Prot_return (
PMAIN_CTXT ctxtp,
PNDIS_PACKET packet)
{
PNDIS_PACKET oldp;
PMAIN_PROTOCOL_RESERVED resp;
LONG lock_value;
ULONG type;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
UNIV_ASSERT(ctxtp->code == MAIN_CTXT_CODE);
MAIN_RESP_FIELD(packet, stack_left, pktstk, resp, FALSE);
/* Check to see if we need to be disposing of this packet. */
lock_value = InterlockedDecrement(&resp->data);
UNIV_ASSERT_VAL(lock_value == 0 || lock_value == 1, lock_value);
if (lock_value == 1)
{
return;
}
/* Resp will become invalid after the call to Main_packet_put.
Save type for assertion below. */
type = resp->type;
oldp = Main_packet_put(ctxtp, packet, FALSE, NDIS_STATUS_SUCCESS);
/* If oldp is NULL, this is our internal packet. */
if (oldp != NULL)
{
UNIV_ASSERT_VAL(type == MAIN_PACKET_TYPE_PASS, type);
NdisReturnPackets(&oldp, 1);
}
}
NDIS_STATUS Prot_transfer (
PMAIN_CTXT ctxtp,
NDIS_HANDLE recv_handle,
PNDIS_PACKET packet,
UINT offset,
UINT len,
PUINT xferred)
{
NDIS_STATUS status;
PNDIS_PACKET newp;
PMAIN_PROTOCOL_RESERVED resp;
PNDIS_PACKET_STACK pktstk;
BOOLEAN stack_left;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
/* V1.1.2 do not accept frames if the card below is resetting */
if (ctxtp -> reset_state != MAIN_RESET_NONE)
{
TRACE_CRIT("%!FUNC! adapter is resetting");
return NDIS_STATUS_FAILURE;
}
/* we are trying to prevent transfer requests from stale receive indicates
that have been made to the protocol layer prior to the reset operation.
we do not know what is the old inbound frame state and cannot expect
to be able to carry out any transfers. */
if (! ctxtp -> recv_indicated)
{
UNIV_PRINT_CRIT(("Prot_transfer: stale receive indicate after reset"));
TRACE_CRIT("%!FUNC! stale receive indicate after reset");
return NDIS_STATUS_FAILURE;
}
newp = Main_packet_get (ctxtp, packet, FALSE, 0, 0);
if (newp == NULL)
{
UNIV_PRINT_CRIT(("Prot_transfer: Error xlating packet"));
TRACE_CRIT("%!FUNC! Error translating packet");
return NDIS_STATUS_RESOURCES;
}
MAIN_RESP_FIELD (newp, stack_left, pktstk, resp, FALSE);
resp -> type = MAIN_PACKET_TYPE_TRANSFER;
NdisTransferData (& status, ctxtp -> mac_handle, recv_handle, offset, len,
newp, xferred); /* V1.1.2 */
if (status != NDIS_STATUS_PENDING)
{
if (status == NDIS_STATUS_SUCCESS)
{
MAIN_PACKET_INFO PacketInfo;
/* Call Main_recv_frame_parse merely to extract the packet length and "group". */
if (Main_recv_frame_parse(ctxtp, newp, &PacketInfo))
{
resp->len = PacketInfo.Length;
resp->group = PacketInfo.Group;
}
/* If we fail to fill in the group and length, just populate these
parameters with values that will not affect the statistics that
are updated in Main_packet_put. */
else
{
resp->len = 0;
resp->group = MAIN_FRAME_DIRECTED;
}
}
Main_packet_put (ctxtp, newp, FALSE, status);
}
return status;
} /* end Prot_transfer */
VOID Prot_cancel_send_packets (
PMAIN_CTXT ctxtp,
PVOID cancel_id)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
NdisCancelSendPackets (ctxtp -> mac_handle, cancel_id);
return;
} /* Prot_cancel_send_packets */