/*++ Copyright (c) 1991 Microsoft Corporation Module Name: request.c Abstract: This file contains code to implement request processing. This driver conforms to the NDIS 3.0 miniport interface. Author: Johnson R. Apacible (JohnsonA) 10-June-1991 Environment: Revision History: --*/ #include extern NDIS_STATUS NE3200ChangeClass( PNE3200_ADAPTER Adapter, IN UINT NewFilterClasses ) /*++ Routine Description: Action routine that will get called when a particular filter class is first used or last cleared. Arguments: NewFilterClasses - The current value of the class filter Return Value: None. --*/ { // // Holds the change that should be returned to the filtering package. // NDIS_STATUS StatusOfChange; // // Holds the list of changes; // UINT PacketChanges; // // This points to the public Command Block. // PNE3200_SUPER_COMMAND_BLOCK CommandBlock; // // This points to the adapter's configuration block. // PNE3200_CONFIGURATION_BLOCK ConfigurationBlock = Adapter->ConfigurationBlock; // // The NE3200 has no method for easily disabling multicast // packets. Therefore, we'll only reconfigure the 82586 // when there is a change in either directed, broadcast, or // promiscuous filtering. // PacketChanges = (Adapter->CurrentPacketFilter ^ NewFilterClasses) & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED); if (!PacketChanges) { return(NDIS_STATUS_SUCCESS); } // // Use the generic command block // IF_LOG('F'); NE3200AcquirePublicCommandBlock( Adapter, &CommandBlock ); // // This from a set. // CommandBlock->Set = TRUE; // // Setup the command block. // CommandBlock->NextCommand = NULL; CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; CommandBlock->Hardware.Status = 0; CommandBlock->Hardware.NextPending = NE3200_NULL; CommandBlock->Hardware.CommandCode = NE3200_COMMAND_CONFIGURE_82586; CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock = NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical); // // Update the configuration block to reflect the new // packet filtering. // if (NewFilterClasses == 0) { ConfigurationBlock->PromiscuousMode = 0; ConfigurationBlock->MacBinPromiscuous = 0; ConfigurationBlock->DisableBroadcast = 1; } else { ConfigurationBlock->MacBinEnablePacketReception = 1; if (PacketChanges & NDIS_PACKET_TYPE_PROMISCUOUS) { ConfigurationBlock->PromiscuousMode = 1; ConfigurationBlock->MacBinPromiscuous = 1; } else { ConfigurationBlock->PromiscuousMode = 0; ConfigurationBlock->MacBinPromiscuous = 0; } if (PacketChanges & NDIS_PACKET_TYPE_BROADCAST) { ConfigurationBlock->DisableBroadcast = 0; } else { ConfigurationBlock->DisableBroadcast = 1; } } // // Now that we've got the command block built, // let's do it! // NE3200SubmitCommandBlock(Adapter, CommandBlock); StatusOfChange = NDIS_STATUS_PENDING; return StatusOfChange; } STATIC NDIS_STATUS NE3200UpdateMulticastTable( IN PNE3200_ADAPTER Adapter, IN UINT CurrentAddressCount, IN CHAR CurrentAddresses[][NE3200_LENGTH_OF_ADDRESS] ) /*++ Routine Description: This routine is called to update the list of multicast addreses on the adapter. Arguments: Adapter - The adapter where the multicast is to be changed. CurrentAddressCount - The number of addresses in the address array. CurrentAddresses - An array of multicast addresses. Note that this array already contains the new address. Return Value: None. --*/ { // // This points to the public Command Block. // PNE3200_SUPER_COMMAND_BLOCK CommandBlock; // // Holds the status that should be returned to the filtering package. // NDIS_STATUS StatusOfUpdate; // // Multicast address table // PUCHAR MulticastAddressTable; IF_LOG('f'); // // See if we can acquire a private command block. // NE3200AcquirePublicCommandBlock(Adapter, &CommandBlock); // // Store the request that uses this command block. // CommandBlock->Set = TRUE; // // Get the multicast address table. // MulticastAddressTable = Adapter->CardMulticastTable; // // Clear out the old address // NdisZeroMemory( MulticastAddressTable, CurrentAddressCount * NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY ); { // // Simple iteration counter. // UINT i; // // Pointer into the multicast address table. // PCHAR OriginalAddress; // // Pointer into our temporary buffer. // PCHAR MungedAddress; // // Munge the address to 16 bytes per entry. // OriginalAddress = &CurrentAddresses[0][0]; MungedAddress = MulticastAddressTable; for ( i = CurrentAddressCount ; i > 0 ; i-- ) { NdisMoveMemory( MungedAddress, OriginalAddress, NE3200_LENGTH_OF_ADDRESS ); OriginalAddress += NE3200_LENGTH_OF_ADDRESS; MungedAddress += NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY; } // // Setup the command block. // CommandBlock->NextCommand = NULL; CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; CommandBlock->Hardware.Status = 0; CommandBlock->Hardware.NextPending = NE3200_NULL; CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_MULTICAST_ADDRESS; CommandBlock->Hardware.PARAMETERS.MULTICAST.NumberOfMulticastAddresses = (USHORT)CurrentAddressCount; if (CurrentAddressCount == 0) { CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable = (NE3200_PHYSICAL_ADDRESS)NULL; } else { CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable = NdisGetPhysicalAddressLow(Adapter->CardMulticastTablePhysical); } // // Now that we've got the command block built, // let's do it! // NE3200SubmitCommandBlock(Adapter, CommandBlock); StatusOfUpdate = NDIS_STATUS_PENDING; } return StatusOfUpdate; } extern NDIS_STATUS NE3200SetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ) /*++ Routine Description: NE3200SetInformation handles a set operation for a single OID. Arguments: MiniportAdapterContext - The adapter that the set is for. Oid - The OID of the set. InformationBuffer - Holds the data to be set. InformationBufferLength - The length of InformationBuffer. 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. Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_PENDING NDIS_STATUS_INVALID_LENGTH NDIS_STATUS_INVALID_OID --*/ { // // Variable to hold the new packet filter // ULONG PacketFilter; // // The adapter to process the request for. // PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); // // Status of NDIS operation // NDIS_STATUS Status; IF_LOG('w'); // // Now check for the most common OIDs // switch (Oid) { case OID_802_3_MULTICAST_LIST: if (InformationBufferLength % NE3200_LENGTH_OF_ADDRESS != 0) { // // The data must be a multiple of the Ethernet // address size. // return(NDIS_STATUS_INVALID_DATA); } // // Now call the routine that does this. // Status = NE3200UpdateMulticastTable( Adapter, InformationBufferLength / NE3200_LENGTH_OF_ADDRESS, InformationBuffer ); *BytesRead = InformationBufferLength; break; case OID_GEN_CURRENT_PACKET_FILTER: if (InformationBufferLength != 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_ALL_MULTICAST | NDIS_PACKET_TYPE_GROUP )) { Status = NDIS_STATUS_NOT_SUPPORTED; *BytesRead = 4; *BytesNeeded = 0; break; } // // Submit the change // Status = NE3200ChangeClass( Adapter, PacketFilter ); *BytesRead = InformationBufferLength; break; case OID_GEN_CURRENT_LOOKAHEAD: *BytesRead = 4; Status = NDIS_STATUS_SUCCESS; break; default: Status = NDIS_STATUS_INVALID_OID; break; } if (Status == NDIS_STATUS_PENDING) { Adapter->RequestInProgress = TRUE; } IF_LOG('W'); return Status; } STATIC NDIS_STATUS NE3200QueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: The NE3200QueryInformation process a Query request for NDIS_OIDs that are specific about the Driver. Arguments: MiniportAdapterContext - a pointer to the adapter. 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. --*/ { // // The command block for getting the statistics from the adapter. // PNE3200_SUPER_COMMAND_BLOCK CommandBlock; // // The adapter to process the request for. // PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); // // Save the information about the request // Adapter->BytesWritten = BytesWritten; Adapter->BytesNeeded = BytesNeeded; Adapter->Oid = Oid; Adapter->InformationBuffer = InformationBuffer; Adapter->InformationBufferLength = InformationBufferLength; IF_LOG('?'); // // Get a public command block. This will succeed since // the wrapper will only give one request at a time, and // there are more than 1 public command block. // NE3200AcquirePublicCommandBlock(Adapter, &CommandBlock ); // // Store the request that uses this CB // CommandBlock->Set = TRUE; // // Setup the command block. // CommandBlock->NextCommand = NULL; CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; CommandBlock->Hardware.Status = 0; CommandBlock->Hardware.NextPending = NE3200_NULL; CommandBlock->Hardware.CommandCode = NE3200_COMMAND_READ_ADAPTER_STATISTICS; // // Now that we're set up, let's do it! // Adapter->RequestInProgress = TRUE; NE3200SubmitCommandBlock(Adapter, CommandBlock); // // Catch the ball at the interrupt handler // IF_LOG('/'); return NDIS_STATUS_PENDING; } STATIC VOID NE3200FinishQueryInformation( IN PNE3200_ADAPTER Adapter ) /*++ Routine Description: The NE3200FinishQueryInformation finish processing a Query request for NDIS_OIDs that are specific about the Driver. Arguments: Adapter - a pointer to the adapter. Return Value: The function value is the status of the operation. --*/ { static NDIS_OID NE3200GlobalSupportedOids[] = { 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, OID_802_3_XMIT_LATE_COLLISIONS }; // // Get the saved information about the request. // PUINT BytesWritten = Adapter->BytesWritten; PUINT BytesNeeded = Adapter->BytesNeeded; NDIS_OID Oid = Adapter->Oid; PVOID InformationBuffer = Adapter->InformationBuffer; UINT InformationBufferLength = Adapter->InformationBufferLength; // // Variables for holding the data that satisfies the request. // NDIS_MEDIUM Medium = NdisMedium802_3; UINT GenericUlong; USHORT GenericUShort; UCHAR GenericArray[6]; NDIS_HARDWARE_STATUS HardwareStatus; // // Common variables for pointing to result of query // PVOID MoveSource = (PVOID)(&GenericUlong); ULONG MoveBytes = sizeof(ULONG); // // The status of the request. // NDIS_STATUS Status = NDIS_STATUS_SUCCESS; // // Initialize the result // *BytesWritten = 0; *BytesNeeded = 0; IF_LOG('!'); // // Switch on request type // switch(Oid){ case OID_GEN_MAC_OPTIONS: GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_NO_LOOPBACK ); break; case OID_GEN_SUPPORTED_LIST: MoveSource = (PVOID)(NE3200GlobalSupportedOids); MoveBytes = sizeof(NE3200GlobalSupportedOids); break; case OID_GEN_HARDWARE_STATUS: if (Adapter->ResetInProgress){ HardwareStatus = NdisHardwareStatusReset; } 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 - NE3200_HEADER_SIZE); break; case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_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 * NE3200_NUMBER_OF_TRANSMIT_BUFFERS; break; case OID_GEN_RECEIVE_BUFFER_SPACE: GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE * NE3200_NUMBER_OF_RECEIVE_BUFFERS; break; 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)"NE3200 Adapter"; MoveBytes = 15; break; case OID_GEN_DRIVER_VERSION: GenericUShort = (USHORT)0x0300; MoveSource = (PVOID)(&GenericUShort); MoveBytes = sizeof(GenericUShort); break; case OID_802_3_PERMANENT_ADDRESS: NdisMoveMemory( (PCHAR)GenericArray, Adapter->NetworkAddress, NE3200_LENGTH_OF_ADDRESS ); MoveSource = (PVOID)(GenericArray); MoveBytes = NE3200_LENGTH_OF_ADDRESS; break; case OID_802_3_CURRENT_ADDRESS: NdisMoveMemory( (PCHAR)GenericArray, Adapter->CurrentAddress, NE3200_LENGTH_OF_ADDRESS ); MoveSource = (PVOID)(GenericArray); MoveBytes = NE3200_LENGTH_OF_ADDRESS; break; case OID_802_3_MAXIMUM_LIST_SIZE: GenericUlong = (ULONG) NE3200_MAXIMUM_MULTICAST; break; default: 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: GenericUlong = (ULONG) (Adapter->CrcErrors + Adapter->AlignmentErrors + Adapter->OutOfResources + Adapter->DmaOverruns); break; case OID_GEN_RCV_NO_BUFFER: GenericUlong = (ULONG) Adapter->OutOfResources; break; case OID_GEN_RCV_CRC_ERROR: GenericUlong = (ULONG) Adapter->CrcErrors; break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: GenericUlong = (ULONG) Adapter->TransmitsQueued; break; case OID_802_3_RCV_ERROR_ALIGNMENT: GenericUlong = (ULONG) Adapter->AlignmentErrors; 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: GenericUlong = (ULONG) Adapter->DmaOverruns; 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: Status = NDIS_STATUS_NOT_SUPPORTED; break; } } if (Status == NDIS_STATUS_SUCCESS) { if (MoveBytes > InformationBufferLength) { // // Not enough room in InformationBuffer. Punt // *BytesNeeded = MoveBytes; Status = NDIS_STATUS_INVALID_LENGTH; } else { // // Copy result into InformationBuffer // *BytesWritten = MoveBytes; if (MoveBytes > 0) { NE3200_MOVE_MEMORY( InformationBuffer, MoveSource, MoveBytes ); } } } Adapter->RequestInProgress = FALSE; // // Complete the request // NdisMQueryInformationComplete( Adapter->MiniportAdapterHandle, Status ); IF_LOG('@'); return; }