/*++ Copyright (c) 1999 Microsoft Corporation Module Name: mp_req.c Abstract: This module contains miniport OID related handlers Revision History: Who When What -------- -------- ---------------------------------------------- DChen 11-01-99 created Notes: --*/ #include "precomp.h" #include "e100_wmi.h" #if DBG #define _FILENUMBER 'QERM' #endif #if OFFLOAD // // This miniport only supports one Encapsultion type: IEEE_802_3_Encapsulation // one task version: NDIS_TASK_OFFLOAD_VERSION. Modify the code below OID_TCP_ // TASK_OFFLOAD in query and setting information functions to make it support // more than one encapsulation type and task version // // Define the task offload the miniport currently supports. // This miniport only supports two kinds of offload tasks: // TCP/IP checksum offload and Segmentation large TCP packet offload // Later if it can supports more tasks, just redefine this task array // NDIS_TASK_OFFLOAD OffloadTasks[] = { { NDIS_TASK_OFFLOAD_VERSION, sizeof(NDIS_TASK_OFFLOAD), TcpIpChecksumNdisTask, 0, sizeof(NDIS_TASK_TCP_IP_CHECKSUM) }, { NDIS_TASK_OFFLOAD_VERSION, sizeof(NDIS_TASK_OFFLOAD), TcpLargeSendNdisTask, 0, sizeof(NDIS_TASK_TCP_LARGE_SEND) } }; // // Get the number of offload tasks this miniport supports // ULONG OffloadTasksCount = sizeof(OffloadTasks) / sizeof(OffloadTasks[0]); // // Specify TCP/IP checksum offload task, the miniport can only supports, for now, // TCP checksum and IP checksum on the sending side, also it supports TCP and IP // options // NDIS_TASK_TCP_IP_CHECKSUM TcpIpChecksumTask = { {1, 1, 1, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; // // Specify Large Send offload task, the miniport supports TCP options and IP options, // and the minimum segment count the protocol can offload is 1. At this point, we // cannot specify the maximum offload size(here is 0), because it depends on the size // of shared memory and the number of TCB used by the driver. // NDIS_TASK_TCP_LARGE_SEND TcpLargeSendTask = { 0, //Currently the version is set to 0, later it may change 0, 1, TRUE, TRUE }; #endif // OFFLOAD ULONG VendorDriverVersion = NIC_VENDOR_DRIVER_VERSION; NDIS_OID NICSupportedOids[] = { 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_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_VENDOR_DRIVER_VERSION, OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_CURRENT_LOOKAHEAD, OID_GEN_DRIVER_VERSION, OID_GEN_MAXIMUM_TOTAL_SIZE, OID_GEN_MAC_OPTIONS, OID_GEN_MEDIA_CONNECT_STATUS, OID_GEN_MAXIMUM_SEND_PACKETS, OID_GEN_SUPPORTED_GUIDS, 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_GEN_PHYSICAL_MEDIUM, OID_GEN_NETWORK_LAYER_ADDRESSES, 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, #if OFFLOAD OID_TCP_TASK_OFFLOAD, #endif /* powermanagement */ OID_PNP_CAPABILITIES, OID_PNP_SET_POWER, OID_PNP_QUERY_POWER, OID_PNP_ADD_WAKE_UP_PATTERN, OID_PNP_REMOVE_WAKE_UP_PATTERN, OID_PNP_ENABLE_WAKE_UP, /* custom oid WMI support */ OID_CUSTOM_DRIVER_SET, OID_CUSTOM_DRIVER_QUERY, OID_CUSTOM_ARRAY, OID_CUSTOM_STRING }; // // WMI support // check out the e100.mof file for examples of how the below // maps into a .mof file for external advertisement of GUIDs // #define NIC_NUM_CUSTOM_GUIDS 4 static const NDIS_GUID NICGuidList[NIC_NUM_CUSTOM_GUIDS] = { { // {F4A80276-23B7-11d1-9ED9-00A0C9010057} example of a uint set E100BExampleSetUINT_OIDGuid, OID_CUSTOM_DRIVER_SET, sizeof(ULONG), // Not setting fNDIS_GUID_ALLOW_WRITE flag means that we don't allow // users without administrator privilege to set this value, but we do // allow any user to query this value (fNDIS_GUID_TO_OID | fNDIS_GUID_ALLOW_READ) }, { // {F4A80277-23B7-11d1-9ED9-00A0C9010057} example of a uint query E100BExampleQueryUINT_OIDGuid, OID_CUSTOM_DRIVER_QUERY, sizeof(ULONG), // setting fNDIS_GUID_ALLOW_READ flag means that we allow any // user to query this value. (fNDIS_GUID_TO_OID | fNDIS_GUID_ALLOW_READ) }, { // {F4A80278-23B7-11d1-9ED9-00A0C9010057} example of an array query E100BExampleQueryArrayOIDGuid, OID_CUSTOM_ARRAY, sizeof(UCHAR), // size is size of each element in the array // setting fNDIS_GUID_ALLOW_READ flag means that we allow any // user to query this value. (fNDIS_GUID_TO_OID|fNDIS_GUID_ARRAY | fNDIS_GUID_ALLOW_READ) }, { // {F4A80279-23B7-11d1-9ED9-00A0C9010057} example of a string query E100BExampleQueryStringOIDGuid, OID_CUSTOM_STRING, (ULONG) -1, // size is -1 for ANSI or NDIS_STRING string types // setting fNDIS_GUID_ALLOW_READ flag means that we allow any // user to query this value. (fNDIS_GUID_TO_OID|fNDIS_GUID_ANSI_STRING | fNDIS_GUID_ALLOW_READ) } }; /** Local Prototypes **/ VOID MPSetPower( PMP_ADAPTER Adapter , NDIS_DEVICE_POWER_STATE PowerState ); VOID MPFillPoMgmtCaps ( IN PMP_ADAPTER Adapter, IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities, IN OUT PNDIS_STATUS pStatus, IN OUT PULONG pulInfoLen ); NDIS_STATUS MPAddWakeUpPattern( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN UINT InformationBufferLength ); NDIS_STATUS MPRemoveWakeUpPattern( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN UINT InformationBufferLength ); BOOLEAN MPAreTwoPatternsEqual ( PNDIS_PM_PACKET_PATTERN pNdisPattern1, PNDIS_PM_PACKET_PATTERN pNdisPattern2 ); NDIS_STATUS MPSetNetworkAddress( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, IN PULONG BytesRead, IN PULONG BytesNeeded ); // // Macros used to walk a doubly linked list. Only macros that are not defined in ndis.h // The List Next macro will work on Single and Doubly linked list as Flink is a common // field name in both // /* PLIST_ENTRY ListNext ( IN PLIST_ENTRY ); PSINGLE_LIST_ENTRY ListNext ( IN PSINGLE_LIST_ENTRY ); */ #define ListNext(_pL) (_pL)->Flink /* PLIST_ENTRY ListPrev ( IN LIST_ENTRY * ); */ #define ListPrev(_pL) (_pL)->Blink __inline BOOLEAN MPIsPoMgmtSupported( IN PMP_ADAPTER pAdapter ) { if (pAdapter->RevsionID >= E100_82559_A_STEP && pAdapter->RevsionID <= E100_82559_C_STEP ) { return TRUE; } else { return FALSE; } } NDIS_STATUS MPQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: MiniportQueryInformation handler Arguments: MiniportAdapterContext Pointer to the adapter structure Oid Oid for this query InformationBuffer Buffer for information InformationBufferLength Size of this buffer BytesWritten Specifies how much info is written BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_NOT_SUPPORTED NDIS_STATUS_BUFFER_TOO_SHORT --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PMP_ADAPTER Adapter; NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; NDIS_MEDIUM Medium = NIC_MEDIA_TYPE; NDIS_PHYSICAL_MEDIUM PhysMedium = NdisPhysicalMediumUnspecified; UCHAR VendorDesc[] = NIC_VENDOR_DESC; NDIS_PNP_CAPABILITIES Power_Management_Capabilities; ULONG ulInfo = 0; ULONG64 ul64Info = 0; USHORT usInfo = 0; UCHAR arrInfo[ETH_LENGTH_OF_ADDRESS]; PVOID pInfo = (PVOID) &ulInfo; ULONG ulInfoLen = sizeof(ulInfo); ULONG ulBytesAvailable = ulInfoLen; PNDIS_TASK_OFFLOAD_HEADER pNdisTaskOffloadHdr; #if OFFLOAD PNDIS_TASK_OFFLOAD pTaskOffload; PNDIS_TASK_TCP_IP_CHECKSUM pTcpIpChecksumTask; PNDIS_TASK_TCP_LARGE_SEND pTcpLargeSendTask; ULONG ulHeadersLen; ULONG ulMaxOffloadSize; UINT i; #endif DBGPRINT(MP_TRACE, ("====> MPQueryInformation\n")); Adapter = (PMP_ADAPTER) MiniportAdapterContext; // // Initialize the result // *BytesWritten = 0; *BytesNeeded = 0; // // Process different type of requests // switch(Oid) { case OID_GEN_SUPPORTED_LIST: pInfo = (PVOID) NICSupportedOids; ulBytesAvailable = ulInfoLen = sizeof(NICSupportedOids); break; case OID_GEN_HARDWARE_STATUS: pInfo = (PVOID) &HardwareStatus; ulBytesAvailable = ulInfoLen = sizeof(NDIS_HARDWARE_STATUS); break; case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: pInfo = (PVOID) &Medium; ulBytesAvailable = ulInfoLen = sizeof(NDIS_MEDIUM); break; case OID_GEN_PHYSICAL_MEDIUM: pInfo = (PVOID) &PhysMedium; ulBytesAvailable = ulInfoLen = sizeof(NDIS_PHYSICAL_MEDIUM); break; case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_MAXIMUM_LOOKAHEAD: if (Adapter->ulLookAhead == 0) { Adapter->ulLookAhead = NIC_MAX_PACKET_SIZE - NIC_HEADER_SIZE; } ulInfo = Adapter->ulLookAhead; break; case OID_GEN_MAXIMUM_FRAME_SIZE: ulInfo = NIC_MAX_PACKET_SIZE - NIC_HEADER_SIZE; break; case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: ulInfo = (ULONG) NIC_MAX_PACKET_SIZE; break; case OID_GEN_MAC_OPTIONS: // Notes: // The protocol driver is free to access indicated data by any means. // Some fast-copy functions have trouble accessing on-board device // memory. NIC drivers that indicate data out of mapped device memory // should never set this flag. If a NIC driver does set this flag, it // relaxes the restriction on fast-copy functions. // This miniport indicates receive with NdisMIndicateReceivePacket // function. It has no MiniportTransferData function. Such a driver // should set this flag. ulInfo = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_NO_LOOPBACK; break; case OID_GEN_LINK_SPEED: case OID_GEN_MEDIA_CONNECT_STATUS: if (InformationBufferLength < ulInfoLen) { break; } NdisAcquireSpinLock(&Adapter->Lock); if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION)) { ASSERT(!Adapter->bQueryPending); Adapter->bQueryPending = TRUE; Adapter->QueryRequest.Oid = Oid; Adapter->QueryRequest.InformationBuffer = InformationBuffer; Adapter->QueryRequest.InformationBufferLength = InformationBufferLength; Adapter->QueryRequest.BytesWritten = BytesWritten; Adapter->QueryRequest.BytesNeeded = BytesNeeded; NdisReleaseSpinLock(&Adapter->Lock); DBGPRINT(MP_WARN, ("MPQueryInformation: OID 0x%08x is pended\n", Oid)); Status = NDIS_STATUS_PENDING; break; } else { NdisReleaseSpinLock(&Adapter->Lock); if (Oid == OID_GEN_LINK_SPEED) { ulInfo = Adapter->usLinkSpeed * 10000; } else // OID_GEN_MEDIA_CONNECT_STATUS { NdisAcquireSpinLock(&Adapter->Lock); ulInfo = NICGetMediaState(Adapter); NdisReleaseSpinLock(&Adapter->Lock); } } break; case OID_GEN_TRANSMIT_BUFFER_SPACE: ulInfo = NIC_MAX_PACKET_SIZE * Adapter->NumTcb; break; case OID_GEN_RECEIVE_BUFFER_SPACE: ulInfo = NIC_MAX_PACKET_SIZE * Adapter->CurrNumRfd; break; case OID_GEN_VENDOR_ID: NdisMoveMemory(&ulInfo, Adapter->PermanentAddress, 3); break; case OID_GEN_VENDOR_DESCRIPTION: pInfo = VendorDesc; ulBytesAvailable = ulInfoLen = sizeof(VendorDesc); break; case OID_GEN_VENDOR_DRIVER_VERSION: ulInfo = VendorDriverVersion; break; case OID_GEN_DRIVER_VERSION: usInfo = (USHORT) NIC_DRIVER_VERSION; pInfo = (PVOID) &usInfo; ulBytesAvailable = ulInfoLen = sizeof(USHORT); break; // WMI support case OID_GEN_SUPPORTED_GUIDS: pInfo = (PUCHAR) &NICGuidList; ulBytesAvailable = ulInfoLen = sizeof(NICGuidList); break; // Task Offload case OID_TCP_TASK_OFFLOAD: DBGPRINT(MP_WARN, ("Query Offloading.\n")); // // If the miniport supports LBFO, it can't support task offload // #if LBFO return NDIS_STATUS_NOT_SUPPORTED; #endif #if OFFLOAD // // Because this miniport uses shared memory to do the offload tasks, if // allocation of memory is failed, then the miniport can't do the offloading // if (Adapter->OffloadEnable == FALSE) { Status = NDIS_STATUS_NOT_SUPPORTED; break; } // // Calculate the information buffer length we need to write the offload // capabilities // ulInfoLen = sizeof(NDIS_TASK_OFFLOAD_HEADER) + FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) + FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + sizeof(NDIS_TASK_TCP_LARGE_SEND); if (ulInfoLen > InformationBufferLength) { *BytesNeeded = ulInfoLen; Status = NDIS_STATUS_BUFFER_TOO_SHORT; break; } // // check version and Encapsulation Type // pNdisTaskOffloadHdr = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer; // // Assume the miniport only supports IEEE_802_3_Encapsulation type // if (pNdisTaskOffloadHdr->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) { DBGPRINT(MP_WARN, ("Encapsulation type is not supported.\n")); pNdisTaskOffloadHdr->OffsetFirstTask = 0; Status = NDIS_STATUS_NOT_SUPPORTED; break; } // // Assume the miniport only supports task version of NDIS_TASK_OFFLOAD_VERSION // if (pNdisTaskOffloadHdr->Size != sizeof(NDIS_TASK_OFFLOAD_HEADER) || pNdisTaskOffloadHdr->Version != NDIS_TASK_OFFLOAD_VERSION) { DBGPRINT(MP_WARN, ("Size or Version is not correct.\n")); pNdisTaskOffloadHdr->OffsetFirstTask = 0; Status = NDIS_STATUS_NOT_SUPPORTED; break; } // // If no capabilities supported, OffsetFirstTask should be set to 0 // Currently we support TCP/IP checksum and TCP large send, so set // OffsetFirstTask to indicate the offset of the first offload task // pNdisTaskOffloadHdr->OffsetFirstTask = pNdisTaskOffloadHdr->Size; // // Fill TCP/IP checksum and TCP large send task offload structures // pTaskOffload = (PNDIS_TASK_OFFLOAD)((PUCHAR)(InformationBuffer) + pNdisTaskOffloadHdr->Size); // // Fill all the offload capabilities the miniport supports. // for (i = 0; i < OffloadTasksCount; i++) { pTaskOffload->Size = OffloadTasks[i].Size; pTaskOffload->Version = OffloadTasks[i].Version; pTaskOffload->Task = OffloadTasks[i].Task; pTaskOffload->TaskBufferLength = OffloadTasks[i].TaskBufferLength; // // Not the last task // if (i != OffloadTasksCount - 1) { pTaskOffload->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + pTaskOffload->TaskBufferLength; } else { pTaskOffload->OffsetNextTask = 0; } switch (OffloadTasks[i].Task) { // // TCP/IP checksum task offload // case TcpIpChecksumNdisTask: pTcpIpChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM) pTaskOffload->TaskBuffer; NdisMoveMemory(pTcpIpChecksumTask, &TcpIpChecksumTask, sizeof(TcpIpChecksumTask)); break; // // TCP large send task offload // case TcpLargeSendNdisTask: pTcpLargeSendTask = (PNDIS_TASK_TCP_LARGE_SEND) pTaskOffload->TaskBuffer; NdisMoveMemory(pTcpLargeSendTask, &TcpLargeSendTask, sizeof(TcpLargeSendTask)); ulHeadersLen = TCP_IP_MAX_HEADER_SIZE + pNdisTaskOffloadHdr->EncapsulationFormat.EncapsulationHeaderSize; ulMaxOffloadSize = (NIC_MAX_PACKET_SIZE - ulHeadersLen) * (ULONG)(Adapter->NumTcb); // // The maximum offload size depends on the size of allocated shared memory // and the number of TCB available, because this driver doesn't use a queue // to store the small packets splited from the large packet, so the number // of small packets must be less than or equal to the number of TCB the // miniport has, so all the small packets can be sent out at one time. // pTcpLargeSendTask->MaxOffLoadSize = (ulMaxOffloadSize > Adapter->OffloadSharedMemSize) ? Adapter->OffloadSharedMemSize: ulMaxOffloadSize; // // Store the maximum offload size // TcpLargeSendTask.MaxOffLoadSize = pTcpLargeSendTask->MaxOffLoadSize; break; } // // Points to the next task offload // if (i != OffloadTasksCount) { pTaskOffload = (PNDIS_TASK_OFFLOAD) ((PUCHAR)pTaskOffload + pTaskOffload->OffsetNextTask); } } // // So far, everything is setup, so return to the caller // *BytesWritten = ulInfoLen; *BytesNeeded = 0; DBGPRINT (MP_WARN, ("Offloading is set.\n")); return NDIS_STATUS_SUCCESS; #endif //OFFLOAD // neither LBFO nor OFFLOAD return NDIS_STATUS_NOT_SUPPORTED; case OID_802_3_PERMANENT_ADDRESS: pInfo = Adapter->PermanentAddress; ulBytesAvailable = ulInfoLen = ETH_LENGTH_OF_ADDRESS; break; case OID_802_3_CURRENT_ADDRESS: pInfo = Adapter->CurrentAddress; ulBytesAvailable = ulInfoLen = ETH_LENGTH_OF_ADDRESS; break; case OID_802_3_MAXIMUM_LIST_SIZE: ulInfo = NIC_MAX_MCAST_LIST; break; case OID_GEN_MAXIMUM_SEND_PACKETS: ulInfo = NIC_MAX_SEND_PACKETS; break; case OID_PNP_CAPABILITIES: MPFillPoMgmtCaps (Adapter, &Power_Management_Capabilities, &Status, &ulInfoLen); if (Status == NDIS_STATUS_SUCCESS) { pInfo = (PVOID) &Power_Management_Capabilities; } else { pInfo = NULL; } break; case OID_PNP_QUERY_POWER: // Status is pre-set in this routine to Success Status = NDIS_STATUS_SUCCESS; break; // WMI support case OID_CUSTOM_DRIVER_QUERY: // this is the uint case DBGPRINT(MP_INFO,("CUSTOM_DRIVER_QUERY got a QUERY\n")); ulInfo = ++Adapter->CustomDriverSet; break; case OID_CUSTOM_DRIVER_SET: DBGPRINT(MP_INFO,("CUSTOM_DRIVER_SET got a QUERY\n")); ulInfo = Adapter->CustomDriverSet; break; // this is the array case case OID_CUSTOM_ARRAY: DBGPRINT(MP_INFO,("CUSTOM_ARRAY got a QUERY\n")); NdisMoveMemory(&ulInfo, Adapter->PermanentAddress, 4); break; // this is the string case case OID_CUSTOM_STRING: DBGPRINT(MP_INFO, ("CUSTOM_STRING got a QUERY\n")); pInfo = (PVOID) VendorDesc; ulBytesAvailable = ulInfoLen = sizeof(VendorDesc); break; case OID_GEN_XMIT_OK: case OID_GEN_RCV_OK: case OID_GEN_XMIT_ERROR: case OID_GEN_RCV_ERROR: case OID_GEN_RCV_NO_BUFFER: case OID_GEN_RCV_CRC_ERROR: case OID_GEN_TRANSMIT_QUEUE_LENGTH: 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_MAX_COLLISIONS: case OID_802_3_RCV_OVERRUN: case OID_802_3_XMIT_UNDERRUN: case OID_802_3_XMIT_HEARTBEAT_FAILURE: case OID_802_3_XMIT_TIMES_CRS_LOST: case OID_802_3_XMIT_LATE_COLLISIONS: Status = NICGetStatsCounters(Adapter, Oid, &ul64Info); ulBytesAvailable = ulInfoLen = sizeof(ul64Info); if (Status == NDIS_STATUS_SUCCESS) { if (InformationBufferLength < sizeof(ULONG)) { Status = NDIS_STATUS_BUFFER_TOO_SHORT; *BytesNeeded = ulBytesAvailable; break; } ulInfoLen = MIN(InformationBufferLength, ulBytesAvailable); pInfo = &ul64Info; } break; default: Status = NDIS_STATUS_NOT_SUPPORTED; break; } if (Status == NDIS_STATUS_SUCCESS) { *BytesNeeded = ulBytesAvailable; if (ulInfoLen <= InformationBufferLength) { // // Copy result into InformationBuffer // *BytesWritten = ulInfoLen; if (ulInfoLen) { NdisMoveMemory(InformationBuffer, pInfo, ulInfoLen); } } else { // // too short // *BytesNeeded = ulInfoLen; Status = NDIS_STATUS_BUFFER_TOO_SHORT; } } DBGPRINT(MP_TRACE, ("<==== MPQueryInformation, OID=0x%08x, Status=%x\n", Oid, Status)); return(Status); } NDIS_STATUS NICGetStatsCounters( IN PMP_ADAPTER Adapter, IN NDIS_OID Oid, OUT PULONG64 pCounter ) /*++ Routine Description: Get the value for a statistics OID Arguments: Adapter Pointer to our adapter Oid Self-explanatory pCounter Pointer to receive the value Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_NOT_SUPPORTED --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; DBGPRINT(MP_TRACE, ("--> NICGetStatsCounters\n")); *pCounter = 0; DumpStatsCounters(Adapter); switch(Oid) { case OID_GEN_XMIT_OK: *pCounter = Adapter->GoodTransmits; break; case OID_GEN_RCV_OK: *pCounter = Adapter->GoodReceives; break; case OID_GEN_XMIT_ERROR: *pCounter = Adapter->TxAbortExcessCollisions + Adapter->TxDmaUnderrun + Adapter->TxLostCRS + Adapter->TxLateCollisions; break; case OID_GEN_RCV_ERROR: *pCounter = Adapter->RcvCrcErrors + Adapter->RcvAlignmentErrors + Adapter->RcvResourceErrors + Adapter->RcvDmaOverrunErrors + Adapter->RcvRuntErrors; break; case OID_GEN_RCV_NO_BUFFER: *pCounter = Adapter->RcvResourceErrors; break; case OID_GEN_RCV_CRC_ERROR: *pCounter = Adapter->RcvCrcErrors; break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: *pCounter = Adapter->nWaitSend; break; case OID_802_3_RCV_ERROR_ALIGNMENT: *pCounter = Adapter->RcvAlignmentErrors; break; case OID_802_3_XMIT_ONE_COLLISION: *pCounter = Adapter->OneRetry; break; case OID_802_3_XMIT_MORE_COLLISIONS: *pCounter = Adapter->MoreThanOneRetry; break; case OID_802_3_XMIT_DEFERRED: *pCounter = Adapter->TxOKButDeferred; break; case OID_802_3_XMIT_MAX_COLLISIONS: *pCounter = Adapter->TxAbortExcessCollisions; break; case OID_802_3_RCV_OVERRUN: *pCounter = Adapter->RcvDmaOverrunErrors; break; case OID_802_3_XMIT_UNDERRUN: *pCounter = Adapter->TxDmaUnderrun; break; case OID_802_3_XMIT_HEARTBEAT_FAILURE: *pCounter = Adapter->TxLostCRS; break; case OID_802_3_XMIT_TIMES_CRS_LOST: *pCounter = Adapter->TxLostCRS; break; case OID_802_3_XMIT_LATE_COLLISIONS: *pCounter = Adapter->TxLateCollisions; break; default: Status = NDIS_STATUS_NOT_SUPPORTED; break; } DBGPRINT(MP_TRACE, ("<-- NICGetStatsCounters\n")); return(Status); } NDIS_STATUS NICSetPacketFilter( IN PMP_ADAPTER Adapter, IN ULONG PacketFilter ) /*++ Routine Description: This routine will set up the adapter so that it accepts packets that match the specified packet filter. The only filter bits that can truly be toggled are for broadcast and promiscuous Arguments: Adapter Pointer to our adapter PacketFilter The new packet filter Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_NOT_SUPPORTED --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; UCHAR NewParameterField; UINT i; BOOLEAN bResult; DBGPRINT(MP_TRACE, ("--> NICSetPacketFilter, PacketFilter=%08x\n", PacketFilter)); // // Need to enable or disable broadcast and promiscuous support depending // on the new filter // NewParameterField = CB_557_CFIG_DEFAULT_PARM15; if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST) { NewParameterField &= ~CB_CFIG_BROADCAST_DIS; } else { NewParameterField |= CB_CFIG_BROADCAST_DIS; } if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { NewParameterField |= CB_CFIG_PROMISCUOUS; } else { NewParameterField &= ~CB_CFIG_PROMISCUOUS; } do { if ((Adapter->OldParameterField == NewParameterField ) && !(PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)) { break; } // // Only need to do something to the HW if the filter bits have changed. // Adapter->OldParameterField = NewParameterField; ((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbCommand = CB_CONFIGURE; ((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbStatus = 0; ((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbLinkPointer = DRIVER_NULL; // // First fill in the static (end user can't change) config bytes // Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20; // // Set the Tx underrun retries // Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] = (UCHAR) (CB_557_CFIG_DEFAULT_PARM7 | (Adapter->AiUnderrunRetry << 1)); // // Set the Tx and Rx Fifo limits // Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] = (UCHAR) ((Adapter->AiTxFifo << 4) | Adapter->AiRxFifo); // // set the MWI enable bit if needed // if (Adapter->MWIEnable) Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE; // // Set the Tx and Rx DMA maximum byte count fields. // if ((Adapter->AiRxDmaCount) || (Adapter->AiTxDmaCount)) { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = Adapter->AiRxDmaCount; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = (UCHAR) (Adapter->AiTxDmaCount | CB_CFIG_DMBC_EN); } else { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = CB_557_CFIG_DEFAULT_PARM4; Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = CB_557_CFIG_DEFAULT_PARM5; } // // Setup for MII or 503 operation. The CRS+CDT bit should only be // set when operating in 503 mode. // if (Adapter->PhyAddress == 32) { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII)); Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = (UCHAR) (NewParameterField | CB_CFIG_CRS_OR_CDT); } else { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII); Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = (UCHAR) (NewParameterField & (~CB_CFIG_CRS_OR_CDT)); } // // Setup Full duplex stuff // // // If forced to half duplex // if (Adapter->AiForceDpx == 1) { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = (CB_557_CFIG_DEFAULT_PARM19 & (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE))); } // // If forced to full duplex // else if (Adapter->AiForceDpx == 2) { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX); } // // If auto-duplex // else { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = CB_557_CFIG_DEFAULT_PARM19; } // // if multicast all is being turned on, set the bit // if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = (CB_557_CFIG_DEFAULT_PARM21 | CB_CFIG_MULTICAST_ALL); } else { Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = CB_557_CFIG_DEFAULT_PARM21; } // // Wait for the SCB to clear before we check the CU status. // if (!WaitScb(Adapter)) { Status = NDIS_STATUS_HARD_ERRORS; break; } // // If we have issued any transmits, then the CU will either be active, // or in the suspended state. If the CU is active, then we wait for // it to be suspended. // if (Adapter->TransmitIdle == FALSE) { // // Wait for suspended state // MP_STALL_AND_WAIT((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); if (!bResult) { MP_SET_HARDWARE_ERROR(Adapter); Status = NDIS_STATUS_HARD_ERRORS; break; } // // Check the current status of the receive unit // if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) { // Issue an RU abort. Since an interrupt will be issued, the // RU will be started by the DPC. Status = D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE); if (Status != NDIS_STATUS_SUCCESS) { break; } } if (!WaitScb(Adapter)) { Status = NDIS_STATUS_HARD_ERRORS; break; } // // Restore the transmit software flags. After the multicast // command is issued, the command unit will be idle, because the // EL bit will be set in the multicast commmand block. // Adapter->TransmitIdle = TRUE; Adapter->ResumeWait = TRUE; } // // Display config info // DBGPRINT(MP_INFO, ("Re-Issuing Configure command for filter change\n")); DBGPRINT(MP_INFO, ("Config Block at virt addr "PTR_FORMAT", phys address %x\n", &((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbStatus, Adapter->NonTxCmdBlockPhys)); for (i = 0; i < CB_CFIG_BYTE_COUNT; i++) DBGPRINT(MP_INFO, (" Config byte %x = %.2x\n", i, Adapter->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i])); // // Submit the configure command to the chip, and wait for it to complete. // Adapter->CSRAddress->ScbGeneralPointer = Adapter->NonTxCmdBlockPhys; Status = D100SubmitCommandBlockAndWait(Adapter); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_NOT_ACCEPTED; } } while (FALSE); DBGPRINT_S(Status, ("<-- NICSetPacketFilter, Status=%x\n", Status)); return(Status); } NDIS_STATUS NICSetMulticastList( IN PMP_ADAPTER Adapter ) /*++ Routine Description: This routine will set up the adapter for a specified multicast address list Arguments: Adapter Pointer to our adapter Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_NOT_ACCEPTED --*/ { NDIS_STATUS Status; PUCHAR McAddress; UINT i, j; BOOLEAN bResult; DBGPRINT(MP_TRACE, ("--> NICSetMulticastList\n")); // // Setup the command block for the multicast command. // for (i = 0; i < Adapter->MCAddressCount; i++) { DBGPRINT(MP_INFO, ("MC(%d) = %02x-%02x-%02x-%02x-%02x-%02x\n", i, Adapter->MCList[i][0], Adapter->MCList[i][1], Adapter->MCList[i][2], Adapter->MCList[i][3], Adapter->MCList[i][4], Adapter->MCList[i][5])); McAddress = &Adapter->NonTxCmdBlock->NonTxCb.Multicast.McAddress[i*ETHERNET_ADDRESS_LENGTH]; for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) *(McAddress++) = Adapter->MCList[i][j]; } Adapter->NonTxCmdBlock->NonTxCb.Multicast.McCount = (USHORT)(Adapter->MCAddressCount * ETH_LENGTH_OF_ADDRESS); ((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbStatus = 0; ((PCB_HEADER_STRUC)Adapter->NonTxCmdBlock)->CbCommand = CB_MULTICAST; // // Wait for the SCB to clear before we check the CU status. // if (!WaitScb(Adapter)) { Status = NDIS_STATUS_HARD_ERRORS; MP_EXIT; } // // If we have issued any transmits, then the CU will either be active, or // in the suspended state. If the CU is active, then we wait for it to be // suspended. // if (Adapter->TransmitIdle == FALSE) { // // Wait for suspended state // MP_STALL_AND_WAIT((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); if (!bResult) { MP_SET_HARDWARE_ERROR(Adapter); Status = NDIS_STATUS_HARD_ERRORS; } // // Restore the transmit software flags. After the multicast command is // issued, the command unit will be idle, because the EL bit will be // set in the multicast commmand block. // Adapter->TransmitIdle = TRUE; Adapter->ResumeWait = TRUE; } // // Update the command list pointer. // Adapter->CSRAddress->ScbGeneralPointer = Adapter->NonTxCmdBlockPhys; // // Submit the multicast command to the adapter and wait for it to complete. // Status = D100SubmitCommandBlockAndWait(Adapter); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_NOT_ACCEPTED; } exit: DBGPRINT_S(Status, ("<-- NICSetMulticastList, Status=%x\n", Status)); return(Status); } NDIS_STATUS MPSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ) /*++ Routine Description: This is the handler for an OID set operation. The only operations that really change the configuration of the adapter are set PACKET_FILTER, and SET_MULTICAST. Arguments: MiniportAdapterContext Pointer to the adapter structure Oid Oid for this query InformationBuffer Buffer for information InformationBufferLength Size of this buffer BytesRead Specifies how much info is read BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_INVALID_LENGTH NDIS_STATUS_INVALID_OID NDIS_STATUS_NOT_SUPPORTED NDIS_STATUS_NOT_ACCEPTED --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext; ULONG PacketFilter; NDIS_DEVICE_POWER_STATE NewPowerState; #if OFFLOAD PNDIS_TASK_OFFLOAD_HEADER pNdisTaskOffloadHdr; PNDIS_TASK_OFFLOAD TaskOffload; PNDIS_TASK_OFFLOAD TmpOffload; PNDIS_TASK_TCP_IP_CHECKSUM pTcpIpChecksumTask; PNDIS_TASK_TCP_LARGE_SEND pNdisTaskTcpLargeSend; UINT i; #endif DBGPRINT(MP_TRACE, ("====> MPSetInformation\n")); *BytesRead = 0; *BytesNeeded = 0; switch(Oid) { case OID_802_3_MULTICAST_LIST: // // Verify the length // if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) { return(NDIS_STATUS_INVALID_LENGTH); } // // Save the number of MC list size // Adapter->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS; ASSERT(Adapter->MCAddressCount <= NIC_MAX_MCAST_LIST); // // Save the MC list // NdisMoveMemory( Adapter->MCList, InformationBuffer, InformationBufferLength); *BytesRead = InformationBufferLength; NdisDprAcquireSpinLock(&Adapter->Lock); NdisDprAcquireSpinLock(&Adapter->RcvLock); Status = NICSetMulticastList(Adapter); NdisDprReleaseSpinLock(&Adapter->RcvLock); NdisDprReleaseSpinLock(&Adapter->Lock); break; case OID_GEN_CURRENT_PACKET_FILTER: // // Verify the Length // if (InformationBufferLength != sizeof(ULONG)) { return(NDIS_STATUS_INVALID_LENGTH); } *BytesRead = InformationBufferLength; PacketFilter = *(PULONG)InformationBuffer; // // any bits not supported? // if (PacketFilter & ~NIC_SUPPORTED_FILTERS) { return(NDIS_STATUS_NOT_SUPPORTED); } // // any filtering changes? // if (PacketFilter == Adapter->PacketFilter) { return(NDIS_STATUS_SUCCESS); } NdisDprAcquireSpinLock(&Adapter->Lock); NdisDprAcquireSpinLock(&Adapter->RcvLock); if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION)) { ASSERT(!Adapter->bSetPending); Adapter->bSetPending = TRUE; Adapter->SetRequest.Oid = Oid; Adapter->SetRequest.InformationBuffer = InformationBuffer; Adapter->SetRequest.InformationBufferLength = InformationBufferLength; Adapter->SetRequest.BytesRead = BytesRead; Adapter->SetRequest.BytesNeeded = BytesNeeded; NdisDprReleaseSpinLock(&Adapter->RcvLock); NdisDprReleaseSpinLock(&Adapter->Lock); Status = NDIS_STATUS_PENDING; break; } Status = NICSetPacketFilter( Adapter, PacketFilter); NdisDprReleaseSpinLock(&Adapter->RcvLock); NdisDprReleaseSpinLock(&Adapter->Lock); if (Status == NDIS_STATUS_SUCCESS) { Adapter->PacketFilter = PacketFilter; } break; case OID_GEN_CURRENT_LOOKAHEAD: // // Verify the Length // if (InformationBufferLength != 4) { return(NDIS_STATUS_INVALID_LENGTH); } Adapter->ulLookAhead = *(PULONG)InformationBuffer; *BytesRead = 4; Status = NDIS_STATUS_SUCCESS; break; case OID_PNP_SET_POWER: DBGPRINT(MP_LOUD, ("SET: Power State change, "PTR_FORMAT"!!!\n", InformationBuffer)); if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE )) { return(NDIS_STATUS_INVALID_LENGTH); } NewPowerState = *(PNDIS_DEVICE_POWER_STATE )InformationBuffer; // // Set the power state - Cannot fail this request // MPSetPower(Adapter ,NewPowerState ); *BytesRead = sizeof(NDIS_DEVICE_POWER_STATE ); Status = NDIS_STATUS_SUCCESS; break; case OID_PNP_ADD_WAKE_UP_PATTERN: // // call a function that would program the adapter's wake // up pattern, return success // DBGPRINT(MP_LOUD, ("SET: Add Wake Up Pattern, !!!\n")); if (MPIsPoMgmtSupported(Adapter) ) { Status = MPAddWakeUpPattern(Adapter,InformationBuffer, InformationBufferLength); if (Status == NDIS_STATUS_SUCCESS) { *BytesRead = InformationBufferLength; } } else { Status = NDIS_STATUS_NOT_SUPPORTED; } break; case OID_PNP_REMOVE_WAKE_UP_PATTERN: DBGPRINT(MP_LOUD, ("SET: Got a WakeUpPattern REMOVE Call\n")); // // call a function that would remove the adapter's wake // up pattern, return success // if (MPIsPoMgmtSupported(Adapter) ) { Status = MPRemoveWakeUpPattern(Adapter,InformationBuffer, InformationBufferLength ); if (Status == NDIS_STATUS_SUCCESS) { *BytesRead = InformationBufferLength; } } else { Status = NDIS_STATUS_NOT_SUPPORTED; } break; case OID_PNP_ENABLE_WAKE_UP: DBGPRINT(MP_LOUD, ("SET: Got a EnableWakeUp Call, "PTR_FORMAT"\n",InformationBuffer)); // // call a function that would enable wake up on the adapter // return success // if (MPIsPoMgmtSupported(Adapter) ) { *BytesRead = InformationBufferLength; Status = NDIS_STATUS_SUCCESS; } else { Status = NDIS_STATUS_NOT_SUPPORTED; } break; /* this OID is for showing how to work with driver specific (custom) OIDs and the NDIS 5 WMI interface using GUIDs */ case OID_CUSTOM_DRIVER_SET: DBGPRINT(MP_INFO, ("OID_CUSTOM_DRIVER_SET got a set\n")); if (InformationBufferLength < sizeof(ULONG)) { return(NDIS_STATUS_INVALID_LENGTH); } *BytesRead = 4; Adapter->CustomDriverSet = (ULONG) *(PULONG)(InformationBuffer); break; #if OFFLOAD case OID_TCP_TASK_OFFLOAD: // // Disable all the existing capabilities whenever task offload is updated // DisableOffload(Adapter); if (InformationBufferLength < sizeof(NDIS_TASK_OFFLOAD_HEADER)) { return NDIS_STATUS_INVALID_LENGTH; } *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER); // // Assume miniport only supports IEEE_802_3_Encapsulation // Check to make sure that TCP/IP passed down the correct encapsulation type // pNdisTaskOffloadHdr = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer; if (pNdisTaskOffloadHdr->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) { pNdisTaskOffloadHdr->OffsetFirstTask = 0; return NDIS_STATUS_FAILURE; } // // The length can't hold one task // if (InformationBufferLength < (pNdisTaskOffloadHdr->OffsetFirstTask + sizeof(NDIS_TASK_OFFLOAD))) { DBGPRINT(MP_WARN, ("response of task offload does not have sufficient space even for 1 offload task!!\n")); Status = NDIS_STATUS_INVALID_LENGTH; break; } // // Copy Encapsulation format into adapter, later the miniport may use it // to get Encapsulation header size // NdisMoveMemory(&(Adapter->EncapsulationFormat), &(pNdisTaskOffloadHdr->EncapsulationFormat), sizeof(NDIS_ENCAPSULATION_FORMAT)); ASSERT(pNdisTaskOffloadHdr->EncapsulationFormat.Flags.FixedHeaderSize == 1); // // Check to make sure we support the task offload requested // TaskOffload = (NDIS_TASK_OFFLOAD *) ( (PUCHAR)pNdisTaskOffloadHdr + pNdisTaskOffloadHdr->OffsetFirstTask); TmpOffload = TaskOffload; // // Check the task in the buffer and enable the offload capabilities // while (TmpOffload) { *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer); switch (TmpOffload->Task) { case TcpIpChecksumNdisTask: // // Invalid information buffer length // if (InformationBufferLength < *BytesRead + sizeof(NDIS_TASK_TCP_IP_CHECKSUM)) { break; } // //Check version // for (i = 0; i < OffloadTasksCount; i++) { if (OffloadTasks[i].Task == TmpOffload->Task && OffloadTasks[i].Version == TmpOffload->Version ) { break; } } // // Version is mismatched // if (i == OffloadTasksCount) { return NDIS_STATUS_NOT_SUPPORTED; } // // This miniport support TCP/IP checksum offload only with sending TCP // and IP checksum with TCP/IP options. // check if the fields in NDIS_TASK_TCP_IP_CHECKSUM is set correctly // Adapter->NicTaskOffload.ChecksumOffload = 1; pTcpIpChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM) TmpOffload->TaskBuffer; if (pTcpIpChecksumTask->V4Transmit.TcpChecksum) { // // If miniport doesn't support sending TCP checksum, we can't enable // this capability // if (TcpIpChecksumTask.V4Transmit.TcpChecksum == 0 ) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set Sending TCP offloading.\n")); // // Enable sending TCP checksum // Adapter->NicChecksumOffload.DoXmitTcpChecksum = 1; } // // left for recieve and other IP and UDP checksum offload // if (pTcpIpChecksumTask->V4Transmit.IpChecksum) { // // If the miniport doesn't support sending IP checksum, we can't enable // this capabilities // if (TcpIpChecksumTask.V4Transmit.IpChecksum == 0) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set Sending IP offloading.\n")); // // Enable sending IP checksum // Adapter->NicChecksumOffload.DoXmitIpChecksum = 1; } if (pTcpIpChecksumTask->V4Receive.TcpChecksum) { // // If the miniport doesn't support receiving TCP checksum, we can't // enable this capability // if (TcpIpChecksumTask.V4Receive.TcpChecksum == 0) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set recieve TCP offloading.\n")); // // Enable recieving TCP checksum // Adapter->NicChecksumOffload.DoRcvTcpChecksum = 1; } if (pTcpIpChecksumTask->V4Receive.IpChecksum) { // // If the miniport doesn't support receiving IP checksum, we can't // enable this capability // if (TcpIpChecksumTask.V4Receive.IpChecksum == 0) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set Recieve IP offloading.\n")); // // Enable recieving IP checksum // Adapter->NicChecksumOffload.DoRcvIpChecksum = 1; } if (pTcpIpChecksumTask->V4Transmit.UdpChecksum) { // // If the miniport doesn't support sending UDP checksum, we can't // enable this capability // if (TcpIpChecksumTask.V4Transmit.UdpChecksum == 0) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set Sending UDP offloading.\n")); // // Enable sending UDP checksum // Adapter->NicChecksumOffload.DoXmitUdpChecksum = 1; } if (pTcpIpChecksumTask->V4Receive.UdpChecksum) { // // IF the miniport doesn't support receiving UDP checksum, we can't // enable this capability // if (TcpIpChecksumTask.V4Receive.UdpChecksum == 0) { return NDIS_STATUS_NOT_SUPPORTED; } DBGPRINT (MP_WARN, ("Set recieve UDP offloading.\n")); // // Enable receiving UDP checksum // Adapter->NicChecksumOffload.DoRcvUdpChecksum = 1; } // // check for V6 setting, because this miniport doesn't support any of // checksum offload for V6, so we just return NDIS_STATUS_NOT_SUPPORTED // if the protocol tries to set these capabilities // if (pTcpIpChecksumTask->V6Transmit.TcpChecksum || pTcpIpChecksumTask->V6Transmit.UdpChecksum || pTcpIpChecksumTask->V6Receive.TcpChecksum || pTcpIpChecksumTask->V6Receive.UdpChecksum) { return NDIS_STATUS_NOT_SUPPORTED; } *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM); break; case TcpLargeSendNdisTask: // // Invalid information buffer length // if (InformationBufferLength < *BytesRead + sizeof(NDIS_TASK_TCP_LARGE_SEND)) { break; } // // Check version // for (i = 0; i < OffloadTasksCount; i++) { if (OffloadTasks[i].Task == TmpOffload->Task && OffloadTasks[i].Version == TmpOffload->Version ) { break; } } if (i == OffloadTasksCount) { return NDIS_STATUS_NOT_SUPPORTED; } pNdisTaskTcpLargeSend = (PNDIS_TASK_TCP_LARGE_SEND) TmpOffload->TaskBuffer; // // Check maximum offload size, if the size is greater than the maximum // size of the miniport can handle, return NDIS_STATUS_NOT_SUPPORTED. // if (pNdisTaskTcpLargeSend->MaxOffLoadSize > TcpLargeSendTask.MaxOffLoadSize || pNdisTaskTcpLargeSend->MinSegmentCount < TcpLargeSendTask.MinSegmentCount) { return NDIS_STATUS_NOT_SUPPORTED; } // // If the miniport doesn't support TCP or IP options, but the protocol // is setting such information, return NDIS_STATUS_NOT_SUPPORTED. // if ((pNdisTaskTcpLargeSend->TcpOptions && !TcpLargeSendTask.TcpOptions) || (pNdisTaskTcpLargeSend->IpOptions && !TcpLargeSendTask.IpOptions)) { return NDIS_STATUS_NOT_SUPPORTED; } // // Store the valid setting information into adapter // Adapter->LargeSendInfo.MaxOffLoadSize = pNdisTaskTcpLargeSend->MaxOffLoadSize; Adapter->LargeSendInfo.MinSegmentCount = pNdisTaskTcpLargeSend->MinSegmentCount; Adapter->LargeSendInfo.TcpOptions = pNdisTaskTcpLargeSend->TcpOptions; Adapter->LargeSendInfo.IpOptions = pNdisTaskTcpLargeSend->IpOptions; // // Everythins is OK, enable large send offload capabilities // Adapter->NicTaskOffload.LargeSendOffload = 1; *BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND); break; default: // // Because this miniport doesn't implement IPSec offload, so it doesn't // support IPSec offload. Tasks other then these 3 task are not supported // return NDIS_STATUS_NOT_SUPPORTED; } // // Go on to the next offload structure // if (TmpOffload->OffsetNextTask) { TmpOffload = (PNDIS_TASK_OFFLOAD) ((PUCHAR) TmpOffload + TmpOffload->OffsetNextTask); } else { TmpOffload = NULL; } } // while break; #endif // Used temporarily for Packet Wakeup. DELETE case OID_GEN_NETWORK_LAYER_ADDRESSES: Status = MPSetNetworkAddress(Adapter, InformationBuffer, InformationBufferLength, BytesRead, BytesNeeded); default: Status = NDIS_STATUS_INVALID_OID; break; } if (Status == NDIS_STATUS_SUCCESS) { *BytesRead = InformationBufferLength; } DBGPRINT(MP_TRACE, ("<==== MPSetInformationSet, OID=0x%08x, Status=%x\n", Oid, Status)); return(Status); } VOID MPSetPowerD0( PMP_ADAPTER Adapter ) /*++ Routine Description: This routine is called when the adapter receives a SetPower to D0. Arguments: Adapter Pointer to the adapter structure PowerState NewPowerState Return Value: --*/ { MPSetPowerD0Private (Adapter); Adapter->CurrentPowerState = NdisDeviceStateD0; } VOID MPSetPowerLow( PMP_ADAPTER Adapter , NDIS_DEVICE_POWER_STATE PowerState ) /*++ Routine Description: This routine is called when the adapter receives a SetPower to a PowerState > D0 Arguments: Adapter Pointer to the adapter structure PowerState NewPowerState Return Value: --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; do { Adapter->NextPowerState = PowerState; // // Stop sending packets. Create a new flag and make it part // of the Send Fail Mask // // // Stop hardware from receiving packets - Set the RU to idle // // // Check the current status of the receive unit // if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) { // // Issue an RU abort. Since an interrupt will be issued, the // RU will be started by the DPC. // Status = D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE); } if (Status != NDIS_STATUS_SUCCESS) { break; } // // Wait for outstanding Receive packets // while (Adapter->PoMgmt.OutstandingRecv != 0) { // // Sleep for 2 Ms; // NdisMSleep (2000); } // // Wait for all incoming sends to complete // // // Start Hardware specific part of the transition to low power state // Setting up wake-up patterns, filters, wake-up events etc // NdisMSynchronizeWithInterrupt( &Adapter->Interrupt, MPSetPowerLowPrivate, Adapter); Status = NDIS_STATUS_SUCCESS; } while (FALSE); return; } VOID MPSetPower( PMP_ADAPTER Adapter , NDIS_DEVICE_POWER_STATE PowerState ) /*++ Routine Description: This routine is called when the adapter receives a SetPower request. It redirects the call to an appropriate routine to Set the New PowerState Arguments: Adapter Pointer to the adapter structure PowerState NewPowerState Return Value: --*/ { if (PowerState == NdisDeviceStateD0) { MPSetPowerD0 (Adapter); } else { MPSetPowerLow (Adapter, PowerState); } } VOID MPFillPoMgmtCaps ( IN PMP_ADAPTER pAdapter, IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities, IN OUT PNDIS_STATUS pStatus, IN OUT PULONG pulInfoLen ) /*++ Routine Description: Fills in the Power Managment structure depending the capabilities of the software driver and the card. Currently this is only supported on 82559 Version of the driver Arguments: Adapter Pointer to the adapter structure pPower_Management_Capabilities - Power management struct as defined in the DDK, pStatus Status to be returned by the request, pulInfoLen Length of the pPowerManagmentCapabilites Return Value: Success or failure depending on the type of card --*/ { BOOLEAN bIsPoMgmtSupported; bIsPoMgmtSupported = MPIsPoMgmtSupported(pAdapter); if (bIsPoMgmtSupported == TRUE) { pPower_Management_Capabilities->Flags = NDIS_DEVICE_WAKE_UP_ENABLE ; pPower_Management_Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; pPower_Management_Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3; pPower_Management_Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; *pulInfoLen = sizeof (*pPower_Management_Capabilities); *pStatus = NDIS_STATUS_SUCCESS; } else { NdisZeroMemory (pPower_Management_Capabilities, sizeof(*pPower_Management_Capabilities)); *pStatus = NDIS_STATUS_NOT_SUPPORTED; *pulInfoLen = 0; } } NDIS_STATUS MPAddWakeUpPattern( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN UINT InformationBufferLength ) /*++ Routine Description: This routine will allocate a local memory structure, copy the pattern, insert the pattern into a linked list and return success We are gauranteed that we wll get only one request at a time, so this is implemented without locks. Arguments: Adapter Adapter structure InformationBuffer Wake up Pattern InformationBufferLength Wake Up Pattern Length Return Value: Success - if successful. NDIS_STATUS_FAILURE - if memory allocation fails. --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; PMP_WAKE_PATTERN pWakeUpPattern = NULL; UINT AllocationLength = 0; PNDIS_PM_PACKET_PATTERN pPmPattern = NULL; ULONG Signature = 0; do { pPmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer; // // Calculate the e100 signature // Status = MPCalculateE100PatternForFilter ( (PUCHAR)pPmPattern+ pPmPattern->PatternOffset, pPmPattern->PatternSize, (PUCHAR)pPmPattern +sizeof(NDIS_PM_PACKET_PATTERN), pPmPattern->MaskSize, &Signature ); if ( Status != NDIS_STATUS_SUCCESS) { break; } // // Allocate the memory to hold the WakeUp Pattern // AllocationLength = sizeof (MP_WAKE_PATTERN) + InformationBufferLength; Status = NdisAllocateMemoryWithTag( &pWakeUpPattern, AllocationLength , NIC_TAG ); if (Status != NDIS_STATUS_SUCCESS) { pWakeUpPattern = NULL; break; } // // Initialize pWakeUpPattern // NdisZeroMemory (pWakeUpPattern, AllocationLength); pWakeUpPattern->AllocationSize = AllocationLength; pWakeUpPattern->Signature = Signature; // // Copy the pattern into local memory // NdisMoveMemory (&pWakeUpPattern->Pattern[0],InformationBuffer, InformationBufferLength); // // Insert the pattern into the list // NdisInterlockedInsertHeadList (&pAdapter->PoMgmt.PatternList, &pWakeUpPattern->linkListEntry, &pAdapter->Lock); Status = NDIS_STATUS_SUCCESS; } while (FALSE); return Status; } NDIS_STATUS MPRemoveWakeUpPattern( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN UINT InformationBufferLength ) /*++ Routine Description: This routine will walk the list of wake up pattern and attempt to match the wake up pattern. If it finds a copy , it will remove that WakeUpPattern Arguments: Adapter Adapter structure InformationBuffer Wake up Pattern InformationBufferLength Wake Up Pattern Length Return Value: Success - if successful. NDIS_STATUS_FAILURE - if memory allocation fails. --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; PNDIS_PM_PACKET_PATTERN pReqPattern = (PNDIS_PM_PACKET_PATTERN)InformationBuffer; PLIST_ENTRY pPatternEntry = ListNext(&pAdapter->PoMgmt.PatternList) ; while (pPatternEntry != (&pAdapter->PoMgmt.PatternList)) { BOOLEAN bIsThisThePattern = FALSE; PMP_WAKE_PATTERN pWakeUpPattern = NULL; PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;; // // initialize local variables // pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry); pCurrPattern = (PNDIS_PM_PACKET_PATTERN)&pWakeUpPattern->Pattern[0]; // // increment the iterator // pPatternEntry = ListNext (pPatternEntry); // // Begin Check : Is (pCurrPattern == pReqPattern) // bIsThisThePattern = MPAreTwoPatternsEqual (pReqPattern, pCurrPattern); if (bIsThisThePattern == TRUE) { // // we have a match - remove the entry // RemoveEntryList (&pWakeUpPattern->linkListEntry); // // Free the entry // NdisFreeMemory (pWakeUpPattern, pWakeUpPattern->AllocationSize, 0); Status = NDIS_STATUS_SUCCESS; break; } } return Status; } VOID MPRemoveAllWakeUpPatterns( PMP_ADAPTER pAdapter ) /*++ Routine Description: This routine will walk the list of wake up pattern and free it Arguments: Adapter Adapter structure Return Value: Success - if successful. --*/ { PLIST_ENTRY pPatternEntry = ListNext(&pAdapter->PoMgmt.PatternList) ; while (pPatternEntry != (&pAdapter->PoMgmt.PatternList)) { PMP_WAKE_PATTERN pWakeUpPattern = NULL; // // initialize local variables // pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN,linkListEntry); // // increment the iterator // pPatternEntry = ListNext (pPatternEntry); // // Remove the entry from the list // RemoveEntryList (&pWakeUpPattern->linkListEntry); // // Free the memory // NdisFreeMemory (pWakeUpPattern, pWakeUpPattern->AllocationSize, 0); } } BOOLEAN MPAreTwoPatternsEqual ( PNDIS_PM_PACKET_PATTERN pNdisPattern1, PNDIS_PM_PACKET_PATTERN pNdisPattern2 ) /*++ Routine Description: This routine will compare two wake up patterns to see if they are equal Arguments: pNdisPattern1 - Pattern1 pNdisPattern2 - Pattern 2 Return Value: True - if patterns are equal False - Otherwise --*/ { BOOLEAN bEqual = FALSE; // Local variables used later in the compare section of this function PUCHAR pMask1, pMask2; PUCHAR pPattern1, pPattern2; UINT MaskSize, PatternSize; do { bEqual = (pNdisPattern1->Priority == pNdisPattern2->Priority); if (bEqual == FALSE) { break; } bEqual = (pNdisPattern1->MaskSize == pNdisPattern2->MaskSize); if (bEqual == FALSE) { break; } // // Verify the Mask // MaskSize = pNdisPattern1->MaskSize ; pMask1 = (PUCHAR) pNdisPattern1 + sizeof (NDIS_PM_PACKET_PATTERN); pMask2 = (PUCHAR) pNdisPattern2 + sizeof (NDIS_PM_PACKET_PATTERN); bEqual = NdisEqualMemory (pMask1, pMask2, MaskSize); if (bEqual == FALSE) { break; } // // Verify the Pattern // bEqual = (pNdisPattern1->PatternSize == pNdisPattern2->PatternSize); if (bEqual == FALSE) { break; } PatternSize = pNdisPattern2->PatternSize; pPattern1 = (PUCHAR) pNdisPattern1 + pNdisPattern1->PatternOffset; pPattern2 = (PUCHAR) pNdisPattern2 + pNdisPattern2->PatternOffset; bEqual = NdisEqualMemory (pPattern1, pPattern2, PatternSize ); if (bEqual == FALSE) { break; } } while (FALSE); return bEqual; } NDIS_STATUS MPSetNetworkAddress( IN PMP_ADAPTER pAdapter, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, IN PULONG BytesRead, IN PULONG BytesNeeded ) /*++ Routine Description: Called when the protocol above us wants to let us know about the network address(es) assigned to this interface. . We pick the first IP address given to us. Arguments: pAdapter - Pointer to the ELAN 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: --*/ { NETWORK_ADDRESS_LIST UNALIGNED * pAddrList = NULL; NETWORK_ADDRESS UNALIGNED * pAddr = NULL; NETWORK_ADDRESS_IP UNALIGNED * pIpAddr= NULL; ULONG Size; NDIS_STATUS Status; // // Initialize. // *BytesRead = 0; Status = NDIS_STATUS_SUCCESS; pAddrList = (NETWORK_ADDRESS_LIST UNALIGNED *)InformationBuffer; do { *BytesNeeded = sizeof(*pAddrList) - FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) + sizeof(NETWORK_ADDRESS) - FIELD_OFFSET(NETWORK_ADDRESS, Address); if (InformationBufferLength < *BytesNeeded) { Status = NDIS_STATUS_INVALID_LENGTH; break; } if (pAddrList->AddressType != NDIS_PROTOCOL_ID_TCP_IP) { // Not interesting. break; } if (pAddrList->AddressCount <= 0) { Status = NDIS_STATUS_INVALID_DATA; break; } pAddr = (NETWORK_ADDRESS UNALIGNED *)&pAddrList->Address[0]; if ((pAddr->AddressLength > InformationBufferLength - *BytesNeeded) || (pAddr->AddressLength == 0)) { Status = NDIS_STATUS_INVALID_LENGTH; break; } if (pAddr->AddressType != NDIS_PROTOCOL_ID_TCP_IP) { // Not interesting. break; } if (pAddr->AddressLength < sizeof(NETWORK_ADDRESS_IP)) { Status = NDIS_STATUS_INVALID_LENGTH; break; } pIpAddr = (NETWORK_ADDRESS_IP UNALIGNED *)&pAddr->Address[0]; Size = sizeof(pIpAddr->in_addr); // // Copy the network address in. // NdisMoveMemory(&pAdapter->PoMgmt.IPAddress.u32 , &pIpAddr->in_addr, sizeof(pIpAddr->in_addr)); Status = NDIS_STATUS_SUCCESS; *BytesRead = InformationBufferLength; } while (FALSE); return Status; }