| /* |
| * Copyright (c) 2016, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "pch.hpp" |
| #include "oid.tmh" |
| |
| template<typename _Datum> |
| PAGED NDIS_STATUS RequestQuery( _In_ PNDIS_OID_REQUEST OidRequest, const _Datum & value ); |
| |
| #define VERIFY_NDIS_OBJECT_HEADER(_header, _type, _revision, _size) \ |
| (((_header).Type == _type) && \ |
| ((_header).Revision >= _revision) && \ |
| ((_header).Size >= _size)) |
| |
| #define VERIFY_NDIS_OBJECT_HEADER_PTR(_header, _type, _revision, _size) \ |
| (((_header)->Type == _type) && \ |
| ((_header)->Revision >= _revision) && \ |
| ((_header)->Size >= _size)) |
| |
| #define VERIFY_NDIS_REQUEST_OBJECT_HEADER(_buffer, _type, _revision, _size) \ |
| VERIFY_NDIS_OBJECT_HEADER_PTR(reinterpret_cast<PNDIS_OBJECT_HEADER>(_buffer), _type, _revision, _size) |
| |
| #define ASSIGN_NDIS_OBJECT_HEADER(_header, _type, _revision, _size) \ |
| (_header).Type = _type; \ |
| (_header).Revision = _revision; \ |
| (_header).Size = _size; |
| |
| #define ASSIGN_NDIS_OBJECT_HEADER_PTR(_header, _type, _revision, _size) \ |
| (_header)->Type = _type; \ |
| (_header)->Revision = _revision; \ |
| (_header)->Size = _size; |
| |
| // |
| // List of Supported OIDs. |
| // |
| NDIS_OID NICSupportedOids[] = |
| { |
| // General |
| OID_GEN_CURRENT_LOOKAHEAD, |
| OID_GEN_CURRENT_PACKET_FILTER, |
| OID_GEN_INTERRUPT_MODERATION, |
| OID_GEN_LINK_PARAMETERS, // TODO: Mandatory Set |
| OID_GEN_MAXIMUM_TOTAL_SIZE, |
| OID_GEN_RCV_OK, |
| OID_GEN_RECEIVE_BLOCK_SIZE, |
| OID_GEN_RECEIVE_BUFFER_SPACE, |
| OID_GEN_STATISTICS, |
| OID_GEN_TRANSMIT_BLOCK_SIZE, |
| OID_GEN_TRANSMIT_BUFFER_SPACE, |
| OID_GEN_VENDOR_DRIVER_VERSION, |
| OID_GEN_VENDOR_DESCRIPTION, |
| OID_GEN_VENDOR_ID, |
| OID_GEN_XMIT_OK, |
| OID_GEN_LINK_PARAMETERS, // TODO: Mandatory Set |
| |
| // 802.3 Specific |
| OID_802_3_CURRENT_ADDRESS, |
| OID_802_3_PERMANENT_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, |
| |
| // PnP Stuff |
| OID_PNP_CAPABILITIES, // Optional |
| OID_PNP_QUERY_POWER, // Optional |
| |
| // OpenThread Stuff |
| OID_OT_CAPABILITIES, |
| }; |
| |
| const ULONG SizeOfNICSupportedOids = sizeof(NICSupportedOids); |
| |
| template<typename _Datum> |
| PAGED |
| NDIS_STATUS RequestQuery( _In_ PNDIS_OID_REQUEST OidRequest, const _Datum & value ) |
| { |
| PAGED_CODE(); |
| NT_ASSERT( (OidRequest->RequestType == NdisRequestQueryInformation) || |
| (OidRequest->RequestType == NdisRequestQueryStatistics) ); |
| |
| if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof( _Datum )) |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( _Datum ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; |
| return NDIS_STATUS_INVALID_LENGTH; |
| } |
| else |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( _Datum ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof( _Datum ); |
| _Datum * pData = reinterpret_cast<_Datum *>(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer); |
| *pData = value; |
| return NDIS_STATUS_SUCCESS; |
| } |
| } |
| |
| PAGED |
| NDIS_STATUS RequestQuery32or64( _In_ PNDIS_OID_REQUEST OidRequest, const ULONG64 value ) |
| { |
| PAGED_CODE(); |
| NT_ASSERT( (OidRequest->RequestType == NdisRequestQueryInformation) || |
| (OidRequest->RequestType == NdisRequestQueryStatistics) ); |
| |
| if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof( ULONG64 )) |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( ULONG64 ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof( ULONG64 ); |
| PULONG64 pData = reinterpret_cast<PULONG64>(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer); |
| *pData = value; |
| return NDIS_STATUS_SUCCESS; |
| } |
| else if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof( ULONG )) |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( ULONG ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof( ULONG ); |
| PULONG pData = reinterpret_cast<PULONG>(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer); |
| *pData = (ULONG)value; |
| return NDIS_STATUS_SUCCESS; |
| } |
| else |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( ULONG64 ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; |
| return NDIS_STATUS_INVALID_LENGTH; |
| } |
| } |
| |
| PAGED |
| NDIS_STATUS RequestQueryThreadCapabilities(_In_ PNDIS_OID_REQUEST OidRequest) |
| { |
| PAGED_CODE(); |
| |
| OT_CAPABILITIES caps = { 0 }; |
| ASSIGN_NDIS_OBJECT_HEADER(caps.Header, NDIS_OBJECT_TYPE_DEFAULT, OT_CAPABILITIES_REVISION_1, SIZEOF_OT_CAPABILITIES_REVISION_1); |
| caps.MiniportMode = OT_MP_MODE_THREAD; // Thread Tunnel mode |
| |
| if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < SIZEOF_OT_CAPABILITIES_REVISION_1) |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = SIZEOF_OT_CAPABILITIES_REVISION_1; |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; |
| return NDIS_STATUS_INVALID_LENGTH; |
| } |
| else |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = SIZEOF_OT_CAPABILITIES_REVISION_1; |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = SIZEOF_OT_CAPABILITIES_REVISION_1; |
| memcpy(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, &caps, SIZEOF_OT_CAPABILITIES_REVISION_1); |
| return NDIS_STATUS_SUCCESS; |
| } |
| } |
| |
| PAGED |
| NDIS_STATUS RequestQueryGenStatistics(_In_ PNDIS_OID_REQUEST OidRequest, _In_ POTTMP_ADAPTER_CONTEXT AdapterContext) |
| { |
| PAGED_CODE(); |
| |
| NDIS_STATISTICS_INFO statistics = { 0 }; |
| ASSIGN_NDIS_OBJECT_HEADER(statistics.Header, NDIS_OBJECT_TYPE_DEFAULT, NDIS_SIZEOF_STATISTICS_INFO_REVISION_1, NDIS_STATISTICS_INFO_REVISION_1); |
| |
| statistics.SupportedStatistics = NIC_SUPPORTED_STATISTICS; |
| |
| /* Bytes in */ |
| statistics.ifHCInOctets = AdapterContext->BytesRxDirected + |
| AdapterContext->BytesRxMulticast + |
| AdapterContext->BytesRxBroadcast; |
| |
| statistics.ifHCInUcastOctets = AdapterContext->BytesRxDirected; |
| statistics.ifHCInMulticastOctets = AdapterContext->BytesRxMulticast; |
| statistics.ifHCInBroadcastOctets = AdapterContext->BytesRxBroadcast; |
| |
| /* Packets in */ |
| statistics.ifHCInUcastPkts = AdapterContext->FramesRxDirected; |
| statistics.ifHCInMulticastPkts = AdapterContext->FramesRxMulticast; |
| statistics.ifHCInBroadcastPkts = AdapterContext->FramesRxBroadcast; |
| |
| /* Errors in */ |
| statistics.ifInErrors = AdapterContext->RxCrcErrors + |
| AdapterContext->RxAlignmentErrors + |
| AdapterContext->RxDmaOverrunErrors + |
| AdapterContext->RxRuntErrors; |
| |
| statistics.ifInDiscards = AdapterContext->RxResourceErrors; |
| |
| /* Bytes out */ |
| statistics.ifHCOutOctets = AdapterContext->BytesTxDirected + |
| AdapterContext->BytesTxMulticast + |
| AdapterContext->BytesTxBroadcast; |
| |
| statistics.ifHCOutUcastOctets = AdapterContext->BytesTxDirected; |
| statistics.ifHCOutMulticastOctets = AdapterContext->BytesTxMulticast; |
| statistics.ifHCOutBroadcastOctets = AdapterContext->BytesTxBroadcast; |
| |
| /* Packets out */ |
| statistics.ifHCOutUcastPkts = AdapterContext->FramesTxDirected; |
| statistics.ifHCOutMulticastPkts = AdapterContext->FramesTxMulticast; |
| statistics.ifHCOutBroadcastPkts = AdapterContext->FramesTxBroadcast; |
| |
| /* Errors out */ |
| statistics.ifOutErrors = AdapterContext->TxAbortExcessCollisions + |
| AdapterContext->TxDmaUnderrun + |
| AdapterContext->TxLostCRS + |
| AdapterContext->TxLateCollisions+ |
| AdapterContext->TransmitFailuresOther; |
| |
| statistics.ifOutDiscards = 0ULL; |
| |
| return RequestQuery(OidRequest, statistics); |
| } |
| |
| PAGED |
| _Use_decl_annotations_ |
| NDIS_STATUS |
| MPOidRequest( |
| _In_ NDIS_HANDLE MiniportAdapterContext, |
| _In_ PNDIS_OID_REQUEST OidRequest |
| ) |
| { |
| POTTMP_ADAPTER_CONTEXT AdapterContext = (POTTMP_ADAPTER_CONTEXT)MiniportAdapterContext; |
| NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED; |
| bool fFailExpected = false; |
| |
| LogFuncEntry(DRIVER_DEFAULT); |
| |
| PAGED_CODE(); |
| |
| switch (OidRequest->RequestType) |
| { |
| case NdisRequestSetInformation: |
| switch (OidRequest->DATA.QUERY_INFORMATION.Oid) |
| { |
| case OID_802_3_MULTICAST_LIST: |
| // TODO: Check with Jeffrey how to better handle this |
| status = NDIS_STATUS_MULTICAST_FULL; |
| fFailExpected = true; |
| break; |
| |
| // |
| // Fake it until we make it :) |
| // We can't bind unless we report success for these OIDs |
| // |
| case OID_GEN_CURRENT_PACKET_FILTER: |
| case OID_PM_ADD_WOL_PATTERN: |
| case OID_PM_REMOVE_WOL_PATTERN: |
| case OID_GEN_CURRENT_LOOKAHEAD: |
| // TODO: Implement this |
| status = NDIS_STATUS_SUCCESS; |
| break; |
| |
| // Explicitly not supported |
| case OID_GEN_INTERRUPT_MODERATION: |
| status = NDIS_STATUS_NOT_SUPPORTED; |
| fFailExpected = true; |
| break; |
| |
| // Unknown |
| default: |
| status = NDIS_STATUS_NOT_SUPPORTED; |
| break; |
| } |
| break; |
| case NdisRequestQueryInformation: |
| case NdisRequestQueryStatistics: |
| switch (OidRequest->DATA.QUERY_INFORMATION.Oid) |
| { |
| case OID_GEN_INTERRUPT_MODERATION: |
| { |
| static const NDIS_INTERRUPT_MODERATION_PARAMETERS nimp = { |
| { NDIS_OBJECT_TYPE_DEFAULT, NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1, NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1 }, |
| 0, |
| NdisInterruptModerationNotSupported }; |
| status = RequestQuery( OidRequest, nimp ); |
| break; |
| } |
| |
| case OID_GEN_RCV_OK: |
| status = RequestQuery32or64( OidRequest, AdapterContext->FramesRxBroadcast |
| + AdapterContext->FramesRxMulticast |
| + AdapterContext->FramesRxDirected ); |
| break; |
| |
| case OID_GEN_MAXIMUM_TOTAL_SIZE: |
| case OID_GEN_TRANSMIT_BLOCK_SIZE: |
| case OID_GEN_RECEIVE_BLOCK_SIZE: |
| status = RequestQuery<ULONG>( OidRequest, HW_MAX_FRAME_SIZE ); |
| break; |
| |
| case OID_GEN_RECEIVE_BUFFER_SPACE: |
| status = RequestQuery<ULONG>( OidRequest, HW_MAX_FRAME_SIZE * AdapterContext->ulMaxBusyRecvs ); |
| break; |
| |
| case OID_GEN_STATISTICS: |
| status = RequestQueryGenStatistics(OidRequest, AdapterContext); |
| break; |
| |
| case OID_GEN_TRANSMIT_BUFFER_SPACE: |
| status = RequestQuery<ULONG>( OidRequest, HW_MAX_FRAME_SIZE * AdapterContext->ulMaxBusySends ); |
| break; |
| |
| case OID_GEN_VENDOR_DESCRIPTION: |
| case OID_GEN_VENDOR_DRIVER_VERSION: |
| case OID_GEN_VENDOR_ID: |
| if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NIC_VENDOR_DESC)) |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( NIC_VENDOR_DESC ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = 0; |
| status = NDIS_STATUS_INVALID_LENGTH; |
| } |
| else |
| { |
| OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof( NIC_VENDOR_DESC ); |
| OidRequest->DATA.QUERY_INFORMATION.BytesWritten = sizeof( NIC_VENDOR_DESC ); |
| memcpy(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, NIC_VENDOR_DESC, sizeof(NIC_VENDOR_DESC)); |
| status = NDIS_STATUS_SUCCESS; |
| } |
| break; |
| |
| case OID_GEN_XMIT_OK: |
| status = RequestQuery32or64( OidRequest, AdapterContext->FramesTxBroadcast |
| + AdapterContext->FramesTxMulticast |
| + AdapterContext->FramesTxDirected ); |
| break; |
| |
| case OID_802_3_CURRENT_ADDRESS: |
| status = RequestQuery( OidRequest, AdapterContext->ExtendedAddress ); |
| break; |
| |
| case OID_802_3_PERMANENT_ADDRESS: |
| status = RequestQuery( OidRequest, AdapterContext->ExtendedAddress ); |
| break; |
| |
| case OID_PNP_CAPABILITIES: |
| // We do not support low power |
| status = NDIS_STATUS_NOT_SUPPORTED; |
| fFailExpected = true; |
| break; |
| |
| case OID_PNP_QUERY_POWER: |
| status = NDIS_STATUS_NOT_ACCEPTED; |
| fFailExpected = true; |
| break; |
| |
| case OID_OT_CAPABILITIES: |
| status = RequestQueryThreadCapabilities( OidRequest ); |
| break; |
| |
| default: |
| status = NDIS_STATUS_NOT_SUPPORTED; |
| break; |
| } |
| break; |
| case NdisRequestMethod: |
| break; |
| default: |
| status = NDIS_STATUS_INVALID_OID; |
| break; |
| |
| } |
| UNREFERENCED_PARAMETER( OidRequest ); |
| |
| if (!fFailExpected && (status != NDIS_STATUS_SUCCESS)) |
| { |
| LogFuncExitMsg(DRIVER_DEFAULT, " Type:%u Oid:%u Status:%!NDIS_STATUS!", OidRequest->RequestType, OidRequest->DATA.QUERY_INFORMATION.Oid, status); |
| } |
| else |
| { |
| // By not using LogFuncExitNDIS, this won't get auto-promoted to a warning on non-0 statuses |
| LogFuncExitMsg(DRIVER_DEFAULT, " Type:%u Oid:%u Status:%!NDIS_STATUS!", OidRequest->RequestType, OidRequest->DATA.QUERY_INFORMATION.Oid, status); |
| } |
| return status; |
| } |
| |
| _Use_decl_annotations_ |
| VOID |
| MPCancelOidRequest( |
| _In_ NDIS_HANDLE /* MiniportAdapterContext */, |
| _In_ PVOID /* pRequestId */ |
| ) |
| { |
| LogFuncEntry(DRIVER_DEFAULT); |
| |
| LogFuncExit(DRIVER_DEFAULT); |
| } |