/*++ Copyright (c) 1990-1992 Microsoft Corporation Module Name: request.c Abstract: This is the cose to handle requests for the National Semiconductor SONIC Ethernet controller. This driver conforms to the NDIS 3.0 miniport interface. Author: Adam Barr (adamba) 14-Nov-1990 Environment: Kernel Mode - Or whatever is the equivalent. Revision History: --*/ #include #include #include // // This macro determines if the directed address // filtering in the CAM is actually necessary given // the current filter. // #define CAM_DIRECTED_SIGNIFICANT(_Filter) \ ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \ (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0) // // This macro determines if the multicast filtering in // the CAM are actually necessary given the current filter. // #define CAM_MULTICAST_SIGNIFICANT(_Filter) \ ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \ (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \ NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0) STATIC NDIS_STATUS ChangeClassDispatch( IN PSONIC_ADAPTER Adapter, IN UINT NewFilterClasses ); STATIC NDIS_STATUS ChangeAddressDispatch( IN PSONIC_ADAPTER Adapter, IN UINT AddressCount, IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] ); extern NDIS_STATUS SonicQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: SonicQueryInformation handles a query operation for a single OID. Arguments: MiniportAdapterContext - Context registered with the wrapper, really a pointer to the adapter. Oid - The OID of the query. InformationBuffer - Holds the result of the query. InformationBufferLength - The length of InformationBuffer. BytesWritten - If the call is successful, returns the number of bytes written to InformationBuffer. BytesNeeded - If there is not enough room in InformationBuffer 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 --*/ { PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); INT i; INT SupportedOids; NDIS_OID MaskOid; PVOID SourceBuffer; ULONG SourceBufferLength; ULONG GenericUlong; USHORT GenericUshort; UCHAR VendorId[4]; #ifdef SONIC_EISA static const UCHAR EisaDescriptor[] = "SONIC EISA Bus Master Ethernet Adapter (DP83932EB-EISA)"; #endif #ifdef SONIC_INTERNAL static const UCHAR InternalDescriptor[] = "MIPS R4000 on-board network controller"; #endif static const NDIS_OID SonicSupportedOids[] = { 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_DIRECTED_BYTES_XMIT, OID_GEN_DIRECTED_FRAMES_XMIT, OID_GEN_MULTICAST_BYTES_XMIT, OID_GEN_MULTICAST_FRAMES_XMIT, OID_GEN_BROADCAST_BYTES_XMIT, OID_GEN_BROADCAST_FRAMES_XMIT, OID_GEN_DIRECTED_BYTES_RCV, OID_GEN_DIRECTED_FRAMES_RCV, OID_GEN_MULTICAST_BYTES_RCV, OID_GEN_MULTICAST_FRAMES_RCV, OID_GEN_BROADCAST_BYTES_RCV, OID_GEN_BROADCAST_FRAMES_RCV, 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 }; // // Check that the OID is valid. // SupportedOids = sizeof(SonicSupportedOids)/sizeof(ULONG); for (i=0; iPermanentNetworkAddress, 3); VendorId[3] = 0x0; SourceBuffer = VendorId; SourceBufferLength = sizeof(VendorId); break; case OID_GEN_VENDOR_DESCRIPTION: switch (Adapter->AdapterType) { #ifdef SONIC_EISA case SONIC_ADAPTER_TYPE_EISA: SourceBuffer = (PVOID)EisaDescriptor; SourceBufferLength = sizeof(EisaDescriptor); break; #endif #ifdef SONIC_INTERNAL case SONIC_ADAPTER_TYPE_INTERNAL: SourceBuffer = (PVOID)InternalDescriptor; SourceBufferLength = sizeof(InternalDescriptor); break; #endif default: ASSERT(FALSE); break; } break; case OID_GEN_DRIVER_VERSION: GenericUshort = (SONIC_NDIS_MAJOR_VERSION << 8) + SONIC_NDIS_MINOR_VERSION; SourceBuffer = &GenericUshort; SourceBufferLength = sizeof(USHORT); break; case OID_GEN_CURRENT_PACKET_FILTER: GenericUlong = Adapter->CurrentPacketFilter; break; case OID_GEN_CURRENT_LOOKAHEAD: GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ? SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM; break; default: ASSERT(FALSE); break; } break; case OID_TYPE_GENERAL_STATISTICS: MaskOid = (Oid & OID_INDEX_MASK) - 1; switch (Oid & OID_REQUIRED_MASK) { case OID_REQUIRED_MANDATORY: ASSERT (MaskOid < GM_ARRAY_SIZE); if (MaskOid == GM_RECEIVE_NO_BUFFER) { // // This one is read off the card, update unless our // counter is more (which indicates an imminent // overflow interrupt, so we don't update). // USHORT MissedPacket; SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &MissedPacket); if ((Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff) < MissedPacket) { Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] = (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) + MissedPacket; } } GenericUlong = Adapter->GeneralMandatory[MaskOid]; break; case OID_REQUIRED_OPTIONAL: ASSERT (MaskOid < GO_ARRAY_SIZE); if (MaskOid == GO_RECEIVE_CRC) { // // This one is read off the card, update unless our // counter is more (which indicates an imminent // overflow interrupt, so we don't update). // USHORT CrcError; SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &CrcError); if ((Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff) < CrcError) { Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] = (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) + CrcError; } } if ((MaskOid / 2) < GO_COUNT_ARRAY_SIZE) { if (MaskOid & 0x01) { // Frame count GenericUlong = Adapter->GeneralOptionalFrameCount[MaskOid / 2]; } else { // Byte count SourceBuffer = &Adapter->GeneralOptionalByteCount[MaskOid / 2]; SourceBufferLength = sizeof(LARGE_INTEGER); } } else { GenericUlong = Adapter->GeneralOptional[MaskOid - GO_ARRAY_START]; } break; default: ASSERT(FALSE); break; } break; case OID_TYPE_802_3_OPERATIONAL: switch (Oid) { case OID_802_3_PERMANENT_ADDRESS: SourceBuffer = Adapter->PermanentNetworkAddress; SourceBufferLength = 6; break; case OID_802_3_CURRENT_ADDRESS: SourceBuffer = Adapter->CurrentNetworkAddress; SourceBufferLength = 6; break; case OID_802_3_MAXIMUM_LIST_SIZE: GenericUlong = SONIC_CAM_ENTRIES - 1; break; default: ASSERT(FALSE); break; } break; case OID_TYPE_802_3_STATISTICS: MaskOid = (Oid & OID_INDEX_MASK) - 1; switch (Oid & OID_REQUIRED_MASK) { case OID_REQUIRED_MANDATORY: ASSERT (MaskOid < MM_ARRAY_SIZE); if (MaskOid == MM_RECEIVE_ERROR_ALIGNMENT) { // // This one is read off the card, update unless our // counter is more (which indicates an imminent // overflow interrupt, so we don't update). // USHORT FaError; SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError); if ((Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff) < FaError) { Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] = (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) + FaError; } } GenericUlong = Adapter->MediaMandatory[MaskOid]; break; case OID_REQUIRED_OPTIONAL: ASSERT (MaskOid < MO_ARRAY_SIZE); GenericUlong = Adapter->MediaOptional[MaskOid]; break; default: ASSERT(FALSE); break; } break; } if (SourceBufferLength > InformationBufferLength) { *BytesNeeded = SourceBufferLength; return NDIS_STATUS_INVALID_LENGTH; } SONIC_MOVE_MEMORY (InformationBuffer, SourceBuffer, SourceBufferLength); *BytesWritten = SourceBufferLength; return NDIS_STATUS_SUCCESS; } STATIC NDIS_STATUS SonicSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ) /*++ Routine Description: SonicQueryInformation handles a set operation for a single OID. Arguments: MiniportAdapterContext - Context registered with the wrapper, really a pointer to the adapter. 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 InformationBuffer 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 --*/ { PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); NDIS_STATUS Status; ULONG PacketFilter; // // Now check for the most common OIDs // 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. // return NDIS_STATUS_INVALID_DATA; } #if DBG if (SonicDbg) { DbgPrint("Processing Change Multicast List request\n"); } #endif // // Now make the change. // Status = ChangeAddressDispatch( Adapter, InformationBufferLength / ETH_LENGTH_OF_ADDRESS, InformationBuffer ); *BytesRead = InformationBufferLength; return Status; break; case OID_GEN_CURRENT_PACKET_FILTER: if (InformationBufferLength != 4) { *BytesNeeded = 4; return NDIS_STATUS_INVALID_LENGTH; } #if DBG if (SonicDbg) { DbgPrint("Processing Change Packet Filter request\n"); } #endif // // Now call the filter package to set the packet filter. // SONIC_MOVE_MEMORY ((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 )) { *BytesRead = 4; *BytesNeeded = 0; return NDIS_STATUS_NOT_SUPPORTED; } Status = ChangeClassDispatch( Adapter, PacketFilter ); *BytesRead = 4; return Status; break; case OID_GEN_CURRENT_LOOKAHEAD: // // No need to record requested lookahead length since we // always indicate the whole packet. // *BytesRead = 4; return NDIS_STATUS_SUCCESS; break; default: return NDIS_STATUS_INVALID_OID; break; } } STATIC NDIS_STATUS ChangeClassDispatch( IN PSONIC_ADAPTER Adapter, IN UINT NewFilterClasses ) /*++ Routine Description: Modifies the Receive Control Register and Cam Enable registers, then re-loads the CAM if necessary. Arguments: Adapter - The adapter. NewFilterClasses - New set of filters. Return Value: NDIS_STATUS_PENDING - if the CAM was reloaded. NDIS_STATUS_SUCCESS - otherwise. --*/ { // // The new value for the RCR. // USHORT NewReceiveControl = SONIC_RCR_DEFAULT_VALUE; // // First take care of the Receive Control Register. // if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) { NewReceiveControl |= SONIC_RCR_PROMISCUOUS_PHYSICAL | SONIC_RCR_ACCEPT_BROADCAST | SONIC_RCR_ACCEPT_ALL_MULTICAST; } else { if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) { NewReceiveControl |= SONIC_RCR_ACCEPT_ALL_MULTICAST; } if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) { NewReceiveControl |= SONIC_RCR_ACCEPT_BROADCAST; } } Adapter->ReceiveControlRegister = NewReceiveControl; SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL, Adapter->ReceiveControlRegister ); if (CAM_DIRECTED_SIGNIFICANT(NewFilterClasses)) { Adapter->CamDescriptorArea->CamEnable |= 1; } else { Adapter->CamDescriptorArea->CamEnable &= ~1; } if (CAM_MULTICAST_SIGNIFICANT(NewFilterClasses)) { Adapter->CamDescriptorArea->CamEnable |= Adapter->MulticastCamEnableBits; } else { Adapter->CamDescriptorArea->CamEnable &= 1; } // // This will cause a LOAD_CAM interrupt when it is done. // SonicStartCamReload(Adapter); Adapter->CurrentPacketFilter = NewFilterClasses; return NDIS_STATUS_PENDING; } STATIC NDIS_STATUS ChangeAddressDispatch( IN PSONIC_ADAPTER Adapter, IN UINT AddressCount, IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] ) /*++ Routine Description: Modifies the Receive Control Register and Cam Enable registers, then re-loads the CAM if necessary. Arguments: Adapter - The adapter. AddressCount - The number of addresses in Addresses Addresses - The new multicast address list. Return Value: NDIS_STATUS_PENDING - if the CAM was reloaded. NDIS_STATUS_SUCCESS - otherwise. --*/ { ULONG EnableBit; NDIS_STATUS Status; UINT i; // // The first entry in the CAM is for our address. // Adapter->MulticastCamEnableBits = 1; EnableBit = 1; // // Loop through, copying the addresses into the CAM. // for (i=0; iMulticastCamEnableBits |= EnableBit; SONIC_LOAD_CAM_FRAGMENT( &Adapter->CamDescriptorArea->CamFragments[i+1], i+1, Addresses[i] ); } Adapter->CamDescriptorAreaSize = AddressCount + 1; // // Now see if we have to worry about re-loading the // CAM also. // if (CAM_MULTICAST_SIGNIFICANT(Adapter->CurrentPacketFilter)) { Adapter->CamDescriptorArea->CamEnable = Adapter->MulticastCamEnableBits; // // This will cause a LOAD_CAM interrupt when it is done. // SonicStartCamReload(Adapter); #if DBG if (SonicDbg) { DbgPrint("Processing Address request pended\n"); } #endif Status = NDIS_STATUS_PENDING; } else { #if DBG if (SonicDbg) { DbgPrint("Processing Address request succeeded\n"); } #endif Status = NDIS_STATUS_SUCCESS; } return Status; }