diff options
Diffstat (limited to 'private/ntos/ndis/netflex/request.c')
-rw-r--r-- | private/ntos/ndis/netflex/request.c | 2148 |
1 files changed, 2148 insertions, 0 deletions
diff --git a/private/ntos/ndis/netflex/request.c b/private/ntos/ndis/netflex/request.c new file mode 100644 index 000000000..7188d17dd --- /dev/null +++ b/private/ntos/ndis/netflex/request.c @@ -0,0 +1,2148 @@ +//********************************************************************** +//********************************************************************** +// +// File Name: REQUEST.C +// +// Program Name: NetFlex NDIS 3.0 Miniport Driver +// +// Companion Files: None +// +// Function: This module contains the NetFlex Miniport Driver +// interface routines called by the Wrapper and the +// configuration manager. +// +// (c) Compaq Computer Corporation, 1992,1993,1994 +// +// This file is licensed by Compaq Computer Corporation to Microsoft +// Corporation pursuant to the letter of August 20, 1992 from +// Gary Stimac to Mark Baber. +// +// History: +// +// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver +// +//********************************************************************** +//********************************************************************** + + +//------------------------------------- +// Include all general companion files +//------------------------------------- +#include <ndis.h> +#include "tmsstrct.h" +#include "macstrct.h" +#include "adapter.h" +#include "protos.h" + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexAddMulticasts +// +// Description: +// This routine adds a Multicast address to +// the adapter if it has not already been added. +// +// Input: +// acb - Our Driver Context for this adapter or head. +// +// Output: +// +// Called By: NetFlexSetInformation +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +NDIS_STATUS NetFlexAddMulticasts( + PACB acb, + PSCBREQ *ScbHead, + PSCBREQ *ScbTail +) +{ + NDIS_STATUS Status; + PETH_OBJS ethobjs; + PSCBREQ scbreq; + USHORT j; + PUCHAR addr; + + // + // Set ethobjs to the special objects... + // + ethobjs = (PETH_OBJS)acb->acb_spec_objs; + + // + // Loop through the multicast table, and send them to the card + // + for (j = 0; j < ethobjs->NumberOfEntries; j++) + { + // + // Get an SCB. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)(&acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status != NDIS_STATUS_SUCCESS) + { + DebugPrint( + 0, + ("NF(%d): Add Multicast, Ran out of SCB's!\n", + acb->anum) + ); + + return(NDIS_STATUS_FAILURE); + } + + // + // Add Multicast entry to card + // + addr = ethobjs->MulticastEntries + (j * NET_ADDR_SIZE); + + DebugPrint( + 1, ("NF(%d): Adding %02x-%02x-%02x-%02x-%02x-%02x to Multicast Table\n", + acb->anum, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])); + + scbreq->req_scb.SCB_Cmd = TMS_MULTICAST; + scbreq->req_macreq = NULL; + scbreq->req_multi.MB_Option = MPB_ADD_ADDRESS; + scbreq->req_multi.MB_Addr_Hi = *((PUSHORT) addr); + scbreq->req_multi.MB_Addr_Med = *((PUSHORT)(addr + 2)); + scbreq->req_multi.MB_Addr_Lo = *((PUSHORT)(addr + 4)); + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq); + } + + return(NDIS_STATUS_SUCCESS); +} + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexDeleteMulticast +// +// Description: +// This routine removes the multicast address from the +// enabled multicast lists. +// +// Input: +// acb - Our Driver Context for this adapter or head. +// +// Output: +// Status - SUCCESS | FAILURE +// +// Called By: +// NetFlexSetInformation +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +NDIS_STATUS NetFlexDeleteMulticast( + PACB acb, + PSCBREQ *ScbHead, + PSCBREQ *ScbTail +) +{ + NDIS_STATUS Status; + PSCBREQ scbreq; + + DebugPrint(1, ("NF(%d): Delete Multicast Table\n", acb->anum)); + + // + // Get a free SCBReq block. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status == NDIS_STATUS_SUCCESS) + { + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_MULTICAST; + scbreq->req_macreq = NULL; + scbreq->req_multi.MB_Option = MPB_CLEAR_ALL; + + NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq); + } + else + { + DebugPrint(0,("NF(%d): Delete Multicast Table, Ran out of SCB's!\n",acb->anum)); + } + + return(Status); +} + + +NDIS_STATUS PromiscuousFilterChanged( + PACB acb, + ULONG Filter, + PSCBREQ *ScbHead, + PSCBREQ *ScbTail +) +{ + NDIS_STATUS Status; + PSCBREQ scbreq; + ULONG open_options; + + // Modify the open options to set COPY ALL FRAMES (promiscuous) + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status == NDIS_STATUS_SUCCESS) + { + // + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_MODIFYOPEN; + scbreq->req_macreq = NULL; + + // + // Set the open options for ethernet and token ring. + // + open_options = OOPTS_CNMAC; + if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5) + open_options |= OOPTS_CMAC; + + // + // If we are turning it on, set the copy all frame bit + // bit, else turn it off. + // + if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) + { + // + // Turn on promiscuous mode. + // + acb->acb_opnblk_virtptr->OPEN_Options |= SWAPS((USHORT)open_options); + scbreq->req_scb.SCB_Ptr = acb->acb_opnblk_virtptr->OPEN_Options; + + DebugPrint(1,("NF(%d): FilterChanged: Turn Promiscous Mode ON...\n",acb->anum)); + acb->acb_promiscuousmode++; + } + else + { + // + // Turn off promiscuous mode. + // + acb->acb_opnblk_virtptr->OPEN_Options &= SWAPS((USHORT)~open_options); + scbreq->req_scb.SCB_Ptr = acb->acb_opnblk_virtptr->OPEN_Options; + + DebugPrint(1,("NF(%d): FilterChanged: Turn Promiscous Mode OFF...\n",acb->anum)); + acb->acb_promiscuousmode--; + } + + // + // Queue the scb to be sent. + // + NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq); + } + else + { + DebugPrint(0, ("NF(%d): Change Promiscuous mode, ran out of SCB's\n", acb->anum)); + } + + return(Status); +} + + +NDIS_STATUS AllMulticastFilterChanged( + PACB acb, + ULONG Filter, + PSCBREQ *ScbHead, + PSCBREQ *ScbTail +) +{ + NDIS_STATUS Status; + PSCBREQ scbreq; + PETH_OBJS ethobjs = acb->acb_spec_objs; + + // + // Get a free SCBReq block. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status != NDIS_STATUS_SUCCESS) + { + DebugPrint(0, ("NF(%d): AllMulticastFilterChanged(), Ran out of SCB's!\n",acb->anum)); + return(Status); + } + + // + // Turning All_Multicast On? + // + if (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) + { + DebugPrint(1,("NF(%d): FilterChanged: Turn ALL_Multicast ON...\n",acb->anum)); + + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_MULTICAST; + scbreq->req_macreq = NULL; + scbreq->req_multi.MB_Option = MPB_SET_ALL; + + // + // Queue the scb to be sent. + // + NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq); + } + else + { + // Turn All_Multicast Off. + // + DebugPrint(1,("NF(%d): FilterChanged: Turn ALL_Multicast OFF, delete all\n",acb->anum)); + + // + // Set up the scb to turn off ALL_MULTICAST. + // + scbreq->req_scb.SCB_Cmd = TMS_MULTICAST; + scbreq->req_macreq = NULL; + scbreq->req_multi.MB_Option = MPB_CLEAR_ALL; + + // + // Queue the scb to be sent. + // + NetFlexEnqueue_TwoPtrQ_Tail(ScbHead, ScbTail, scbreq); + + // + // Is Multicast on? + // + if (Filter & NDIS_PACKET_TYPE_MULTICAST) + { + // + // Yes, we need to re-enable all of the entries... + // The call to delete the multicast address above + // will determine if a completion is queued. + // + if (ethobjs->NumberOfEntries > 0) + NetFlexAddMulticasts(acb, ScbHead, ScbTail); + } + else + { + // + // Multicast isn't enabled, and we deleted them, so indicate + // that we also removed the multicast entries. + // + ethobjs->NumberOfEntries = 0; + } + } + + return(NDIS_STATUS_SUCCESS); +} + + +NDIS_STATUS MulticastFilterChanged( + PACB acb, + ULONG Filter, + PSCBREQ *ScbHead, + PSCBREQ *ScbTail +) +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PSCBREQ scbreq; + PETH_OBJS ethobjs; + + // + // If the ALL_MULTICAST filter bit is set then we don't need to + // turn on/off the MULTICAST crap. We will save the current filter + // options with the ACB in the calling routine so that we know + // to turn on the MULTICAST addresses when the ALL_MULTICAST bit + // is cleared. + // + if (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) + return(NDIS_STATUS_SUCCESS); + + // + // Get a pointer to the ethernet objecst. + // + ethobjs = acb->acb_spec_objs; + + // + // Are we turning the MULTICAST bit on or off? + // + if (Filter & NDIS_PACKET_TYPE_MULTICAST) + { + DebugPrint(1,("NF(%d): FilterChanged: Turn multicast ON...\n",acb->anum)); + + // + // Do we have any entries to enable? + // + if (ethobjs->NumberOfEntries > 0) + Status = NetFlexAddMulticasts(acb, ScbHead, ScbTail); + } + else + { + DebugPrint(1,("NF(%d): FilterChanged: Turn multicast OFF, delete all\n", acb->anum)); + + // + // Have any to delete? + // + if (ethobjs->NumberOfEntries > 0) + Status = NetFlexDeleteMulticast(acb, ScbHead, ScbTail); + } + + return(Status); +} + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexSetInformation +// +// Description: +// NetFlexSetInformation handles a set operation for a +// single OID. +// +// Input: +// MiniportAdapterContext - Our Driver Context for +// this adapter or head. +// +// Oid - The OID of the set. +// +// InformationBuffer - Holds the data to be set. +// +// InformationBufferLength - The length of InformationBuffer. +// +// Output: +// +// BytesRead - If the call is successful, returns the number +// of bytes read from InformationBuffer. +// +// BytesNeeded - If there is not enough data in OvbBuffer +// to satisfy the OID, returns the amount of +// storage needed. +// Status +// +// Called By: +// Miniport Wrapper +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +NDIS_STATUS NetFlexSetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded +) +{ + ULONG value; + PMACREQ macreq; + PETH_OBJS ethobjs; + PTR_OBJS trobjs; + PSCBREQ scbreq; + PSCBREQ ScbHead = NULL; + PSCBREQ ScbTail = NULL; + ULONG Filter; + ULONG BadFilter; + BOOLEAN QueueCompletion = FALSE; + BOOLEAN QueueCleanup = FALSE; + + PACB acb = (PACB) MiniportAdapterContext; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + *BytesRead = 0; + *BytesNeeded = 0; + + if (acb->acb_state == AS_RESETTING) + { + return(NDIS_STATUS_RESET_IN_PROGRESS); + } + + if (acb->RequestInProgress) + { + DebugPrint(0,("NF(%d): SetOID: Aready have RequestInProcess!\n",acb->anum)); + return NDIS_STATUS_FAILURE; + } + + acb->RequestInProgress = TRUE; + + // + // Save the information about the request + // + acb->BytesRead = BytesRead; + acb->BytesNeeded = BytesNeeded; + acb->Oid = Oid; + acb->InformationBuffer = InformationBuffer; + acb->InformationBufferLength = InformationBufferLength; + + switch (Oid) + { + case OID_GEN_CURRENT_PACKET_FILTER: + if (InformationBufferLength != sizeof(ULONG)) + { + DebugPrint(0,("NF(%d): Bad Packet Filter\n",acb->anum)); + acb->RequestInProgress = FALSE; + + return(NDIS_STATUS_INVALID_DATA); + } + + Filter = *(PULONG)(InformationBuffer); + DebugPrint(1,("NF(%d): OidSet: GEN_CURRENT_PACKET_FILTER = %x\n",acb->anum,Filter)); + + //------------------------------------------- + // Filters Common to TokenRing and Ethernet + //------------------------------------------- + +#if (DBG || DBGPRINT) + if (Filter & NDIS_PACKET_TYPE_DIRECTED) + DebugPrint(1,("NF(%d): FilterChangeAction: Directed\n",acb->anum)); +#endif + // + // Verify Filter + // + if ( acb->acb_gen_objs.media_type_in_use == NdisMedium802_3) + { + //-------------------------------- + // Ethernet Specific Filters... + //-------------------------------- + // + // accept only the following: + // + BadFilter = (ULONG)~(NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_BROADCAST | + (acb->FullDuplexEnabled ? + 0 : NDIS_PACKET_TYPE_PROMISCUOUS) + ); + if (Filter & BadFilter) + { + DebugPrint(1,("NF(%d): PacketFilter Not Supported\n",acb->anum)); + + *BytesRead = sizeof(ULONG); + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + // + // Did the state of the ALL_MULTICAST bit change? + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ^ + (Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) + ) + { + Status = AllMulticastFilterChanged( + acb, + Filter, + &ScbHead, + &ScbTail + ); + if (NDIS_STATUS_SUCCESS != Status) + { + // + // We might need to cleanup the local + // queue of SCBs. + // + QueueCleanup = TRUE; + break; + } + + // + // We successfully changed the ALL_MULTICAST bit. + // + QueueCompletion = TRUE; + } + + // + // Did the state of the MULTICAST bit change? + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_MULTICAST) ^ + (Filter & NDIS_PACKET_TYPE_MULTICAST) + ) + { + Status = MulticastFilterChanged( + acb, + Filter, + &ScbHead, + &ScbTail + ); + if (NDIS_STATUS_SUCCESS != Status) + { + // + // We might need to cleanup the local + // queue of SCBs. + // + QueueCleanup = TRUE; + break; + } + + // + // We successfully changed the MULTICAST bit. + // + QueueCompletion = TRUE; + } + } + else + { + //------------------------------- + // Token Ring Specific Filters... + //------------------------------- + // + // accept all of the following: + // + BadFilter = (ULONG)~(NDIS_PACKET_TYPE_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL | + NDIS_PACKET_TYPE_GROUP | + NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_PROMISCUOUS + ); + if (Filter & BadFilter) + { + DebugPrint(1,("NF(%d): PacketFilter Not Supported\n",acb->anum)); + + *BytesRead = sizeof(ULONG); + + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + // + // Are we turning the All Functional address filter on or off? + // + if (((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) ^ + (Filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL)) || + ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_FUNCTIONAL) ^ + (Filter & NDIS_PACKET_TYPE_FUNCTIONAL)) + ) + { + // + // We are changing it. Are we turning it on? + // Set functional address to all functional address + // + // Get a free SCBReq block. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status != NDIS_STATUS_SUCCESS) + { + // + // We failed to get an scb. We don't need + // to cleanup the scb queue since this is the + // first one. + // + break; + } + + // + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_SETFUNCT; + scbreq->req_macreq = NULL; + + // + // If we are turning it on, set the functional address + // to all ones, else set it to the acb's functional + // address. + // + if (Filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) + { + scbreq->req_scb.SCB_Ptr = SWAPL(0x7fffffff); + } + else + { + if (Filter & NDIS_PACKET_TYPE_FUNCTIONAL) + { + scbreq->req_scb.SCB_Ptr = + *((PLONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_func_addr)); + } + else + { + // + // clear it + // + scbreq->req_scb.SCB_Ptr = 0; + } + } + + DebugPrint(1,("NF(%d): FilterChanged: Setting Functional Address =0x%x\n",acb->anum,scbreq->req_scb.SCB_Ptr)); + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq); + + // + // Indicate we need to QueueCompletion MacReq + // + QueueCompletion = TRUE; + } + + // + // Changing Group? + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_GROUP) ^ + (Filter & NDIS_PACKET_TYPE_GROUP) + ) + { + // Get a free SCBReq block. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status != NDIS_STATUS_SUCCESS) + { + // + // We might need to cleanup the local + // queue of SCBs. + // + QueueCleanup = TRUE; + + break; + } + + // + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_SETGROUP; + scbreq->req_macreq = NULL; + + // + // Set or Clear the Group Address? + // + if (Filter & NDIS_PACKET_TYPE_GROUP) + { + scbreq->req_scb.SCB_Ptr = + *((PLONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_grp_addr)); + } + else + { + scbreq->req_scb.SCB_Ptr = 0; + } + + DebugPrint(1,("NF(%d): FilterChanged: Setting Group Address =0x%x\n",acb->anum,scbreq->req_scb.SCB_Ptr)); + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq); + + // + // Indicate we need to QueueCompletion MacReq + // + QueueCompletion = TRUE; + } + } + + // + // Did the state of the PROMISCUOUS flag change? + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_PROMISCUOUS) ^ + (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) + ) + { + Status = PromiscuousFilterChanged( + acb, + Filter, + &ScbHead, + &ScbTail + ); + if (NDIS_STATUS_SUCCESS != Status) + { + // + // We might need to cleanup the local + // queue of SCBs. + // + QueueCleanup = TRUE; + break; + } + + // + // We successfully changed the PROMISCUOUS bit. + // + QueueCompletion = TRUE; + } + + acb->acb_gen_objs.cur_filter = Filter; + *BytesRead = InformationBufferLength; + + break; + + case OID_802_3_MULTICAST_LIST: + + // + // Is the adapter setup for token ring? + // + if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5 ) + { + // + // Token ring does not support multicast. + // + DebugPrint(0,("NF(%d): MULTICAST LIST INVALID OID\n",acb->anum)); + *BytesRead = 0; + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + if (InformationBufferLength % NET_ADDR_SIZE != 0) + { + // + // The data must be a multiple of the Ethernet address size. + // + DebugPrint(0,("NF(%d): MULTICAST LIST INVALID LENGTH\n",acb->anum)); + + *BytesNeeded = InformationBufferLength + (NET_ADDR_SIZE - (InformationBufferLength % NET_ADDR_SIZE)); + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_INVALID_DATA; + + break; + } + + // + // Get a pointer to the ethernet objects. + // + ethobjs = (PETH_OBJS)(acb->acb_spec_objs); + scbreq = NULL; + + value = (InformationBufferLength / NET_ADDR_SIZE ); + + if (value > ethobjs->MaxMulticast) + { + DebugPrint(0,("NF(%d): TOO MANY MULTICAST ADDRESSES\n",acb->anum)); + + // + // There are too many, but add as many as we can. + // + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_MULTICAST_FULL; + + break; + } + + DebugPrint(1, ("NF(%d): Saving multicast address\n", acb->anum)); + + // + // Save entries in the table. + // + NdisMoveMemory( + ethobjs->MulticastEntries, + InformationBuffer, + value * NET_ADDR_SIZE + ); + + // + // If we have any entries enabled, delete them, + // unless NDIS_PACKET_TYPE_ALL_MULTICAST is set. + // + if (!(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) && + (ethobjs->NumberOfEntries > 0) + ) + { + // + // Get a free SCBReq block. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status != NDIS_STATUS_SUCCESS) + { + DebugPrint(0,("NF(%d): MULTICAST_LIST: out of SCBs\n", acb->anum)); + + // + // Since this is the first SCB, and it failed, + // we don't need to clean up. + // + break; + } + + DebugPrint(1,("NF(%d): MULTICAST_LIST: clearing current list\n", acb->anum)); + + // Queue SCB to process request + // + scbreq->req_scb.SCB_Cmd = TMS_MULTICAST; + scbreq->req_macreq = NULL; + scbreq->req_multi.MB_Option = MPB_CLEAR_ALL; + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq); + + // + // Indicate we need to a Queue MacReq Completion + // + QueueCompletion = TRUE; + } + + // + // Save number of entrys + // + ethobjs->NumberOfEntries = (SHORT)value; + + // + // If filter has NDIS_PACKET_TYPE_MULTICAST, but NOT + // NDIS_PACKET_TYPE_ALL_MULTICAST, then enable these entries now. + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_MULTICAST) && + !(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) + ) + { + if (ethobjs->NumberOfEntries > 0) + { + Status = NetFlexAddMulticasts(acb, &ScbHead, &ScbTail); + if (Status != NDIS_STATUS_SUCCESS) + { + // + // Cleanup the local SCB queue. + // + QueueCleanup = TRUE; + break; + } + + // + // Indicate we need to a Queue MacReq Completion + // + QueueCompletion = TRUE; + } + } + + *BytesRead = InformationBufferLength; + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + // + // We don't set anything, just return ok. - RVC true? + // + *BytesRead = 4; + Status = NDIS_STATUS_SUCCESS; + DebugPrint(1,("NF(%d): OID_GEN_CURRENT_LOOKAHEAD...\n",acb->anum)); + + break; + + + case OID_802_5_CURRENT_FUNCTIONAL: + if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3) + { + // + // If we are running Ethernet, a call for this oid is an error. + // + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL ) + { + DebugPrint(0,("NF(%d): Oid_Set Functional Address bad\n",acb->anum)); + *BytesNeeded = TR_LENGTH_OF_FUNCTIONAL - InformationBufferLength; + + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_INVALID_LENGTH; + + break; + } + + // + // Get the oid info. + // + NdisMoveMemory( + (PVOID)&value, + InformationBuffer, + TR_LENGTH_OF_FUNCTIONAL + ); + + // + // Get a pointer to the token ring objects. + // + trobjs = (PTR_OBJS)(acb->acb_spec_objs); + + *((PULONG)(trobjs->cur_func_addr)) = value; + + DebugPrint(1,("NF(%d): OidSet Functional Address = %08x\n",acb->anum,value)); + + // + // Update filter if the funcational address has been set in + // the packet filter. + // + if (!(acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) && + (acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_FUNCTIONAL) + ) + { + // + // Get an scb. + // + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status == NDIS_STATUS_SUCCESS) + { + scbreq->req_scb.SCB_Cmd = TMS_SETFUNCT; + scbreq->req_macreq = NULL; + scbreq->req_scb.SCB_Ptr = value; + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq); + + QueueCompletion = TRUE; + } + } + + *BytesRead = TR_LENGTH_OF_FUNCTIONAL; + break; + + case OID_802_5_CURRENT_GROUP: + if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3 ) + { + // If we are running Ethernet, a call for this oid is an error. + // + acb->RequestInProgress = FALSE; + + Status = NDIS_STATUS_NOT_SUPPORTED; + + break; + } + + if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL) + { + DebugPrint(0,("NF(%d): OidSet Group Address BAD\n",acb->anum)); + *BytesNeeded = TR_LENGTH_OF_FUNCTIONAL - InformationBufferLength; + + acb->RequestInProgress = FALSE; + Status = NDIS_STATUS_INVALID_LENGTH; + + break; + } + + NdisMoveMemory( + (PVOID)&value, + InformationBuffer, + TR_LENGTH_OF_FUNCTIONAL + ); + + trobjs = (PTR_OBJS)(acb->acb_spec_objs); + + *((PULONG)(trobjs->cur_grp_addr)) = value; + + DebugPrint(1,("NF(%d): OidSet Group Address = %08x\n",acb->anum,value)); + + // + // Update filter if the group address has been set in + // the packet filter. + // + if ((acb->acb_gen_objs.cur_filter & NDIS_PACKET_TYPE_GROUP) != 0) + { + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq + ); + if (Status == NDIS_STATUS_SUCCESS) + { + scbreq->req_scb.SCB_Cmd = TMS_SETGROUP; + scbreq->req_macreq = NULL; + scbreq->req_scb.SCB_Ptr = value; + + // + // Queue the scb. + // + NetFlexEnqueue_TwoPtrQ_Tail(&ScbHead, &ScbTail, scbreq); + + QueueCompletion = TRUE; + } + } + + *BytesRead = TR_LENGTH_OF_FUNCTIONAL; + break; + + default: + + Status = NDIS_STATUS_INVALID_OID; + break; + + } + + if (QueueCleanup) + { + DebugPrint(1,("NF(%d): Error Setting OID (0x%x)\n",acb->anum, Oid)); + + // + // There was an error trying to get sufficent SCBs to + // complete the request. + // + while (ScbHead != NULL) + { + NetFlexDequeue_OnePtrQ_Head(&ScbHead, &scbreq); + + NetFlexEnqueue_OnePtrQ_Head( + (PVOID *)&acb->acb_scbreq_free, + scbreq + ); + } + + QueueCompletion = FALSE; + } + + if (QueueCompletion) + { + // + // Was there actually an scb queued? + // + if (NULL != ScbHead) + { + // + // We should have a local list of scb's to send. + // + do + { + // + // Get a pointer to the next scb to process. + // + scbreq = ScbHead->req_next; + + // + // Are we on the last scb? + // + if (NULL == scbreq) + { + // + // Get a mac request in case we need the completeion + // + NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_macreq_free), + (PVOID *)¯eq + ); + + // + // Initialize the completion request. + // + macreq->req_next = NULL; + macreq->req_type = REQUEST_CMP; + macreq->req_status = NDIS_STATUS_SUCCESS; + + // + // Setup the last scb to be sent to the card. + // + ScbHead->req_macreq = macreq; + + // + // put the macreq on the macreq queue + // + NetFlexEnqueue_TwoPtrQ_Tail( + (PVOID *)&(acb->acb_macreq_head), + (PVOID *)&(acb->acb_macreq_tail), + (PVOID)macreq + ); + } + + // + // Send the scb down to the card + // + NetFlexQueueSCB(acb, ScbHead); + + ScbHead = scbreq; + + } while (NULL != scbreq); + + return(NDIS_STATUS_PENDING); + } + } + + // + // Request was aborted due to error. + // + acb->RequestInProgress = FALSE; + + return(Status); +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexQueryInformation +// +// Description: +// The NetFlexQueryInformation process a Query request for +// NDIS_OIDs that are specific about the Driver. +// +// Input: +// MiniportAdapterContext - Our Driver Context for this +// adapter or head. +// +// 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. +// +// Output: +// 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. +// +// Status - The function value is the Status of the operation. +// +// Called By: +// Miniport Wrapper +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +NDIS_STATUS +NetFlexQueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded +) +{ + PACB acb = (PACB) MiniportAdapterContext; + PMACREQ macreq; + ULONG lvalue; + USHORT svalue; + PTR_OBJS trobjs; + PETH_OBJS ethobjs; + PUCHAR srcptr; + PUCHAR copyptr = NULL; + PSCBREQ scbreq; + UCHAR vendorid[4]; + SHORT copylen = (SHORT)sizeof(ULONG); // Most common length + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + BOOLEAN needcopy = TRUE; + + if (acb->acb_state == AS_RESETTING) + { + return(NDIS_STATUS_RESET_IN_PROGRESS); + } + + // + // Initialize the result + // + *BytesWritten = 0; + *BytesNeeded = 0; + + // + // General Objects Characteristics + // + + switch (Oid) + { + case OID_GEN_SUPPORTED_LIST: + copyptr = (PUCHAR)acb->acb_gbl_oid_list; + copylen = (SHORT)acb->acb_gbl_oid_list_size; + DebugPrint(2,("NF: Query OID_GEN_SUPPORTED_LIST...\n",acb->anum)); + break; + + case OID_GEN_HARDWARE_STATUS: + lvalue = NdisHardwareStatusNotReady; + switch (acb->acb_state) + { + case AS_OPENED: + lvalue = NdisHardwareStatusReady; + DebugPrint(1,("NF(%d):Query HW Status - AS_OPENED\n",acb->anum)); + break; + case AS_CLOSING: + lvalue = NdisHardwareStatusClosing; + DebugPrint(1,("NF(%d):Query HW Status - AS_CLOSING\n",acb->anum)); + break; + case AS_RESETTING: + case AS_RESET_HOLDING: + DebugPrint(1,("NF(%d):Query HW Status - AS_RESETTING\n",acb->anum)); + lvalue = NdisHardwareStatusReset; + break; + case AS_INITIALIZING: + DebugPrint(1,("NF(%d):Query HW Status - AS_INITIALIZING\n",acb->anum)); + lvalue = NdisHardwareStatusInitializing; + break; + default: + DebugPrint(1,("NF(%d):NetFlexQueryInformation: Undefinded State - 0x%x",acb->anum,acb->acb_state)); + break; + } + copyptr = (PUCHAR)&lvalue; + DebugPrint(2,("NF(%d): Query OID_GEN_HARDWARE_STATUS 0x%x...\n",acb->anum,lvalue)); + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + copyptr = (PUCHAR)&acb->acb_gen_objs.media_type_in_use; + DebugPrint(2,("NF(%d): Query OID_GEN_MEDIA_IN_USE 0x%x...\n",acb->anum, + acb->acb_gen_objs.media_type_in_use)); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + copyptr = (PUCHAR)&acb->acb_gen_objs.max_frame_size; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + // Frame size is the max frame size minus the minimum header size. + // + lvalue = acb->acb_gen_objs.max_frame_size - 14; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_GEN_LINK_SPEED: + lvalue = acb->acb_gen_objs.link_speed * 10000; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + lvalue = acb->acb_gen_objs.max_frame_size * acb->acb_maxtrans; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + lvalue = acb->acb_gen_objs.max_frame_size * acb->acb_maxrcvs; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_GEN_VENDOR_ID: + NdisMoveMemory(vendorid,acb->acb_gen_objs.perm_staddr,3); + vendorid[3] = 0x0; + copyptr = (PUCHAR)vendorid; + break; + + case OID_GEN_VENDOR_DESCRIPTION: + copyptr = (PUCHAR)"Compaq NetFlex Driver, Version 1.10"; // RVC: move to string... + copylen = (USHORT)36; + break; + + case OID_GEN_DRIVER_VERSION: + svalue = 0x0300; + copyptr = (PUCHAR)&svalue; + copylen = (SHORT)sizeof(USHORT); + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + lvalue = acb->acb_gen_objs.cur_filter; + copyptr = (PUCHAR)&lvalue; + DebugPrint(2,("NF(%d): Query OID_GEN_CURRENT_PACKET_FILTER = 0x%x\n",acb->anum,lvalue)); + break; + + case OID_GEN_MAC_OPTIONS: + lvalue = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_RECEIVE_SERIALIZED; + + // + // Indicate we need loop back if running Full Duplex + // + if (acb->FullDuplexEnabled) + { + lvalue |= NDIS_MAC_OPTION_NO_LOOPBACK | + NDIS_MAC_OPTION_FULL_DUPLEX; + } + copyptr = (PUCHAR)&lvalue; + break; + + // + // GENERAL STATISTICS (Mandatory) + // + + case OID_GEN_XMIT_OK: + copyptr = (PUCHAR)&acb->acb_gen_objs.frames_xmitd_ok; + break; + + case OID_GEN_RCV_OK: + copyptr = (PUCHAR)&acb->acb_gen_objs.frames_rcvd_ok; + break; + + case OID_GEN_XMIT_ERROR: + copyptr = (PUCHAR)&acb->acb_gen_objs.frames_xmitd_err; + break; + + case OID_GEN_RCV_ERROR: + copyptr = (PUCHAR)&acb->acb_gen_objs.frames_rcvd_err; + break; + + case OID_NF_INTERRUPT_COUNT: + copyptr = (PUCHAR)&acb->acb_gen_objs.interrupt_count; + break; + + case OID_NF_INTERRUPT_RATIO: + copyptr = (PUCHAR)&acb->RcvIntRatio; + break; + + case OID_NF_INTERRUPT_RATIO_CHANGES: + copyptr = (PUCHAR)&acb->acb_gen_objs.interrupt_ratio_changes; + break; + + } // end of general + + if (copyptr == NULL) + { + if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3 ) + { + //--------------------------------------- + // Ethernet Specific Oid's + //--------------------------------------- + // + + switch (Oid) + { + //------------------------------------- + // 802.3 OPERATIONAL CHARACTERISTICS + //------------------------------------- + + case OID_802_3_PERMANENT_ADDRESS: + srcptr = acb->acb_gen_objs.perm_staddr; + copyptr = (PUCHAR)srcptr; + copylen = (SHORT)NET_ADDR_SIZE; + + case OID_802_3_CURRENT_ADDRESS: + srcptr = acb->acb_gen_objs.current_staddr; + copyptr = (PUCHAR)srcptr; + copylen = (SHORT)NET_ADDR_SIZE; + break; + + case OID_802_3_MULTICAST_LIST: + DebugPrint(2,("NF(%d): Query OID_802_3_MULTICAST_LIST\n",acb->anum)); + ethobjs = (PETH_OBJS)(acb->acb_spec_objs); + + needcopy = TRUE; + copylen = ethobjs->NumberOfEntries * NET_ADDR_SIZE; + copyptr = (PVOID) ðobjs->NumberOfEntries; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + ethobjs = (PETH_OBJS)(acb->acb_spec_objs); + lvalue = ethobjs->MaxMulticast; + copyptr = (PUCHAR)&lvalue; + DebugPrint(2,("NF(%d): Query OID_802_3_MAXIMUM_LIST_SIZE = 0x%x\n",acb->anum,lvalue)); + break; + + //------------------------------- + // 802.3 STATISTICS (Mandatory) + //------------------------------- + + case OID_GEN_RCV_NO_BUFFER: + lvalue = 0; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_LATE_COLLISIONS: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_GEN_RCV_CRC_ERROR: + if (acb->acb_logbuf_valid) + { + ethobjs = (PETH_OBJS)(acb->acb_spec_objs); + + switch (Oid) + { + case OID_802_3_RCV_ERROR_ALIGNMENT: + lvalue = ethobjs->RSL_AlignmentErr; + break; + case OID_802_3_XMIT_ONE_COLLISION: + lvalue = ethobjs->RSL_1_Collision; + break; + case OID_802_3_XMIT_MORE_COLLISIONS: + lvalue = ethobjs->RSL_More_Collision; + break; + case OID_802_3_XMIT_DEFERRED: + lvalue = ethobjs->RSL_DeferredXmit; + break; + case OID_802_3_XMIT_LATE_COLLISIONS: + lvalue = ethobjs->RSL_LateCollision; + break; + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_XMIT_TIMES_CRS_LOST: + lvalue = ethobjs->RSL_Excessive; + break; + default: + lvalue = ethobjs->RSL_FrameCheckSeq; + break; + } + copyptr = (PUCHAR)&lvalue; + } + else + { + needcopy = FALSE; + Status = NetFlexDequeue_OnePtrQ_Head( + (PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq); + + if (Status != NDIS_STATUS_SUCCESS) + { + Status = NDIS_STATUS_RESOURCES; + } + else + { + // Save the information about the request + // + if (acb->RequestInProgress) + { + DebugPrint(0,("NF(%d): Query OID: Aready have RequestInProcess!\n",acb->anum)); + // return NDIS_STATUS_FAILURE; + } + + acb->RequestInProgress = TRUE; + + acb->BytesWritten = BytesWritten; + acb->BytesNeeded = BytesNeeded; + acb->Oid = Oid; + acb->InformationBuffer = InformationBuffer; + acb->InformationBufferLength = InformationBufferLength; + + DebugPrint(2,("NF(%d): Queue Up Request to get OID (0x%x) info\n",acb->anum,Oid)); + + NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free), + (PVOID *)¯eq); + macreq->req_next = NULL; + macreq->req_type = QUERY_CMP; + macreq->req_status = NDIS_STATUS_SUCCESS; + + scbreq->req_scb.SCB_Cmd = TMS_READLOG; + scbreq->req_macreq = macreq; + scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_logbuf_physptr))); + + // + // put the macreq on the macreq queue + // + NetFlexEnqueue_TwoPtrQ_Tail( (PVOID *)&(acb->acb_macreq_head), + (PVOID *)&(acb->acb_macreq_tail), + (PVOID)macreq); + + NetFlexQueueSCB(acb, scbreq); + Status = NDIS_STATUS_PENDING; + } + } + break; + + default: + DebugPrint(1,("NF(%d): (ETH) Invalid Query or Unsupported OID, %x\n",acb->anum,Oid)); + Status = NDIS_STATUS_NOT_SUPPORTED; + needcopy = FALSE; + break; + } + } + else + { + //--------------------------------------- + // Token Ring Specific Oid's + //--------------------------------------- + // + switch (Oid) + { + // We added the 802.5 stats here as well because of the + // read error log buffer. + // + case OID_802_5_LINE_ERRORS: + case OID_802_5_LOST_FRAMES: + case OID_802_5_BURST_ERRORS: + case OID_802_5_AC_ERRORS: + case OID_802_5_CONGESTION_ERRORS: + case OID_802_5_FRAME_COPIED_ERRORS: + case OID_802_5_TOKEN_ERRORS: + case OID_GEN_RCV_NO_BUFFER: + if (acb->acb_logbuf_valid) + { + trobjs = (PTR_OBJS)(acb->acb_spec_objs); + switch (Oid) + { + case OID_GEN_RCV_NO_BUFFER: + lvalue = trobjs->REL_Congestion; + break; + case OID_802_5_LINE_ERRORS: + lvalue = trobjs->REL_LineError; + break; + case OID_802_5_LOST_FRAMES: + lvalue = trobjs->REL_LostError; + break; + case OID_802_5_BURST_ERRORS: + lvalue = trobjs->REL_BurstError; + break; + case OID_802_5_AC_ERRORS: + lvalue = trobjs->REL_ARIFCIError; + break; + case OID_802_5_CONGESTION_ERRORS: + lvalue = trobjs->REL_Congestion; + break; + case OID_802_5_FRAME_COPIED_ERRORS: + lvalue = trobjs->REL_CopiedError; + break; + case OID_802_5_TOKEN_ERRORS: + lvalue = trobjs->REL_TokenError; + break; + default: + DebugPrint(0,("NetFlexQueryInformation: Undefinded OID - 0x%x",Oid)); + break; + } + copyptr = (PUCHAR)&lvalue; + } + else + { + needcopy = FALSE; + Status = NetFlexDequeue_OnePtrQ_Head((PVOID *)&(acb->acb_scbreq_free), + (PVOID *)&scbreq); + + if (Status != NDIS_STATUS_SUCCESS) + { + Status = NDIS_STATUS_RESOURCES; + } + else + { + // + // Save the information about the request + // + if (acb->RequestInProgress) + { + DebugPrint(0,("NF(%d): Query OID: Aready have RequestInProcess!\n",acb->anum)); + //return NDIS_STATUS_FAILURE; + } + + acb->RequestInProgress = TRUE; + + acb->BytesWritten = BytesWritten; + acb->BytesNeeded = BytesNeeded; + acb->Oid = Oid; + acb->InformationBuffer = InformationBuffer; + acb->InformationBufferLength = InformationBufferLength; + + DebugPrint(2,("NF(%d): Queue Up Request to get OID (0x%x) info\n",acb->anum,Oid)); + + NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free), + (PVOID *)¯eq); + macreq->req_next = NULL; + macreq->req_type = QUERY_CMP; + macreq->req_status = NDIS_STATUS_SUCCESS; + + scbreq->req_scb.SCB_Cmd = TMS_READLOG; + scbreq->req_macreq = macreq; + scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_logbuf_physptr))); + // + // put the macreq on the macreq queue + // + NetFlexEnqueue_TwoPtrQ_Tail( (PVOID *)&(acb->acb_macreq_head), + (PVOID *)&(acb->acb_macreq_tail), + (PVOID)macreq); + + NetFlexQueueSCB(acb, scbreq); + Status = NDIS_STATUS_PENDING; + } + } + break; + + //------------------------------------ + // 802.5 OPERATIONAL CHARACTERISTICS + //------------------------------------ + + case OID_802_5_PERMANENT_ADDRESS: + srcptr = acb->acb_gen_objs.perm_staddr; + copyptr = (PUCHAR)srcptr; + copylen = (SHORT)NET_ADDR_SIZE; + break; + + case OID_802_5_CURRENT_ADDRESS: + srcptr = acb->acb_gen_objs.current_staddr; + copyptr = (PUCHAR)srcptr; + copylen = (SHORT)NET_ADDR_SIZE; + break; + + case OID_802_5_UPSTREAM_ADDRESS: + NetFlexGetUpstreamAddress(acb); + srcptr = ((PTR_OBJS)acb->acb_spec_objs)->upstream_addr; + copyptr = (PUCHAR)srcptr; + copylen = (SHORT)NET_ADDR_SIZE; + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + lvalue = *( (PULONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_func_addr)); + copyptr = (PUCHAR)&lvalue; + copylen = (SHORT)NET_GROUP_SIZE; + break; + + case OID_802_5_CURRENT_GROUP: + lvalue = *( (PULONG)(((PTR_OBJS)(acb->acb_spec_objs))->cur_grp_addr)); + copylen = (lvalue == 0) ? 0 : NET_GROUP_SIZE; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_802_5_LAST_OPEN_STATUS: + lvalue = acb->acb_lastopenstat; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_802_5_CURRENT_RING_STATUS: + lvalue = acb->acb_lastringstatus; + copyptr = (PUCHAR)&lvalue; + break; + + case OID_802_5_CURRENT_RING_STATE: + lvalue = acb->acb_lastringstate; + copyptr = (PUCHAR)&lvalue; + break; + + default: + DebugPrint(1,("NF(%d): (TR) Invalid Query or Unsupported OID, %x\n",acb->anum,Oid)); + Status = NDIS_STATUS_NOT_SUPPORTED; + needcopy = FALSE; + break; + } + } + } + + if (needcopy) + { + // Do we have enough space for the list + the oid value + the length? + // + if (InformationBufferLength < (USHORT) copylen) + { + DebugPrint(1,("NF(%d): Tell the user of the bytes needed\n",acb->anum)); + *BytesNeeded = copylen - InformationBufferLength; + Status = NDIS_STATUS_INVALID_LENGTH; + } + else + { + // Copy the data bytes + // + NdisMoveMemory( InformationBuffer, + copyptr, + copylen); + // + // Update the information pointer and size. + // + *BytesWritten += copylen; + } + } + + acb->RequestInProgress = Status == NDIS_STATUS_PENDING; + + return Status; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexFinishQueryInformation +// +// Description: +// The NetFlexFinishQueryInformation finish processing a Query request for +// NDIS_OIDs that are specific about the Driver which we had to update +// before returning. +// +// Input: +// acb - Our Driver Context for this adapter or head. +// +// Output: +// The function value is the Status of the operation. +// +// Called By: +// +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +VOID +NetFlexFinishQueryInformation( + PACB acb, + NDIS_STATUS Status + ) +{ + ULONG lvalue; + PTR_OBJS trobjs; + PETH_OBJS ethobjs; + BOOLEAN needcopy = TRUE; + PUCHAR copyptr; + SHORT copylen = (SHORT)sizeof(ULONG); // Most common length + + // + // Get the saved information about the request. + // + + PUINT BytesWritten = acb->BytesWritten; + PUINT BytesNeeded = acb->BytesNeeded; + NDIS_OID Oid = acb->Oid; + PVOID InformationBuffer = acb->InformationBuffer; + UINT InformationBufferLength = acb->InformationBufferLength; + + DebugPrint(2,("NF(%d): NetFlexFinishQueryInformation\n",acb->anum)); + + if (Status == NDIS_STATUS_SUCCESS) + { + *BytesNeeded = 0; + + switch (Oid) + { + + case OID_GEN_RCV_NO_BUFFER: + case OID_802_5_LINE_ERRORS: + case OID_802_5_LOST_FRAMES: + case OID_802_5_BURST_ERRORS: + case OID_802_5_AC_ERRORS: + case OID_802_5_CONGESTION_ERRORS: + case OID_802_5_FRAME_COPIED_ERRORS: + case OID_802_5_TOKEN_ERRORS: + trobjs = (PTR_OBJS)(acb->acb_spec_objs); + switch (Oid) + { + case OID_GEN_RCV_NO_BUFFER: + lvalue = trobjs->REL_Congestion; + break; + case OID_802_5_LINE_ERRORS: + lvalue = trobjs->REL_LineError; + break; + case OID_802_5_LOST_FRAMES: + lvalue = trobjs->REL_LostError; + break; + case OID_802_5_BURST_ERRORS: + lvalue = trobjs->REL_BurstError; + break; + case OID_802_5_AC_ERRORS: + lvalue = trobjs->REL_ARIFCIError; + break; + case OID_802_5_CONGESTION_ERRORS: + lvalue = trobjs->REL_Congestion; + break; + case OID_802_5_FRAME_COPIED_ERRORS: + lvalue = trobjs->REL_CopiedError; + break; + case OID_802_5_TOKEN_ERRORS: + lvalue = trobjs->REL_TokenError; + break; + default: + DebugPrint(0,("NetFlexFinishQueryInformation: Undefinded OID - 0x%x",Oid)); + break; + } + copyptr = (PUCHAR)&lvalue; + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_LATE_COLLISIONS: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_GEN_RCV_CRC_ERROR: + ethobjs = (PETH_OBJS)(acb->acb_spec_objs); + + switch (Oid) + { + case OID_802_3_RCV_ERROR_ALIGNMENT: + lvalue = ethobjs->RSL_AlignmentErr; + break; + case OID_802_3_XMIT_ONE_COLLISION: + lvalue = ethobjs->RSL_1_Collision; + break; + case OID_802_3_XMIT_MORE_COLLISIONS: + lvalue = ethobjs->RSL_More_Collision; + break; + case OID_802_3_XMIT_DEFERRED: + lvalue = ethobjs->RSL_DeferredXmit; + break; + case OID_802_3_XMIT_LATE_COLLISIONS: + lvalue = ethobjs->RSL_LateCollision; + break; + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_XMIT_TIMES_CRS_LOST: + lvalue = ethobjs->RSL_Excessive; + break; + default: + lvalue = ethobjs->RSL_FrameCheckSeq; + break; + } + copyptr = (PUCHAR)&lvalue; + break; + + default: + DebugPrint(1,("NF(%d): Invalid Query or Unsupported OID, %x\n",acb->anum,Oid)); + Status = NDIS_STATUS_NOT_SUPPORTED; + needcopy = FALSE; + break; + } + + if (needcopy) + { + // Do we have enough space for the list + the oid value + the length? + // + if (InformationBufferLength < (USHORT) copylen) + { + DebugPrint(1,("NF(%d): Tell the user of the bytes needed\n",acb->anum)); + *BytesNeeded = copylen - InformationBufferLength; + Status = NDIS_STATUS_INVALID_LENGTH; + } + else + { + // Copy the data bytes + // + NdisMoveMemory( InformationBuffer, + copyptr, + copylen); + // + // Update the information pointer and size. + // + *BytesWritten += copylen; + } + } + } + + // + // Complete the request + // + NdisMQueryInformationComplete( acb->acb_handle, + Status ); + acb->RequestInProgress = FALSE; + +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexGetUpstreamAddress +// +// Description: +// This routine gets the upstream neighbor of +// the adapter in Token-Ring. +// +// Input: +// acb - Our Driver Context for this adapter or head. +// +// Output: +// Returns NDIS_STATUS_SUCCESS for a successful +// completion. Otherwise, an error code is returned. +// +// Called By: +// NetFlexBoardInitandReg +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +VOID +NetFlexGetUpstreamAddress( + PACB acb + ) +{ + USHORT value; + SHORT i; + + NdisRawWritePortUshort(acb->SifAddrPort, acb->acb_upstreamaddrptr+4 ); + + for (i = 0; i < 3; i++) + { + NdisRawReadPortUshort(acb->SifDIncPort,(PUSHORT) &value); + + ((PTR_OBJS)(acb->acb_spec_objs))->upstream_addr[i*2] = + (UCHAR)(SWAPS(value)); + ((PTR_OBJS)(acb->acb_spec_objs))->upstream_addr[(i*2)+1] = + (UCHAR)value; + } +} + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexProcessMacReq +// +// Description: +// This routine completes a request which had to wait +// for a adapter command to complete. +// +// Input: +// acb - Our Driver Context for this adapter or head. +// +// Output: +// None +// +// Called By: +// NetFlexHandleInterrupt +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +VOID +NetFlexProcessMacReq( + PACB acb + ) +{ + + NDIS_STATUS status; + PMACREQ macreq; + BOOLEAN ReceiveResult; + + DebugPrint(1,("NF(%d): NetFlexProcessMacReq entered.\n", acb->anum)); + + while (acb->acb_confirm_qhead != NULL) + { + // We have command to complete. + // + macreq = acb->acb_confirm_qhead; + if ((acb->acb_confirm_qhead = macreq->req_next) == NULL) + { + acb->acb_confirm_qtail = NULL; + } + // + // what was the status... + // + status = macreq->req_status; + + switch (macreq->req_type) + { + case OPENADAPTER_CMP: + + // + // Cancel the Reset Timer, since the hardware seems to be working correctly + // + NdisMCancelTimer(&acb->ResetTimer,&ReceiveResult); + + // + // Did the open complete successfully? + // + if (status == NDIS_STATUS_SUCCESS) + { + // Yes, mark as opened. + // + acb->acb_lastopenstat = 0; + acb->acb_lastringstate = NdisRingStateOpened; + + // + // If the open completed successfully, we need to + // issue the transmit and receive commands. Also, + // we need to set the state according to the status. + // + if (acb->acb_state == AS_OPENING) + { + acb->acb_state = AS_OPENED; + } + + // + // Now lets finish the open by sending a receive command to the adapter. + // + acb->acb_rcv_whead = acb->acb_rcv_head; + + // + // Now lets finish the open by sending a + // transmit and receive command to the adapter. + // + acb->acb_xmit_whead = acb->acb_xmit_wtail = acb->acb_xmit_head; + + // + // If the adapter is ready for a command, call a + // routine that will kick off the transmit command. + // + if (acb->acb_scb_virtptr->SCB_Cmd == 0) + { + NetFlexSendNextSCB(acb); + } + else if (!acb->acb_scbclearout) + { + // + // Make sure we are interrupted when the SCB is + // available so that we can send the transmit command. + // + acb->acb_scbclearout = TRUE; + NdisRawWritePortUshort( + acb->SifIntPort, + (USHORT)SIFINT_SCBREQST); + } + } + else + { + // Open failed. + // If we had an open error that is specific to TOKEN RING, + // set the last open status to the correct error code. Otherwise, + // just send the status as normal. + // + if (macreq->req_status == NDIS_STATUS_TOKEN_RING_OPEN_ERROR) + { + acb->acb_lastopenstat = (NDIS_STATUS)(macreq->req_info) | + NDIS_STATUS_TOKEN_RING_OPEN_ERROR; + } + else + { + acb->acb_lastopenstat = 0; + } + acb->acb_lastringstate = NdisRingStateOpenFailure; + + if (acb->acb_state == AS_OPENING) + { + acb->acb_state = AS_INITIALIZED; + } + // + // Force a reset. + // + acb->ResetState = RESET_STAGE_4; + } + + // + // Put Macreq back on free queue + // + NetFlexEnqueue_OnePtrQ_Head((PVOID *)&(acb->acb_macreq_free), + (PVOID)macreq); + + + // + // + // processed the open command. + // + + if (acb->ResetState == RESET_STAGE_4) + { + // + // If this is the completion of a Reset, set the reset timer + // so it can be completed. + // + NdisMSetTimer(&acb->ResetTimer,10); + } + break; + + case CLOSEADAPTER_CMP: + acb->acb_state = AS_CLOSING; + break; + + case QUERY_CMP: + case REQUEST_CMP: + + if (acb->RequestInProgress) + { + // + // Go process the request + // Is it a Query or a Set? + // + if (macreq->req_type == QUERY_CMP) + { + NetFlexFinishQueryInformation(acb,status); + } + else + { + DebugPrint(1,("NF(%d): NetFlexProcessMacReq: Completing request.\n", acb->anum)); + + acb->RequestInProgress = FALSE; + NdisMSetInformationComplete(acb->acb_handle, status); + } + } + else + { + DebugPrint(0,("NF(%d): Have macreq QUERY_CMP or REQUEST_CMP without RequestInProgress!\n",acb->anum)); + } + + NdisZeroMemory(macreq, sizeof(MACREQ)); + NetFlexEnqueue_OnePtrQ_Head( + (PVOID *)&(acb->acb_macreq_free), + (PVOID)macreq + ); + + break; + + default: // We should NEVER be here + DebugPrint(0,("NF(%d): ProcessMaqReq - No command - ERROR!\n",acb->anum)); + break; + } // End of switch + } // End of while confirm q +} |