summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/elnkmc/request.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/elnkmc/request.c1859
1 files changed, 1859 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnkmc/request.c b/private/ntos/ndis/elnkmc/request.c
new file mode 100644
index 000000000..6a678961c
--- /dev/null
+++ b/private/ntos/ndis/elnkmc/request.c
@@ -0,0 +1,1859 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This file contains code to implement MacRequest and
+ MacQueryGlobalStatistics. This driver conforms to the
+ NDIS 3.0 interface.
+
+Author:
+
+ Johnson R. Apacible (JohnsonA) 10-June-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+//
+// So we can trace things...
+//
+#define STATIC
+
+#include <efilter.h>
+#include <Elnkhw.h>
+#include <Elnksw.h>
+
+extern
+BOOLEAN
+ChangeClassDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ );
+
+extern
+VOID
+ChangeAddressDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+ElnkQueryInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ IN PUINT BytesWritten,
+ IN PUINT BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+ElnkSetInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ OUT PUINT BytesRead,
+ OUT PUINT BytesNeeded
+ );
+
+extern
+VOID
+ElnkQueueRequest(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ );
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ );
+
+VOID
+ElnkRemoveAdapter(
+ IN NDIS_HANDLE MacAdapterContext
+ );
+
+
+extern
+NDIS_STATUS
+ElnkChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular filter
+ class is first used or last cleared.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ NdisRequest - the change filter request from the protocol.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from an open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // The open that made this request.
+ //
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ NdisRequest;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ ASSERT(OldFilterClasses != NewFilterClasses);
+
+
+ if (ChangeClassDispatch(Adapter,
+ OldFilterClasses,
+ NewFilterClasses,
+ Open,
+ Set
+ )) {
+
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ } else {
+
+ StatusOfChange = NDIS_STATUS_SUCCESS;
+
+ }
+
+ }
+
+ return StatusOfChange;
+
+}
+
+BOOLEAN
+ChangeClassDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Reconfigures the adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ OldFilterClasses - The values of the class filter before it
+ was changed.
+
+ NewFilterClasses - The current value of the class filter
+
+ Set - TRUE if this is due to a set.
+
+Return Value:
+
+ TRUE, if we need to fill in a command block. FALSE, otherwise.
+
+--*/
+
+{
+
+ //
+ // Status to return
+ //
+ BOOLEAN StatusToReturn = FALSE;
+
+ //
+ // Default Value
+ //
+ USHORT NewParameterField = DEFAULT_PARM5;
+
+ OldFilterClasses;
+
+ if (NewFilterClasses & (NDIS_PACKET_TYPE_PROMISCUOUS |
+ NDIS_PACKET_TYPE_ALL_MULTICAST)) {
+
+ NewParameterField |= CONFIG_PROMISCUOUS;
+
+ } else {
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+
+ NewParameterField &= ~CONFIG_BROADCAST;
+
+ }
+
+ }
+
+ if (Adapter->OldParameterField != NewParameterField) {
+
+ IF_LOG('+');
+
+ Adapter->OldParameterField = NewParameterField;
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Command,
+ CB_CONFIG
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Status,
+ CB_STATUS_FREE
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter1,
+ DEFAULT_PARM1
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter2,
+ DEFAULT_PARM2
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter3,
+ DEFAULT_PARM3
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter4,
+ DEFAULT_PARM4
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter5,
+ NewParameterField
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Config.Parameter6,
+ DEFAULT_PARM6
+ );
+
+
+ //
+ // if this was not from an ndisrequest, then we need to store the
+ // open somewhere
+ //
+
+ if (!Set) {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
+
+ Adapter->CloseResultedInChanges = TRUE;
+
+ } else {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
+
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+ }
+
+
+ StatusToReturn = TRUE;
+
+ }
+
+ return(StatusToReturn);
+
+}
+
+
+extern
+NDIS_STATUS
+ElnkChangeAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when the multicast address
+ list has changed.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired.
+
+Arguments:
+
+ OldAddressCount - The number of addresses in OldAddresses.
+
+ OldAddresses - The old multicast address list.
+
+ NewAddressCount - The number of addresses in NewAddresses.
+
+ NewAddresses - The new multicast address list.
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ RequestHandle - A value supplied by the NDIS interface that the MAC
+ must use when completing this request with the NdisCompleteRequest
+ service, if the MAC completes this request asynchronously.
+
+ Set - If true the change resulted from a set, otherwise the
+ change resulted from a open closing.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+
+
+ PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // The open that made this request.
+ //
+ PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ //
+ // Holds the change that should be returned to the filtering package.
+ //
+ NDIS_STATUS StatusOfChange;
+
+ OldAddressCount; OldAddresses; NdisRequest; Set;
+
+ if (Adapter->ResetInProgress) {
+
+ StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ } else {
+
+ //
+ // The whole purpose of this routine is to determine whether
+ // the filtering changes need to result in the hardware being
+ // reset.
+ //
+
+ //
+ // We are referencing this open
+ //
+
+ ChangeAddressDispatch(
+ Adapter,
+ NewAddressCount,
+ NewAddresses,
+ Open,
+ Set
+ );
+
+ StatusOfChange = NDIS_STATUS_PENDING;
+
+ }
+
+ return StatusOfChange;
+
+}
+
+extern
+VOID
+ChangeAddressDispatch(
+ IN PELNK_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
+ IN PELNK_OPEN Open,
+ IN BOOLEAN Set
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the multicast address list of the adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ AddressCount - The number of addresses in Addresses
+
+ Addresses - The new multicast address list.
+
+Return Value:
+
+
+--*/
+
+{
+
+ UINT i, j;
+
+ IF_LOG('-');
+
+ //
+ // Setup the command block.
+ //
+
+ for (i = 0 ; i < AddressCount; i++ ) {
+
+ for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) {
+
+ NdisWriteRegisterUchar(
+ &Adapter->MulticastBlock->Parm.Multicast.MulticastID[i][j],
+ Addresses[i][j]
+ );
+ }
+ }
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Parm.Multicast.McCount,
+ (USHORT)(AddressCount * ETH_LENGTH_OF_ADDRESS)
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Status,
+ CB_STATUS_FREE
+ );
+
+ NdisWriteRegisterUshort(
+ &Adapter->MulticastBlock->Command,
+ CB_MULTICAST
+ );
+
+ //
+ // if this was not from an ndisrequest, then we need to store the
+ // open somewhere
+ //
+
+ if (!Set) {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
+
+ Adapter->CloseResultedInChanges = TRUE;
+
+ } else {
+ Adapter->TransmitInfo[
+ Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
+ //
+ // Now that we're set up, let's do it!
+ //
+
+ if (Adapter->FirstReset) {
+
+ ElnkSubmitCommandBlockAndWait(Adapter);
+
+ } else {
+
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+
+ }
+ }
+
+}
+
+
+STATIC
+VOID
+ElnkCloseAction(
+ IN NDIS_HANDLE MacBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Action routine that will get called when a particular binding
+ was closed while it was indicating through NdisIndicateReceive
+
+ All this routine needs to do is to decrement the reference count
+ of the binding.
+
+ NOTE: This routine assumes that it is called with the lock acquired.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
+}
+
+
+
+NDIS_STATUS
+ElnkRequest(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ The ElnkRequest function handles general requests from the
+ protocol. Currently these include SetInformation and
+ QueryInformation, more may be added in the future.
+
+Arguments:
+
+ MacBindingHandle - The context value returned by the MAC when the
+ adapter was opened. In reality, it is a pointer to ELNK_OPEN.
+
+ NdisRequest - A structure describing the request. In the case
+ of asynchronous completion, this pointer will be used to
+ identify the request that is completing.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // This holds the status we will return.
+ //
+
+ NDIS_STATUS StatusOfRequest;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PELNK_ADAPTER Adapter;
+
+ //
+ // Pts to the reserved section of the request
+ //
+ PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
+
+ Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ PELNK_OPEN Open;
+
+ Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
+
+ if (!Open->BindingShuttingDown) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestSetInformation:
+ case NdisRequestQueryInformation:
+
+ //
+ // This is a valid request, queue it.
+ //
+
+ Open->References++;
+
+ Reserved->OpenBlock = Open;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ ElnkQueueRequest (Adapter, NdisRequest);
+
+ StatusOfRequest = NDIS_STATUS_PENDING;
+ break;
+
+ default:
+
+ //
+ // Unknown request
+ //
+
+ StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_CLOSING;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusOfRequest;
+}
+
+extern
+VOID
+ElnkQueueRequest(
+ IN PELNK_ADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkQueueRequest takes an NDIS_REQUEST and ensures that it
+ gets processed and completed. It processes the
+ request immediately if nothing else is in progress, otherwise
+ it queues it for later processing.
+
+ THIS ROUTINE IS CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Adapter - The adapter that the request is for.
+
+ NdisRequest - The NDIS_REQUEST structure describing the request.
+ The ElnkReserved section is partially filled in, except
+ for the queueing and current offset fields.
+
+Return Value:
+
+ NDIS_STATUS_PENDING if the request was queued.
+ Otherwise, the return code from ElnkProcessRequestQueue.
+ This will be NDIS_STATUS_PENDING if the request was queued
+ to the adapter, otherwise the status of the request.
+
+
+--*/
+
+{
+
+ //
+ // Queue the request.
+ //
+
+ if (Adapter->FirstRequest != (PNDIS_REQUEST)NULL) {
+
+ //
+ // Something else on the queue, just queue it.
+ //
+
+ PELNK_RESERVED_FROM_REQUEST(Adapter->LastRequest)->Next = NdisRequest;
+ Adapter->LastRequest = NdisRequest;
+
+ } else {
+
+ //
+ // The queue if empty, so nothing is in progress.
+ //
+
+ Adapter->FirstRequest = NdisRequest;
+ Adapter->LastRequest = NdisRequest;
+
+ ElnkProcessRequestQueue(Adapter);
+
+ }
+}
+
+extern
+VOID
+ElnkProcessRequestQueue(
+ IN PELNK_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkProcessRequestQueue takes the requests on the queue
+ and processes them as much as possible. It will complete
+ any requests that it fully processes. It will stop when
+ the queue is empty or it finds a request that has to pend.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD.
+
+Arguments:
+
+ Adapter - The adapter that the request is for.
+
+Return Value:
+
+ NDIS_STATUS_PENDING (probably should be VOID...)
+
+
+--*/
+{
+ PNDIS_REQUEST Request;
+ PELNK_REQUEST_RESERVED Reserved;
+ PELNK_OPEN Open;
+ NDIS_STATUS Status;
+
+ //
+ // Only one request can be processed at one time
+ //
+
+ if (Adapter->ProcessingRequests) {
+
+ return;
+
+ } else {
+
+ Adapter->ProcessingRequests = TRUE;
+
+ }
+
+ Request = Adapter->FirstRequest;
+
+ for (;;) {
+
+ //
+ // Loop until we exit, which happens when a
+ // request pends, or we empty the queue.
+ //
+
+ if ((Request == (PNDIS_REQUEST)NULL) || Adapter->ResetInProgress) {
+
+ break;
+ }
+
+ Reserved = PELNK_RESERVED_FROM_REQUEST(Request);
+
+ switch (Request->RequestType) {
+
+ case NdisRequestClose:
+
+ Adapter->CloseResultedInChanges = FALSE;
+
+ Open = Reserved->OpenBlock;
+
+ Status = EthDeleteFilterOpenAdapter(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ NULL
+ );
+
+
+ //
+ // If the status is successful that merely implies that
+ // we were able to delete the reference to the open binding
+ // from the filtering code.
+ //
+ // The delete filter routine can return a "special" status
+ // that indicates that there is a current NdisIndicateReceive
+ // on this binding. See below.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // Account for the filter's reference to this open.
+ //
+
+ Open->References--;
+
+ } else if (Status == NDIS_STATUS_PENDING) {
+
+ //
+ // When the request completes we will dereference the
+ // open to account for the filter package's reference.
+ //
+
+ } else if (Status == NDIS_STATUS_CLOSING_INDICATING) {
+
+ //
+ // When we have this status it indicates that the filtering
+ // code was currently doing an NdisIndicateReceive. Our
+ // close action routine will get called when the filter
+ // is done with us, we remove the reference there.
+ //
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ ASSERT(0);
+
+ }
+
+ if (Adapter->CloseResultedInChanges) {
+
+ //
+ // This means that we have to submit the command that was
+ // formed from the close callbacks.
+ //
+ ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
+
+ }
+
+ //
+ // This flag prevents further requests on this binding.
+ //
+
+ Open->BindingShuttingDown = TRUE;
+
+ //
+ // Remove the reference kept for the fact that we
+ // had something queued.
+ //
+
+ Open->References--;
+
+ //
+ // Remove the open from the open list and put it on
+ // the closing list. This list is checked after every
+ // request, and when the reference count goes to zero
+ // the close is completed.
+ //
+
+ RemoveEntryList(&Open->OpenList);
+ InsertTailList(&Adapter->CloseList,&Open->OpenList);
+
+ break;
+
+ case NdisRequestOpen:
+
+ Open = Reserved->OpenBlock;
+
+ IF_LOG('O');
+
+ if (!EthNoteFilterOpenAdapter(
+ Open->OwningAdapter->FilterDB,
+ Open,
+ Open->NdisBindingContext,
+ &Open->NdisFilterHandle
+ )) {
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_FAILURE,
+ 0);
+
+ ELNK_FREE_PHYS(Open);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ } else {
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in and increment
+ // the opens reference count to account for the fact that the
+ // filter routines have a "reference" to the open.
+ //
+
+ InsertTailList(&Adapter->OpenBindings,&Open->OpenList);
+ Adapter->OpenCount++;
+ Open->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteOpenAdapter(
+ Open->NdisBindingContext,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ }
+
+ //
+ // Set this, since we want to continue processing
+ // the queue.
+ //
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+
+ case NdisRequestQueryInformation:
+
+ Status = ElnkQueryInformation(
+ Adapter,
+ Reserved->OpenBlock,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ case NdisRequestQueryStatistics:
+
+ IF_LOG('1');
+
+ Status = ElnkQueryInformation(
+ Adapter,
+ (PELNK_OPEN)NULL,
+ Request->DATA.QUERY_INFORMATION.Oid,
+ Request->DATA.QUERY_INFORMATION.InformationBuffer,
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength,
+ &(Request->DATA.QUERY_INFORMATION.BytesWritten),
+ &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
+ );
+
+ break;
+
+ case NdisRequestSetInformation:
+
+ IF_LOG('2');
+
+ Status = ElnkSetInformation(
+ Adapter,
+ Reserved->OpenBlock,
+ Request->DATA.SET_INFORMATION.Oid,
+ Request->DATA.SET_INFORMATION.InformationBuffer,
+ Request->DATA.SET_INFORMATION.InformationBufferLength,
+ &(Request->DATA.SET_INFORMATION.BytesRead),
+ &(Request->DATA.SET_INFORMATION.BytesNeeded));
+
+ break;
+
+ }
+
+ //
+ // see if operation pended
+ //
+
+ if (Status == NDIS_STATUS_PENDING) {
+
+ Adapter->ProcessingRequests = FALSE;
+
+ return;
+
+ }
+
+
+ //
+ // If we fall through here, we are done with this request.
+ //
+
+ Adapter->FirstRequest = Reserved->Next;
+
+ if (Request->RequestType == NdisRequestQueryStatistics) {
+
+ Adapter->References++;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteQueryStatistics(
+ Adapter->NdisAdapterHandle,
+ Request,
+ Status
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Adapter->References--;
+
+ } else if ((Request->RequestType == NdisRequestQueryInformation) ||
+ (Request->RequestType == NdisRequestSetInformation)) {
+
+ Open = Reserved->OpenBlock;
+
+ NdisReleaseSpinLock(&Adapter->Lock);
+
+ NdisCompleteRequest(
+ Open->NdisBindingContext,
+ Request,
+ Status
+ );
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+
+ Open->References--;
+
+ }
+
+ Request = Adapter->FirstRequest;
+
+ //
+ // Now loop and continue on with the next request.
+ //
+
+ }
+
+ Adapter->ProcessingRequests = FALSE;
+
+}
+
+
+extern
+NDIS_STATUS
+ElnkSetInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN INT InformationBufferLength,
+ OUT PUINT BytesRead,
+ OUT PUINT BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkSetInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ Adapter - The adapter that the set is for.
+
+ Open - a pointer to the open instance.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which contains the value to be set
+
+ InformationBufferLength - a pointer to the number of bytes in the
+ InformationBuffer.
+
+ BytesRead - Number of bytes read.
+
+ BytesNeeded - Number of bytes needed to satisfy this request.
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+ ULONG LookAheadBufferSize;
+ //
+ // Now check for the most common OIDs
+ //
+
+ *BytesNeeded = 0;
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ *BytesNeeded = ETH_LENGTH_OF_ADDRESS;
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Now call the filter package to set up the addresses.
+ //
+
+ Status = EthChangeFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ (PNDIS_REQUEST)NULL,
+ InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ InformationBuffer,
+ TRUE
+ );
+
+ *BytesRead = InformationBufferLength;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+
+ NdisMoveMemory ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+
+ //
+ // Verify bits
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ break;
+
+ }
+
+ Status = EthFilterAdjust(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ (PNDIS_REQUEST)NULL,
+ PacketFilter,
+ TRUE
+ );
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+
+ }
+
+ *BytesRead = 4;
+
+ NdisMoveMemory(&LookAheadBufferSize,
+ InformationBuffer,
+ sizeof(ULONG));
+
+
+
+ if (LookAheadBufferSize <= (MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE)) {
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ }
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ NdisMoveMemory(&Open->ProtOptionFlags, InformationBuffer, 4);
+
+ *BytesRead = 4;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+ return Status;
+}
+
+
+
+STATIC
+NDIS_STATUS
+ElnkQueryInformation(
+ IN PELNK_ADAPTER Adapter,
+ IN PELNK_OPEN Open,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PUINT BytesWritten,
+ OUT PUINT BytesNeeded
+)
+
+/*++
+
+Routine Description:
+
+ The ElnkQueryProtocolInformation process a Query request for
+ NDIS_OIDs that are specific to a binding about the MAC. Note that
+ some of the OIDs that are specific to bindings are also queryable
+ on a global basis. Rather than recreate this code to handle the
+ global queries, I use a flag to indicate if this is a query for the
+ global data or the binding specific data.
+
+Arguments:
+
+ Adapter - a pointer to the adapter.
+
+ Open - a pointer to the open instance. If null, then return
+ global statistics.
+
+ Oid - the NDIS_OID to process.
+
+ InformationBuffer - a pointer into the
+ NdisRequest->InformationBuffer into which store the result of the query.
+
+ InformationBufferLength - a pointer to the number of bytes left in the
+ InformationBuffer.
+
+ BytesWritten - a pointer to the number of bytes written into the
+ InformationBuffer.
+
+ BytesNeeded - If there is not enough room in the information buffer
+ then this will contain the number of bytes needed to complete the
+ request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+
+static
+NDIS_OID ElnkGlobalSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST
+ };
+
+static
+NDIS_OID ElnkProtocolSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE
+ };
+
+
+ NDIS_MEDIUM Medium = NdisMedium802_3;
+ UINT GenericUlong;
+ USHORT GenericUShort;
+ UCHAR GenericArray[6];
+ UINT MulticastAddresses;
+
+ NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
+
+ //
+ // Common variables for pointing to result of query
+ //
+
+ PVOID MoveSource = (PVOID)(&GenericUlong);
+ ULONG MoveBytes = sizeof(GenericUlong);
+ USHORT TmpUshort;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ //
+ // Switch on request type
+ //
+
+ switch(Oid){
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ if (Open == NULL) {
+ MoveSource = (PVOID)(ElnkGlobalSupportedOids);
+ MoveBytes = sizeof(ElnkGlobalSupportedOids);
+ } else {
+ MoveSource = (PVOID)(ElnkProtocolSupportedOids);
+ MoveBytes = sizeof(ElnkProtocolSupportedOids);
+ }
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+
+ if (Adapter->ResetInProgress){
+
+ HardwareStatus = NdisHardwareStatusReset;
+
+ } else if (Adapter->FirstReset) {
+
+ HardwareStatus = NdisHardwareStatusInitializing;
+
+ } else {
+
+ HardwareStatus = NdisHardwareStatusReady;
+
+ }
+
+
+ MoveSource = (PVOID)(&HardwareStatus);
+ MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
+
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+
+ MoveSource = (PVOID) (&Medium);
+ MoveBytes = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE;
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE;
+
+ break;
+
+
+
+ case OID_GEN_LINK_SPEED:
+
+ //
+ // 10 Mbps
+ //
+
+ GenericUlong = (ULONG)100000;
+
+ break;
+
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ Adapter->NumberOfTransmitBuffers;
+
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
+ Adapter->NumberOfReceiveBuffers;
+
+ break;
+
+
+#if ELNKMC
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+ MoveSource = (PVOID)(&GenericUlong);
+ MoveBytes = sizeof(GenericUlong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"ElnkMC Adapter";
+ MoveBytes = 15;
+ break;
+
+#else
+
+ case OID_GEN_VENDOR_ID:
+
+ NdisMoveMemory(
+ (PVOID)&GenericUlong,
+ Adapter->NetworkAddress,
+ 3
+ );
+ GenericUlong &= 0xFFFFFF00;
+ GenericUlong != 0x01;
+ MoveSource = (PVOID)(&GenericUlong);
+ MoveBytes = sizeof(GenericUlong);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ MoveSource = (PVOID)"Elnk16 Adapter";
+ MoveBytes = 15;
+ break;
+
+#endif
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUShort = (USHORT)0x0300;
+
+ MoveSource = (PVOID)(&GenericUShort);
+ MoveBytes = sizeof(GenericUShort);
+ break;
+
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (Open != NULL) {
+
+ GenericUlong = (ULONG)(ETH_QUERY_PACKET_FILTER(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle
+ ));
+ } else {
+
+ GenericUlong = (ULONG)ETH_QUERY_FILTER_CLASSES(
+ Adapter->FilterDB
+ );
+
+ }
+
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ ETH_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->NetworkAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ ETH_COPY_NETWORK_ADDRESS(
+ (PCHAR)GenericArray,
+ Adapter->CurrentAddress
+ );
+
+ MoveSource = (PVOID)(GenericArray);
+ MoveBytes = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (Open == NULL) {
+
+ NDIS_STATUS Status;
+ EthQueryGlobalFilterAddresses(
+ &Status,
+ Adapter->FilterDB,
+ InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)InformationBuffer);
+
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+
+ } else {
+
+ NDIS_STATUS Status;
+ EthQueryOpenFilterAddresses(
+ &Status,
+ Adapter->FilterDB,
+ Open->NdisFilterHandle,
+ InformationBufferLength,
+ &MulticastAddresses,
+ (PVOID)InformationBuffer);
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
+ } else {
+ MoveSource = (PVOID)InformationBuffer;
+ MoveBytes = ETH_LENGTH_OF_ADDRESS *
+ EthNumberOfOpenFilterAddresses(
+ Adapter->FilterDB,
+ Open->NdisFilterHandle);
+ }
+
+ }
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = (ULONG) ELNK_MAXIMUM_MULTICAST;
+
+ break;
+
+ default:
+
+ if (Open != NULL) {
+
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ switch(Oid){
+
+ case OID_GEN_XMIT_OK:
+ GenericUlong = (ULONG) Adapter->GoodTransmits;
+ break;
+
+ case OID_GEN_RCV_OK:
+ GenericUlong = (ULONG) Adapter->GoodReceives;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ GenericUlong = (ULONG) (Adapter->RetryFailure +
+ Adapter->LostCarrier +
+ Adapter->UnderFlow +
+ Adapter->NoClearToSend);
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
+ NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &TmpUshort);
+ GenericUlong += TmpUshort;
+ GenericUlong += Adapter->FrameTooShort + Adapter->NoEofDetected;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &GenericUlong);
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ GenericUlong = (ULONG) Adapter->TransmitsQueued;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &GenericUlong);
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ GenericUlong = (ULONG) Adapter->OneRetry;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->MoreThanOneRetry;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+ GenericUlong = (ULONG) Adapter->Deferred;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ GenericUlong = (ULONG) Adapter->RetryFailure;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+ NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &GenericUlong);
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+ GenericUlong = (ULONG) Adapter->UnderFlow;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ GenericUlong = (ULONG) Adapter->NoClearToSend;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ GenericUlong = (ULONG) Adapter->LostCarrier;
+ break;
+
+ default:
+ StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ }
+
+ if (StatusToReturn == NDIS_STATUS_SUCCESS) {
+
+ if (MoveBytes > InformationBufferLength) {
+
+ //
+ // Not enough room in InformationBuffer. Punt
+ //
+
+ *BytesNeeded = MoveBytes;
+
+ StatusToReturn = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+ } else {
+
+ //
+ // Copy result into InformationBuffer
+ //
+
+ *BytesWritten = MoveBytes;
+ if (MoveBytes > 0) {
+ ELNK_MOVE_MEMORY(
+ InformationBuffer,
+ MoveSource,
+ MoveBytes
+ );
+ }
+ }
+ }
+
+ return(StatusToReturn);
+}
+
+
+extern
+NDIS_STATUS
+ElnkQueryGlobalStatistics(
+ IN NDIS_HANDLE MacAdapterContext,
+ IN PNDIS_REQUEST NdisRequest
+ )
+
+/*++
+
+Routine Description:
+
+ ElnkQueryGlobalStatistics handles a per-adapter query
+ for statistics. It is similar to ElnkQueryInformation,
+ which is per-binding.
+
+Arguments:
+
+ MacAdapterContext - The context value that the MAC passed
+ to NdisRegisterAdapter; actually as pointer to a
+ ELNK_ADAPTER.
+
+ NdisRequest - Describes the query request.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+
+--*/
+
+{
+
+ //
+ // This holds the status we will return.
+ //
+
+ NDIS_STATUS StatusOfRequest;
+
+ //
+ // Points to the adapter that this request is coming through.
+ //
+ PELNK_ADAPTER Adapter = (PELNK_ADAPTER)MacAdapterContext;
+
+ PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
+
+ NdisAcquireSpinLock(&Adapter->Lock);
+ Adapter->References++;
+
+ if (!Adapter->ResetInProgress) {
+
+ switch (NdisRequest->RequestType) {
+
+ case NdisRequestQueryStatistics:
+
+ //
+ // Valid request.
+ //
+
+ Reserved->OpenBlock = (PELNK_OPEN)NULL;
+ Reserved->Next = (PNDIS_REQUEST)NULL;
+
+ ElnkQueueRequest (Adapter, NdisRequest);
+
+ StatusOfRequest = NDIS_STATUS_PENDING;
+ break;
+
+ default:
+
+ //
+ // Unknown request
+ //
+
+ StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ } else {
+
+ StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
+
+ }
+
+
+ //
+ // This macro assumes it is called with the lock held,
+ // and releases it.
+ //
+
+ ELNK_DO_DEFERRED(Adapter);
+ return StatusOfRequest;
+}