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.
 
 
 
 
 
 

1696 lines
59 KiB

/*++
Copyright(c) 1998,99 Microsoft Corporation
Module Name:
nic.c
Abstract:
Windows Load Balancing Service (WLBS)
Driver - upper-level (NIC) layer of intermediate miniport
Author:
kyrilf
--*/
#define NDIS_MINIPORT_DRIVER 1
//#define NDIS50_MINIPORT 1
#define NDIS51_MINIPORT 1
#include <ndis.h>
#include "nic.h"
#include "prot.h"
#include "main.h"
#include "util.h"
#include "wlbsparm.h"
#include "univ.h"
#include "log.h"
#include "nic.tmh"
/* define this routine here since the necessary portion of ndis.h was not
imported due to NDIS_... flags */
extern NTKERNELAPI VOID KeBugCheckEx (ULONG code, ULONG_PTR p1, ULONG_PTR p2, ULONG_PTR p3, ULONG_PTR p4);
NTHALAPI KIRQL KeGetCurrentIrql();
/* GLOBALS */
static ULONG log_module_id = LOG_MODULE_NIC;
/* PROCEDURES */
/* miniport handlers */
NDIS_STATUS Nic_init ( /* PASSIVE_IRQL */
PNDIS_STATUS open_status,
PUINT medium_index,
PNDIS_MEDIUM medium_array,
UINT medium_size,
NDIS_HANDLE adapter_handle,
NDIS_HANDLE wrapper_handle)
{
PMAIN_CTXT ctxtp;
UINT i;
NDIS_STATUS status;
PMAIN_ADAPTER adapterp;
/* verify that we have the context setup (Prot_bind was called) */
UNIV_PRINT_INFO(("Nic_init: Initializing, adapter_handle=0x%p", adapter_handle));
ctxtp = (PMAIN_CTXT) NdisIMGetDeviceContext (adapter_handle);
if (ctxtp == NULL)
{
UNIV_PRINT_INFO(("Nic_init: return=NDIS_STATUS_ADAPTER_NOT_FOUND"));
TRACE_INFO("%!FUNC! return=NDIS_STATUS_ADAPTER_NOT_FOUND");
return NDIS_STATUS_ADAPTER_NOT_FOUND;
}
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
/* return supported mediums */
for (i = 0; i < medium_size; i ++)
{
if (medium_array [i] == ctxtp -> medium)
{
* medium_index = i;
break;
}
}
if (i >= medium_size)
{
UNIV_PRINT_CRIT(("Nic_init: Unsupported media requested %d, %d, %x", i, medium_size, ctxtp -> medium));
UNIV_PRINT_INFO(("Nic_init: return=NDIS_STATUS_UNSUPPORTED_MEDIA"));
LOG_MSG2 (MSG_ERROR_MEDIA, MSG_NONE, i, ctxtp -> medium);
TRACE_CRIT("%!FUNC! Unsupported media requested i=%d, size=%d, medium=0x%x", i, medium_size, ctxtp -> medium);
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_UNSUPPORTED_MEDIA");
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
ctxtp -> prot_handle = adapter_handle;
NdisMSetAttributesEx (adapter_handle, ctxtp, 0,
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER | /* V1.1.2 */ /* v2.07 */
NDIS_ATTRIBUTE_DESERIALIZE |
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND, 0);
/* Setting up the default value for the Device State Flag as PM capable
initialize the PM Variable, (for both NIC and the PROT)
Device is ON by default. */
ctxtp->prot_pnp_state = NdisDeviceStateD0;
ctxtp->nic_pnp_state = NdisDeviceStateD0;
/* Allocate memory for our pseudo-periodic NDIS timer. */
status = NdisAllocateMemoryWithTag(&ctxtp->timer, sizeof(NDIS_MINIPORT_TIMER), UNIV_POOL_TAG);
if (status != NDIS_STATUS_SUCCESS) {
UNIV_PRINT_CRIT(("Nic_init: Error allocating timer; status=0x%x", status));
UNIV_PRINT_INFO(("Nic_init: return=NDIS_STATUS_RESOURCES"));
LOG_MSG2(MSG_ERROR_MEMORY, MSG_NONE, sizeof(NDIS_MINIPORT_TIMER), status);
TRACE_CRIT("%!FUNC! Error allocating timer; status=0x%x", status);
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_RESOURCES");
return NDIS_STATUS_RESOURCES;
}
/* Initialize the timer structure; here we set the timer routine (Nic_timer) and the
context that will be a parameter to that function, the adapter MAIN_CTXT. */
NdisMInitializeTimer((PNDIS_MINIPORT_TIMER)ctxtp->timer, ctxtp->prot_handle, Nic_timer, ctxtp);
/* Set the initial timeout value to the default heartbeat period from the registry. */
ctxtp->curr_tout = ctxtp->params.alive_period;
{
PNDIS_REQUEST request;
MAIN_ACTION act;
ULONG xferred;
ULONG needed;
ULONG result;
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;
/* Check to see if the media is connected. Some cards do not register disconnection, so use this as a hint. */
request->RequestType = NdisRequestQueryInformation;
request->DATA.QUERY_INFORMATION.Oid = OID_GEN_MEDIA_CONNECT_STATUS;
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 media connection status %d %d", status, xferred, needed));
TRACE_CRIT("%!FUNC! Error 0x%x requesting media connection status %d %d", status, xferred, needed);
ctxtp->media_connected = TRUE;
}
else
{
UNIV_PRINT_INFO(("Prot_bind: Media state - %s", result == NdisMediaStateConnected ? "CONNECTED" : "DISCONNECTED"));
TRACE_INFO("%!FUNC! Media state - %s", result == NdisMediaStateConnected ? "CONNECTED" : "DISCONNECTED");
ctxtp->media_connected = (result == NdisMediaStateConnected);
}
}
NdisAcquireSpinLock(& univ_bind_lock);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
adapterp -> announced = TRUE;
NdisReleaseSpinLock(& univ_bind_lock);
/* Set the first heartbeat timeout. */
NdisMSetTimer((PNDIS_MINIPORT_TIMER)ctxtp->timer, ctxtp->curr_tout);
UNIV_PRINT_INFO(("Nic_init: return=NDIS_STATUS_SUCCESS"));
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_SUCCESS");
return NDIS_STATUS_SUCCESS;
} /* end Nic_init */
VOID Nic_halt ( /* PASSIVE_IRQL */
NDIS_HANDLE adapter_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
BOOLEAN done;
NDIS_STATUS status;
PMAIN_ADAPTER adapterp;
UNIV_PRINT_INFO(("Nic_halt: Halting, adapter_id=0x%x", ctxtp -> adapter_id));
TRACE_INFO("->%!FUNC! Halting, adapter_id=0x%x", ctxtp -> adapter_id);
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);
NdisAcquireSpinLock(& univ_bind_lock);
if (! adapterp -> announced)
{
NdisReleaseSpinLock(& univ_bind_lock);
UNIV_PRINT_CRIT(("Nic_halt: Adapter not announced, adapter id = 0x%x", ctxtp -> adapter_id));
UNIV_PRINT_INFO(("Nic_halt: return"));
TRACE_CRIT("%!FUNC! Adapter not announced, adapter id = 0x%x", ctxtp -> adapter_id);
TRACE_INFO("<-%!FUNC! return");
return;
}
adapterp -> announced = FALSE;
NdisReleaseSpinLock(& univ_bind_lock);
/* Cancel the heartbeat timer. */
NdisMCancelTimer((PNDIS_MINIPORT_TIMER)ctxtp->timer, &done);
/* If canceling the timer fails, this means that the timer was not in the timer queue.
This indicates that either the timer function is currently running, or was about to
be run when we canceled it. However, we can't be SURE whether or not the timer
routine will run, so we can't count on it - the DPC may or may not have been canceled
if NdisMCancelTimer returns false. Since we have set adapterp->announced to FALSE,
this will prevent the timer routine from re-setting the timer before it exits.
To make sure that we don't free any memory that may be used by the timer routine,
we'll just wait here for at least one heartbeat period before we delete the timer
memory and move on to delete the adapter context, just in case. */
if (!done) Nic_sleep(ctxtp->curr_tout);
/* Free the timer memory. */
NdisFreeMemory(ctxtp->timer, sizeof(NDIS_MINIPORT_TIMER), 0);
/* ctxtp->prot_handle = NULL;
This is commented out to resolve a timing issue.
During unbind, a packet could go through but the flags
announced and bound are reset and prot_handle is set to NULL
So, this should be set after CloseAdapter. */
status = Prot_close (adapterp);
if (status != NDIS_STATUS_SUCCESS)
{
/* Don't do an early exit. This check was added for tracing only */
TRACE_CRIT("%!FUNC! Prot_close failed with 0x%x", status);
}
/* ctxtp might be gone at this point! */
UNIV_PRINT_INFO(("Nic_halt: return"));
TRACE_INFO("<-%!FUNC! return");
} /* end Nic_halt */
//#define TRACE_OID
NDIS_STATUS Nic_info_query (
NDIS_HANDLE adapter_handle,
NDIS_OID oid,
PVOID info_buf,
ULONG info_len,
PULONG written,
PULONG needed)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status;
PMAIN_ACTION actp;
PNDIS_REQUEST request;
ULONG size;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: called for %x, %x %d\n", oid, info_buf, info_len);
#endif
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
UNIV_ASSERT (adapterp -> ctxtp == ctxtp);
// reference counting in unbinding
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized, adapter_id = 0x%x", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
if (oid == OID_PNP_QUERY_POWER)
{
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_PNP_QUERY_POWER\n");
#endif
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_SUCCESS for oid=OID_PNP_QUERY_POWER");
return NDIS_STATUS_SUCCESS;
}
if (ctxtp -> reset_state != MAIN_RESET_NONE ||
ctxtp->nic_pnp_state > NdisDeviceStateD0 ||
ctxtp->standby_state)
{
TRACE_CRIT("%!FUNC! adapter reset or in standby, adapter id = 0x%x", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
switch (oid)
{
case OID_GEN_SUPPORTED_LIST:
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_SUPPORTED_LIST\n");
#endif
TRACE_VERB("%!FUNC! case: OID_GEN_SUPPORTED_LIST");
break;
#if 0
size = sizeof(univ_oids);
if (size > info_len)
{
* needed = size;
return NDIS_STATUS_INVALID_LENGTH;
}
NdisMoveMemory (info_buf, univ_oids, size);
* written = size;
return NDIS_STATUS_SUCCESS;
#endif
case OID_GEN_XMIT_OK:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_XMIT_OK adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_ok;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_XMIT_OK %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_RCV_OK:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_RCV_OK adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_ok;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_RCV_OK %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_XMIT_ERROR:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_XMIT_ERROR adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_err;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_XMIT_ERROR %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_RCV_ERROR:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_RCV_ERROR adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_err;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_RCV_ERROR %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_RCV_NO_BUFFER:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_RCV_NO_BUFFER adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_no_buf;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_RCV_NO_BUFFER %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_DIRECTED_BYTES_XMIT:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_DIRECTED_BYTES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_xmit_bytes_dir;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_DIRECTED_BYTES_XMIT %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_DIRECTED_FRAMES_XMIT:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_DIRECTED_FRAMES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_frames_dir;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_DIRECTED_FRAMES_XMIT %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_MULTICAST_BYTES_XMIT:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_MULTICAST_BYTES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_xmit_bytes_mcast;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_MULTICAST_BYTES_XMIT %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_MULTICAST_FRAMES_XMIT:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_MULTICAST_FRAMES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_frames_mcast;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_MULTICAST_FRAMES_XMIT %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_BROADCAST_BYTES_XMIT:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_BROADCAST_BYTES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_xmit_bytes_bcast;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_BROADCAST_BYTES_XMIT %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_BROADCAST_FRAMES_XMIT:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_BROADCAST_FRAMES_XMIT adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_frames_bcast;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_BROADCAST_FRAMES_XMIT %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_DIRECTED_BYTES_RCV:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_DIRECTED_BYTES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_recv_bytes_dir;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_DIRECTED_BYTES_RCV %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_DIRECTED_FRAMES_RCV:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_DIRECTED_FRAMES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_frames_dir;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_DIRECTED_FRAMES_RCV %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_MULTICAST_BYTES_RCV:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_MULTICAST_BYTES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_recv_bytes_mcast;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_MULTICAST_BYTES_RCV %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_MULTICAST_FRAMES_RCV:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_MULTICAST_FRAMES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_frames_mcast;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_MULTICAST_FRAMES_RCV %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_BROADCAST_BYTES_RCV:
if (info_len < sizeof (ULONGLONG))
{
* needed = sizeof (ULONGLONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_BROADCAST_BYTES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONGLONG) info_buf) = ctxtp -> cntr_recv_bytes_bcast;
* written = sizeof (ULONGLONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_DIRECTED_BROADCAST_RCV %.0f\n", *(PULONGLONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_BROADCAST_FRAMES_RCV:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_BROADCAST_FRAMES_RCV adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_frames_bcast;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_BROADCAST_FRAMES_RCV %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_RCV_CRC_ERROR:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_RCV_CRC_ERROR adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_recv_crc_err;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_RCV_CRC_ERROR %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
if (info_len < sizeof (ULONG))
{
* needed = sizeof (ULONG);
TRACE_CRIT("%!FUNC! case: OID_GEN_TRANSMIT_QUEUE_LENGTH adapter id = 0x%x, info_buf too small", ctxtp -> adapter_id);
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
* ((PULONG) info_buf) = ctxtp -> cntr_xmit_queue_len;
* written = sizeof (ULONG);
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: OID_GEN_TRANSMIT_QUEUE_LENGTH %d\n", *(PULONG) info_buf);
#endif
return NDIS_STATUS_SUCCESS;
default:
break;
}
actp = Main_action_get (ctxtp);
if (actp == NULL)
{
UNIV_PRINT_CRIT(("Nic_info_query: Error allocating action"));
TRACE_CRIT("%!FUNC! Error allocating action");
TRACE_VERB("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
request = & actp -> op . request . req;
request -> RequestType = NdisRequestQueryInformation;
request -> DATA . QUERY_INFORMATION . Oid = oid;
request -> DATA . QUERY_INFORMATION . InformationBuffer = info_buf;
request -> DATA . QUERY_INFORMATION . InformationBufferLength = info_len;
actp -> op . request . xferred = written;
actp -> op . request . needed = needed;
/* pass request down */
status = Prot_request (ctxtp, actp, TRUE);
if (status != NDIS_STATUS_PENDING)
{
* written = request -> DATA . QUERY_INFORMATION . BytesWritten;
* needed = request -> DATA . QUERY_INFORMATION . BytesNeeded;
#if defined(TRACE_OID)
DbgPrint("Nic_info_query: done %x, %d %d, %x\n", status, * written, * needed, * ((PULONG) (request -> DATA . QUERY_INFORMATION . InformationBuffer)));
#endif
/* override return values of some oids */
if (oid == OID_GEN_MAXIMUM_SEND_PACKETS && info_len >= sizeof (ULONG))
{
* ((PULONG) info_buf) = CVY_MAX_SEND_PACKETS;
* written = sizeof (ULONG);
status = NDIS_STATUS_SUCCESS;
}
else if (oid == OID_802_3_CURRENT_ADDRESS && status == NDIS_STATUS_SUCCESS)
{
if (info_len >= sizeof(CVY_MAC_ADR)) {
if (!ctxtp->params.mcast_support && ctxtp->cl_ip_addr != 0)
NdisMoveMemory(info_buf, &ctxtp->cl_mac_addr, sizeof(CVY_MAC_ADR));
else
NdisMoveMemory(info_buf, &ctxtp->ded_mac_addr, sizeof(CVY_MAC_ADR));
*written = sizeof(CVY_MAC_ADR);
} else {
UNIV_PRINT_CRIT(("Nic_info_query: MAC address buffer too small (%u) - not spoofing", info_len));
}
}
else if (oid == OID_GEN_MAC_OPTIONS && status == NDIS_STATUS_SUCCESS)
{
* ((PULONG) info_buf) |= NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
* ((PULONG) info_buf) &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
}
else if (oid == OID_PNP_CAPABILITIES && status == NDIS_STATUS_SUCCESS)
{
PNDIS_PNP_CAPABILITIES pnp_capabilities;
PNDIS_PM_WAKE_UP_CAPABILITIES pm_struct;
if (info_len >= sizeof (NDIS_PNP_CAPABILITIES))
{
pnp_capabilities = (PNDIS_PNP_CAPABILITIES) info_buf;
pm_struct = & pnp_capabilities -> WakeUpCapabilities;
pm_struct -> MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
pm_struct -> MinPatternWakeUp = NdisDeviceStateUnspecified;
pm_struct -> MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
ctxtp -> prot_pnp_state = NdisDeviceStateD0;
ctxtp -> nic_pnp_state = NdisDeviceStateD0;
* written = sizeof (NDIS_PNP_CAPABILITIES);
* needed = 0;
status = NDIS_STATUS_SUCCESS;
}
else
{
* needed = sizeof (NDIS_PNP_CAPABILITIES);
status = NDIS_STATUS_RESOURCES;
}
}
Main_action_put (ctxtp, actp);
}
return status;
} /* end Nic_info_query */
NDIS_STATUS Nic_info_set (
NDIS_HANDLE adapter_handle,
NDIS_OID oid,
PVOID info_buf,
ULONG info_len,
PULONG read,
PULONG needed)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status;
PMAIN_ACTION actp;
PNDIS_REQUEST request;
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 defined(TRACE_OID)
DbgPrint("Nic_info_set: called for %x, %x %d\n", oid, info_buf, info_len);
#endif
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized, adapter id = 0x%x", ctxtp -> adapter_id);
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
/* the Set Power should not be sent to the miniport below the Passthru,
but is handled internally */
if (oid == OID_PNP_SET_POWER)
{
NDIS_DEVICE_POWER_STATE new_pnp_state;
#if defined(TRACE_OID)
DbgPrint("Nic_info_set: OID_PNP_SET_POWER\n");
#endif
TRACE_VERB("%!FUNC! OID_PNP_SET_POWER");
if (info_len >= sizeof (NDIS_DEVICE_POWER_STATE))
{
new_pnp_state = (* (PNDIS_DEVICE_POWER_STATE) info_buf);
/* If WLBS is transitioning from an Off to On state, it must wait
for all underlying miniports to be turned On */
if (ctxtp->nic_pnp_state > NdisDeviceStateD0 &&
new_pnp_state != NdisDeviceStateD0)
{
// If the miniport is in a non-D0 state, the miniport can only
// receive a Set Power to D0
TRACE_CRIT("%!FUNC! miniport is in a non-D0 state");
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
//
// Is the miniport 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->nic_pnp_state == NdisDeviceStateD0 &&
new_pnp_state > NdisDeviceStateD0)
{
ctxtp->standby_state = TRUE;
}
// Note: lock these *_pnp_state variables
//
// If the miniport 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->nic_pnp_state > NdisDeviceStateD0 &&
new_pnp_state == NdisDeviceStateD0)
{
ctxtp->standby_state = FALSE;
}
ctxtp->nic_pnp_state = new_pnp_state;
// Note: We should be waiting here, as we do in prot_pnp_handle
// Note: Also wait for indicated packets to "return"
* read = sizeof (NDIS_DEVICE_POWER_STATE);
* needed = 0;
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_SUCCESS");
return NDIS_STATUS_SUCCESS;
}
else
{
* read = 0;
* needed = sizeof (NDIS_DEVICE_POWER_STATE);
TRACE_CRIT("%!FUNC! info_buf too small");
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_INVALID_LENGTH");
return NDIS_STATUS_INVALID_LENGTH;
}
}
if (ctxtp -> reset_state != MAIN_RESET_NONE ||
ctxtp->nic_pnp_state > NdisDeviceStateD0 ||
ctxtp->standby_state)
{
TRACE_CRIT("%!FUNC! adapter reset or in standby, adapter id = 0x%x", ctxtp -> adapter_id);
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
actp = Main_action_get (ctxtp);
if (actp == NULL)
{
UNIV_PRINT_CRIT(("Nic_info_set: Error allocating action"));
TRACE_CRIT("%!FUNC! Error allocating action");
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
request = & actp -> op . request . req;
request -> RequestType = NdisRequestSetInformation;
request -> DATA . SET_INFORMATION . Oid = oid;
/* V1.3.0b Multicast support. If protocol is setting multicast list, make sure we always
add our multicast address on at the end. If the cluster IP address 0.0.0.0, then we don't
want to add the multicast MAC address to the NIC - we retain the current MAC address. */
if (oid == OID_802_3_MULTICAST_LIST && ctxtp -> params . mcast_support && ctxtp -> params . cl_ip_addr != 0)
{
ULONG size, i, len;
PUCHAR ptr;
UNIV_PRINT_VERB(("Nic_info_set: OID_802_3_MULTICAST_LIST"));
/* search and see if our multicast address is alrady in the list */
len = CVY_MAC_ADDR_LEN (ctxtp -> medium);
for (i = 0; i < info_len; i += len)
{
if (CVY_MAC_ADDR_COMP (ctxtp -> medium, (PUCHAR) info_buf + i, & ctxtp -> cl_mac_addr))
{
UNIV_PRINT_VERB(("Nic_info_set: Cluster MAC matched - no need to add it"));
CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp -> cl_mac_addr);
break;
}
else
CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", (PUCHAR) info_buf + i);
}
/* if cluster mac not found, add it to the list */
if (i >= info_len)
{
UNIV_PRINT_VERB(("Nic_info_set: Cluster MAC not found - adding it"));
CVY_MAC_ADDR_PRINT (ctxtp -> medium, "", & ctxtp -> cl_mac_addr);
size = info_len + len;
status = NdisAllocateMemoryWithTag (& ptr, size, UNIV_POOL_TAG);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_info_set: Error allocating space %d %x", size, status));
LOG_MSG2 (MSG_ERROR_MEMORY, MSG_NONE, size, status);
Main_action_put (ctxtp, actp);
TRACE_CRIT("%!FUNC! Error allocating size=%d, status=0x%x", size, status);
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
/* If we have allocated a new buffer to hold the multicast MAC list,
note that we need to free it later when the request completes.
Main_action_get initializes the buffer to NULL, so a buffer will
only be freed if we explicitly store its address here. */
actp->op.request.buffer = ptr;
actp->op.request.buffer_len = size;
CVY_MAC_ADDR_COPY (ctxtp -> medium, ptr, & ctxtp -> cl_mac_addr);
NdisMoveMemory (ptr + len, info_buf, info_len);
request -> DATA . SET_INFORMATION . InformationBuffer = ptr;
request -> DATA . SET_INFORMATION . InformationBufferLength = size;
}
else
{
request -> DATA . SET_INFORMATION . InformationBuffer = info_buf;
request -> DATA . SET_INFORMATION . InformationBufferLength = info_len;
}
}
else
{
request -> DATA . SET_INFORMATION . InformationBuffer = info_buf;
request -> DATA . SET_INFORMATION . InformationBufferLength = info_len;
}
actp -> op . request . xferred = read;
actp -> op . request . needed = needed;
status = Prot_request (ctxtp, actp, TRUE);
if (status != NDIS_STATUS_PENDING)
{
/* V1.3.0b multicast support - clean up array used for storing list
of multicast addresses */
* read = request -> DATA . SET_INFORMATION . BytesRead;
* needed = request -> DATA . SET_INFORMATION . BytesNeeded;
if (request -> DATA . SET_INFORMATION . Oid == OID_802_3_MULTICAST_LIST)
{
/* If the request buffer is non-NULL, then we were forced to allocate a new buffer
large enough to hold the entire multicast MAC address list, plus our multicast
MAC address, which was missing from the list sent down by the protocol. To mask
this from the protocol, free the buffer and decrease the number of bytes read
by the miniport by the length of a MAC address before returning the request to
the protocol. */
if (actp->op.request.buffer != NULL) {
NdisFreeMemory(actp->op.request.buffer, actp->op.request.buffer_len, 0);
* read -= CVY_MAC_ADDR_LEN (ctxtp -> medium);
}
}
#if defined (NLB_TCP_NOTIFICATION)
else if (request->DATA.SET_INFORMATION.Oid == OID_GEN_NETWORK_LAYER_ADDRESSES)
{
/* Schedule an NDIS work item to get the interface index of this NLB
instance from TCP/IP by querying the IP address table. */
(VOID)Main_schedule_work_item(ctxtp, Main_set_interface_index);
/* Overwrite the status from the request. We will ALWAYS succeed this OID,
lest the protocol decide to stop sending it down to us. See the DDK. */
status = NDIS_STATUS_SUCCESS;
}
#endif
#if defined(TRACE_OID)
DbgPrint("Nic_info_set: done %x, %d %d\n", status, * read, * needed);
#endif
Main_action_put (ctxtp, actp);
}
TRACE_INFO("<-%!FUNC! return=0x%x", status);
return status;
} /* end Nic_info_set */
NDIS_STATUS Nic_reset (
PBOOLEAN addr_reset,
NDIS_HANDLE adapter_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status;
PMAIN_ADAPTER adapterp;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
adapterp = & (univ_adapters [ctxtp -> adapter_id]);
UNIV_ASSERT (adapterp -> code == MAIN_ADAPTER_CODE);
if (! adapterp -> inited)
{
TRACE_CRIT("%!FUNC! adapter not initialized");
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_FAILURE");
return NDIS_STATUS_FAILURE;
}
UNIV_PRINT_VERB(("Nic_reset: Called"));
/* since no information needs to be passed to Prot_reset,
action is not allocated. Prot_reset_complete will get
one and pass it to Nic_reset_complete */
status = Prot_reset (ctxtp);
if (status != NDIS_STATUS_SUCCESS && status != NDIS_STATUS_PENDING)
{
UNIV_PRINT_CRIT(("Nic_reset: Error resetting adapter, status=0x%x", status));
TRACE_CRIT("%!FUNC! Error resetting adapter, status=0x%x", status);
}
TRACE_INFO("<-%!FUNC! return=0x%x", status);
return status;
} /* end Nic_reset */
VOID Nic_cancel_send_packets (
NDIS_HANDLE adapter_handle,
PVOID cancel_id)
{
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);
/* Since no internal queues are maintained,
* can simply pass the cancel call to the miniport
*/
Prot_cancel_send_packets (ctxtp, cancel_id);
TRACE_INFO("<-%!FUNC! return");
return;
} /* Nic_cancel_send_packets */
VOID Nic_pnpevent_notify (
NDIS_HANDLE adapter_handle,
NDIS_DEVICE_PNP_EVENT pnp_event,
PVOID info_buf,
ULONG info_len)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
return;
} /* Nic_pnpevent_notify */
VOID Nic_adapter_shutdown (
NDIS_HANDLE adapter_handle)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
return;
} /* Nic_adapter_shutdown */
/* helpers for protocol layer */
NDIS_STATUS Nic_announce (
PMAIN_CTXT ctxtp)
{
NDIS_STATUS status;
NDIS_STRING nic_name;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
/* create the name to expose to TCP/IP protocol and call NDIS to force
TCP/IP to bind to us */
NdisInitUnicodeString (& nic_name, ctxtp -> virtual_nic_name);
/* Called from Prot_bind at PASSIVE_LEVEL - %ls is OK. */
UNIV_PRINT_INFO(("Nic_announce: Exposing %ls, %ls", nic_name . Buffer, ctxtp -> virtual_nic_name));
status = NdisIMInitializeDeviceInstanceEx (univ_driver_handle, & nic_name, (NDIS_HANDLE) ctxtp);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_announce: Error announcing driver %x", status));
__LOG_MSG1 (MSG_ERROR_ANNOUNCE, nic_name . Buffer + (wcslen(L"\\DEVICE\\") * sizeof(WCHAR)), status);
}
UNIV_PRINT_INFO(("Nic_announce: return=0x%x", status));
return status;
} /* end Nic_announce */
NDIS_STATUS Nic_unannounce (
PMAIN_CTXT ctxtp)
{
NDIS_STATUS status;
NDIS_STRING nic_name;
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);
NdisAcquireSpinLock(& univ_bind_lock);
if (! adapterp -> announced || ctxtp -> prot_handle == NULL)
{
adapterp -> announced = FALSE;
ctxtp->prot_handle = NULL;
NdisReleaseSpinLock(& univ_bind_lock);
NdisInitUnicodeString (& nic_name, ctxtp -> virtual_nic_name);
/* Called from Prot_unbind at PASSIVE_LEVEL - %ls is OK. */
UNIV_PRINT_INFO(("Nic_unannounce: Cancelling %ls, %ls", nic_name . Buffer, ctxtp -> virtual_nic_name));
status = NdisIMCancelInitializeDeviceInstance (univ_driver_handle, & nic_name);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_unannounce: Error cancelling driver %x", status));
__LOG_MSG1 (MSG_ERROR_ANNOUNCE, nic_name . Buffer + (wcslen(L"\\DEVICE\\") * sizeof(WCHAR)), status);
TRACE_CRIT("%!FUNC! Error cancelling driver status=0x%x", status);
}
UNIV_PRINT_INFO(("Nic_unannounce: return=NDIS_STATUS_SUCCESS"));
TRACE_INFO("<-%!FUNC! return=NDIS_STATUS_SUCCESS");
return NDIS_STATUS_SUCCESS;
}
NdisReleaseSpinLock(& univ_bind_lock);
UNIV_PRINT_INFO(("Nic_unannounce: Calling DeinitializeDeviceInstance"));
TRACE_INFO("%!FUNC! Calling DeinitializeDeviceInstance");
status = NdisIMDeInitializeDeviceInstance (ctxtp -> prot_handle);
UNIV_PRINT_INFO(("Nic_unannounce: return=0x%x", status));
TRACE_INFO("<-%!FUNC! return=0x%x", status);
return status;
} /* end Nic_unannounce */
/* routines that can be used with Nic_sync */
VOID Nic_request_complete (
NDIS_HANDLE handle,
PVOID cookie)
{
PMAIN_ACTION actp = (PMAIN_ACTION) cookie;
PMAIN_CTXT ctxtp = actp -> ctxtp;
NDIS_STATUS status = actp -> status;
PNDIS_REQUEST request = & actp -> op . request . req;
PULONG ptr;
ULONG oid;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
if (request -> RequestType == NdisRequestSetInformation)
{
UNIV_ASSERT (request -> DATA . SET_INFORMATION . Oid != OID_PNP_SET_POWER);
* actp -> op . request . xferred =
request -> DATA . SET_INFORMATION . BytesRead;
* actp -> op . request . needed =
request -> DATA . SET_INFORMATION . BytesNeeded;
#if defined(TRACE_OID)
DbgPrint("Nic_request_complete: set done %x, %d %d\n", status, * actp -> op . request . xferred, * actp -> op . request . needed);
#endif
TRACE_VERB("%!FUNC! set done status=0x%x, xferred=%d, needed=%d", status, * actp -> op . request . xferred, * actp -> op . request . needed);
/* V1.3.0b multicast support - free multicast list array */
if (request -> DATA . SET_INFORMATION . Oid == OID_802_3_MULTICAST_LIST)
{
/* If the request buffer is non-NULL, then we were forced to allocate a new buffer
large enough to hold the entire multicast MAC address list, plus our multicast
MAC address, which was missing from the list sent down by the protocol. To mask
this from the protocol, free the buffer and decrease the number of bytes read
by the miniport by the length of a MAC address before returning the request to
the protocol. */
if (actp->op.request.buffer != NULL) {
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_request_complete: Error setting multicast list, status=0x%x", status));
TRACE_CRIT("%!FUNC! Error setting multicast list, status=0x%x", status);
}
NdisFreeMemory(actp->op.request.buffer, actp->op.request.buffer_len, 0);
* actp -> op . request . xferred -= CVY_MAC_ADDR_LEN (ctxtp -> medium);
}
}
#if defined (NLB_TCP_NOTIFICATION)
else if (request->DATA.SET_INFORMATION.Oid == OID_GEN_NETWORK_LAYER_ADDRESSES)
{
/* Schedule an NDIS work item to get the interface index of this NLB
instance from TCP/IP by querying the IP address table. */
(VOID)Main_schedule_work_item(ctxtp, Main_set_interface_index);
/* Overwrite the status from the request. We will ALWAYS succeed this OID,
lest the protocol decide to stop sending it down to us. See the DDK. */
status = NDIS_STATUS_SUCCESS;
}
#endif
NdisMSetInformationComplete (ctxtp -> prot_handle, status);
}
else if (request -> RequestType == NdisRequestQueryInformation)
{
* actp -> op . request . xferred =
request -> DATA . QUERY_INFORMATION . BytesWritten;
* actp -> op . request . needed =
request -> DATA . QUERY_INFORMATION . BytesNeeded;
#if defined(TRACE_OID)
DbgPrint("Nic_request_complete: query done %x, %d %d\n", status, * actp -> op . request . xferred, * actp -> op . request . needed);
#endif
oid = request -> DATA . QUERY_INFORMATION . Oid;
ptr = ((PULONG) request -> DATA . QUERY_INFORMATION . InformationBuffer);
/* override certain oid values with our own */
if (oid == OID_GEN_MAXIMUM_SEND_PACKETS &&
request -> DATA . QUERY_INFORMATION . InformationBufferLength >=
sizeof (ULONG))
{
* ptr = CVY_MAX_SEND_PACKETS;
* actp -> op . request . xferred = sizeof (ULONG);
status = NDIS_STATUS_SUCCESS;
}
else if (oid == OID_802_3_CURRENT_ADDRESS && status == NDIS_STATUS_SUCCESS)
{
if (request->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(CVY_MAC_ADR)) {
if (!ctxtp->params.mcast_support && ctxtp->cl_ip_addr != 0)
NdisMoveMemory(ptr, &ctxtp->cl_mac_addr, sizeof(CVY_MAC_ADR));
else
NdisMoveMemory(ptr, &ctxtp->ded_mac_addr, sizeof(CVY_MAC_ADR));
*actp->op.request.xferred = sizeof(CVY_MAC_ADR);
} else {
UNIV_PRINT_CRIT(("Nic_request_complete: MAC address buffer too small (%u) - not spoofing", request->DATA.QUERY_INFORMATION.InformationBufferLength));
}
}
else if (oid == OID_GEN_MAC_OPTIONS && status == NDIS_STATUS_SUCCESS)
{
* ptr |= NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA;
* ptr &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
}
else if (oid == OID_PNP_CAPABILITIES && status == NDIS_STATUS_SUCCESS)
{
PNDIS_PNP_CAPABILITIES pnp_capabilities;
PNDIS_PM_WAKE_UP_CAPABILITIES pm_struct;
if (request -> DATA . QUERY_INFORMATION . InformationBufferLength >=
sizeof (NDIS_PNP_CAPABILITIES))
{
pnp_capabilities = (PNDIS_PNP_CAPABILITIES) ptr;
pm_struct = & pnp_capabilities -> WakeUpCapabilities;
pm_struct -> MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
pm_struct -> MinPatternWakeUp = NdisDeviceStateUnspecified;
pm_struct -> MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
ctxtp -> prot_pnp_state = NdisDeviceStateD0;
ctxtp -> nic_pnp_state = NdisDeviceStateD0;
* actp -> op . request . xferred = sizeof (NDIS_PNP_CAPABILITIES);
* actp -> op . request . needed = 0;
status = NDIS_STATUS_SUCCESS;
}
else
{
* actp -> op . request . needed = sizeof (NDIS_PNP_CAPABILITIES);
status = NDIS_STATUS_RESOURCES;
}
}
NdisMQueryInformationComplete (ctxtp -> prot_handle, status);
}
else
{
UNIV_PRINT_CRIT(("Nic_request_complete: Strange request completion %x\n", request -> RequestType));
TRACE_CRIT("%!FUNC! Strange request completion 0x%x", request -> RequestType);
}
Main_action_put (ctxtp, actp);
} /* end Nic_request_complete */
VOID Nic_reset_complete (
PMAIN_CTXT ctxtp,
NDIS_STATUS status)
{
TRACE_INFO("->%!FUNC!");
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_reset_complete: Error resetting adapter %x", status));
TRACE_CRIT("%!FUNC! Error resetting adapter 0x%x", status);
}
NdisMResetComplete (ctxtp -> prot_handle, status, TRUE);
TRACE_INFO("<-%!FUNC! return");
} /* end Nic_reset_complete */
VOID Nic_send_complete (
PMAIN_CTXT ctxtp,
NDIS_STATUS status,
PNDIS_PACKET packet)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_send_complete: Error sending to adapter %x", status));
TRACE_CRIT("%!FUNC! Error sending to adapter 0x%x", status);
}
// ctxtp -> sends_completed ++;
NdisMSendComplete (ctxtp -> prot_handle, packet, status);
} /* end Nic_send_complete */
VOID Nic_recv_complete ( /* PASSIVE_IRQL */
PMAIN_CTXT ctxtp)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
UNIV_ASSERT (ctxtp -> medium == NdisMedium802_3);
NdisMEthIndicateReceiveComplete (ctxtp -> prot_handle);
} /* end Nic_recv_complete */
VOID Nic_send_resources_signal (
PMAIN_CTXT ctxtp)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
UNIV_PRINT_VERB(("Nic_send_resources_signal: Signalling send resources available"));
NdisMSendResourcesAvailable (ctxtp -> prot_handle);
} /* end Nic_send_resources_signal */
NDIS_STATUS Nic_PNP_handle (
PMAIN_CTXT ctxtp,
PNET_PNP_EVENT pnp_event)
{
NDIS_STATUS status;
TRACE_INFO("->%!FUNC!");
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
if (ctxtp -> prot_handle != NULL)
{
status = NdisIMNotifyPnPEvent (ctxtp -> prot_handle, pnp_event);
}
else
{
status = NDIS_STATUS_SUCCESS;
}
UNIV_PRINT_VERB(("Nic_PNP_handle: status 0x%x", status));
TRACE_INFO("<-%!FUNC! return=0x%x", status);
return status;
}
VOID Nic_status (
PMAIN_CTXT ctxtp,
NDIS_STATUS status,
PVOID buf,
UINT len)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
UNIV_PRINT_VERB(("Nic_status: Status indicated %x", status));
NdisMIndicateStatus (ctxtp -> prot_handle, status, buf, len);
} /* end Nic_status */
VOID Nic_status_complete (
PMAIN_CTXT ctxtp)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
NdisMIndicateStatusComplete (ctxtp -> prot_handle);
} /* end Nic_status_complete */
VOID Nic_packets_send (
NDIS_HANDLE adapter_handle,
PPNDIS_PACKET packets,
UINT num_packets)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status;
PMAIN_ADAPTER adapterp;
/* V1.1.4 */
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)
{
// ctxtp -> uninited_return += num_packets;
TRACE_CRIT("%!FUNC! adapter not initialized");
return;
}
// ctxtp -> sends_in ++;
Prot_packets_send (ctxtp, packets, num_packets);
} /* end Nic_packets_send */
VOID Nic_return (
NDIS_HANDLE adapter_handle,
PNDIS_PACKET packet)
{
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);
Prot_return (ctxtp, packet);
} /* end Nic_return */
/* would be called by Prot_packet_recv */
VOID Nic_recv_packet (
PMAIN_CTXT ctxtp,
PNDIS_PACKET packet)
{
NDIS_STATUS status;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = NDIS_GET_PACKET_STATUS (packet);
NdisMIndicateReceivePacket (ctxtp -> prot_handle, & packet, 1);
if (status == NDIS_STATUS_RESOURCES)
Prot_return (ctxtp, packet);
} /* end Nic_recv_packet */
VOID Nic_timer (
PVOID dpc,
PVOID cp,
PVOID arg1,
PVOID arg2)
{
PMAIN_CTXT ctxtp = cp;
PMAIN_ADAPTER adapterp;
ULONG tout;
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 the adapter is not initialized at this point, then we can't process
the timeout, so just reset the timer and bail out. Note: this should
NEVER happen, as the context is always initialized BEFORE the timer is
set and the timer is always cancelled BEFORE the context is de-initialized. */
if (!adapterp->inited) {
UNIV_PRINT_CRIT(("Nic_timer: Adapter not initialized. Bailing out without resetting the heartbeat timer."));
TRACE_CRIT("%!FUNC! Adapter not initialized. Bailing out without resetting the heartbeat timer.");
return;
}
/* Initialize tout to the current heartbeat timeout. */
tout = ctxtp->curr_tout;
/* Handle the heartbeat timer. */
Main_ping(ctxtp, &tout);
NdisAcquireSpinLock(&univ_bind_lock);
/* If the adapter is not announced anymore, then we don't want to reset the timer. */
if (!adapterp->announced) {
UNIV_PRINT_CRIT(("Nic_timer: Adapter not announced. Bailing out without resetting the heartbeat timer."));
TRACE_CRIT("%!FUNC! Adapter not announced. Bailing out without resetting the heartbeat timer.");
NdisReleaseSpinLock(&univ_bind_lock);
return;
}
/* Cache the next timeout value specified by the load module and use it to
reset the timer for the next heartbeat timeout. */
ctxtp->curr_tout = tout;
NdisMSetTimer((PNDIS_MINIPORT_TIMER)ctxtp->timer, tout);
NdisReleaseSpinLock(&univ_bind_lock);
}
VOID Nic_sleep (
ULONG msecs)
{
NdisMSleep(msecs);
} /* end Nic_sleep */
/* Added from old code for NT 5.1 - ramkrish */
VOID Nic_recv_indicate (
PMAIN_CTXT ctxtp,
NDIS_HANDLE recv_handle,
PVOID head_buf,
UINT head_len,
PVOID look_buf,
UINT look_len,
UINT packet_len)
{
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 was reset");
return;
}
UNIV_ASSERT (ctxtp -> medium == NdisMedium802_3);
NdisMEthIndicateReceive (ctxtp -> prot_handle,
recv_handle,
head_buf,
head_len,
look_buf,
look_len,
packet_len);
} /* end Nic_recv_indicate */
NDIS_STATUS Nic_transfer (
PNDIS_PACKET packet,
PUINT xferred,
NDIS_HANDLE adapter_handle,
NDIS_HANDLE receive_handle,
UINT offset,
UINT len)
{
PMAIN_CTXT ctxtp = (PMAIN_CTXT) adapter_handle;
NDIS_STATUS status;
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
status = Prot_transfer (ctxtp, receive_handle, packet, offset, len, xferred);
if (status != NDIS_STATUS_PENDING && status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_transfer: Error transferring from adapter %x", status));
TRACE_CRIT("%!FUNC! error transferring from adapter 0x%x", status);
}
return status;
} /* end Nic_transfer */
VOID Nic_transfer_complete (
PMAIN_CTXT ctxtp,
NDIS_STATUS status,
PNDIS_PACKET packet,
UINT xferred)
{
UNIV_ASSERT (ctxtp -> code == MAIN_CTXT_CODE);
if (status != NDIS_STATUS_SUCCESS)
{
UNIV_PRINT_CRIT(("Nic_transfer: Error transferring from adapter %x", status));
TRACE_CRIT("%!FUNC! error transferring from adapter 0x%x", status);
}
NdisMTransferDataComplete (ctxtp -> prot_handle, packet, status, xferred);
} /* end Nic_transfer_complete */