Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1859 lines
43 KiB

/*++
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;
}