diff --git a/RtEthSample/RtEthSample.inx b/RtEthSample/RtEthSample.inx
index 70d0db8..4b6ebf1 100644
--- a/RtEthSample/RtEthSample.inx
+++ b/RtEthSample/RtEthSample.inx
@@ -46,6 +46,8 @@ CatalogFile.NT = RtEthSample.cat
[RTL8168.ndi.NT]
FeatureScore = 0xFE
+CopyFiles = RtEthSample.CopyFiles
+
Characteristics = 0x04 ; NCF_PHYSICAL
; TODO: Update with the type of bus (PCI, USB, or custom) your device uses.
@@ -65,7 +67,6 @@ BusType = 5 ; PCIBus
*AccessType = 2 ; NET_IF_ACCESS_BROADCAST
*HardwareLoopback = 0 ; false
-CopyFiles = MyCopyFiles
AddReg = ndi.reg
; To make it easier to share common keywords across different devices, we have
@@ -79,6 +80,8 @@ AddReg = InterruptModeration.kw
AddReg = InterruptModerationLevel.kw
AddReg = OffloadChecksum.kw
AddReg = PriorityVlanTag.kw
+AddReg = LSO.kw
+AddReg = ReceiveSideScaling.kw
[ndi.reg]
; TODO: Update these if your device is not Ethernet.
@@ -103,10 +106,9 @@ StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
; TODO: Update the name of your binary.
ServiceBinary = %13%\RtEthSample.sys
-AddReg = RtEthSample.Service.Reg
-[RtEthSample.Service.Reg]
-HKR,, BootFlags, 0x00010001, 1 ; CM_SERVICE_NETWORK_BOOT_LOAD
+[RtEthSample.CopyFiles]
+RtEthSample.sys
[Service.EventLog]
AddReg = Service.AddEventLog.reg
@@ -114,14 +116,8 @@ AddReg = Service.AddEventLog.reg
[Service.AddEventLog.reg]
HKR,, EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
HKR,, TypesSupported, 0x00010001, 7
-
-; TODO: List off all the binaries that are part of your driver package.
-; Typically this is just the .sys file.
-[MyCopyFiles]
-RtEthSample.sys
-
[DestinationDirs]
-MyCopyFiles = 13
+RtEthSample.CopyFiles = 13
[SourceDisksNames]
1 = %DiskDescription%
@@ -224,17 +220,36 @@ HKR,Ndi\params\*UDPChecksumOffloadIPv6\enum, "2", 0, %RxEnabled%
HKR,Ndi\params\*UDPChecksumOffloadIPv6\enum, "3", 0, %RxTxEnabled%
[PriorityVlanTag.kw]
-HKR,Ndi\Params\*PriorityVlanTag, ParamDesc, 0, %PriorityVLAN%
-HKR,Ndi\Params\*PriorityVlanTag, Default, 0, "3"
-HKR,Ndi\Params\*PriorityVlanTag, Type, 0, "enum"
-HKR,Ndi\Params\*PriorityVlanTag\enum, "0", 0, %PriorityVLANDisabled%
-HKR,Ndi\Params\*PriorityVlanTag\enum, "1", 0, %PriorityEnabled%
-HKR,Ndi\Params\*PriorityVlanTag\enum, "2", 0, %VLANEnabled%
-HKR,Ndi\Params\*PriorityVlanTag\enum, "3", 0, %PriorityVLANEnabled%
+HKR,Ndi\Params\*PriorityVlanTag, ParamDesc, 0, %PriorityVLAN%
+HKR,Ndi\Params\*PriorityVlanTag, Default, 0, "3"
+HKR,Ndi\Params\*PriorityVlanTag, Type, 0, "enum"
+HKR,Ndi\Params\*PriorityVlanTag\enum, "0", 0, %PriorityVLANDisabled%
+HKR,Ndi\Params\*PriorityVlanTag\enum, "1", 0, %PriorityEnabled%
+HKR,Ndi\Params\*PriorityVlanTag\enum, "2", 0, %VLANEnabled%
+HKR,Ndi\Params\*PriorityVlanTag\enum, "3", 0, %PriorityVLANEnabled%
+
+[LSO.kw]
+HKR,Ndi\Params\*LsoV2Ipv4, ParamDesc, 0, %LSOv2Ipv4%
+HKR,Ndi\Params\*LsoV2Ipv4, Type, 0, "enum"
+HKR,Ndi\Params\*LsoV2Ipv4, Default, 0, "1"
+HKR,Ndi\Params\*LsoV2Ipv4\enum, "0", 0, %Disabled%
+HKR,Ndi\Params\*LsoV2Ipv4\enum, "1", 0, %Enabled%
+
+HKR,Ndi\Params\*LsoV2Ipv6, ParamDesc, 0, %LSOv2Ipv6%
+HKR,Ndi\Params\*LsoV2Ipv6, Type, 0, "enum"
+HKR,Ndi\Params\*LsoV2Ipv6, Default, 0, "1"
+HKR,Ndi\Params\*LsoV2Ipv6\enum, "0", 0, %Disabled%
+HKR,Ndi\Params\*LsoV2Ipv6\enum, "1", 0, %Enabled%
+
+[ReceiveSideScaling.kw]
+HKR,Ndi\Params\*RSS, ParamDesc, 0, "%ReceiveSideScaling%"
+HKR,Ndi\Params\*RSS, default, 0, "1"
+HKR,Ndi\Params\*RSS, type, 0, "enum"
+HKR,Ndi\Params\*RSS, optional, 0, "0"
+HKR,Ndi\Params\*RSS\enum, "0", 0, %Disabled%"
+HKR,Ndi\Params\*RSS\enum, "1", 0, %Enabled%"
+HKR, "", *RSS, 0, "1"
-;
-; Localized strings
-;
[Strings]
Provider = "Realtek"
AutoDetect = "Auto Negotiation"
@@ -257,11 +272,12 @@ TxEnabled = "Tx Enabled"
RxEnabled = "Rx Enabled"
RxTxEnabled = "Rx & Tx Enabled"
FlowControl = "Flow Control"
-PriorityVLAN = "Packet Priority & VLAN"
-PriorityVLANDisabled = "Packet Priority & VLAN Disabled"
+PriorityVLAN = "Priority & VLAN"
+PriorityVLANDisabled = "Priority & VLAN Disabled"
+PriorityVLANEnabled = "Priority & VLAN Enabled"
PriorityEnabled = "Packet Priority Enabled"
+ReceiveSideScaling = "Receive Side Scaling"
VLANEnabled = "VLAN Enabled"
-PriorityVLANEnabled = "Packet Priority & VLAN Enabled"
InterruptModeration = "Interrupt Moderation"
InterruptModerationLevel = "Interrupt Moderation Level"
ReceiveBuffers = "Receive Buffers"
@@ -271,6 +287,9 @@ IMLow = "Low"
IMMedium = "Medium"
TransmitBuffers = "Transmit Buffers"
+LSOv2Ipv4 = "Large Send Offload v2 (IPv4)"
+LSOv2Ipv6 = "Large Send Offload v2 (IPv6)"
+
RTL8168.DeviceDesc = "Realtek PCIe GBE Family Controller NetAdapter Sample Driver"
Service.DisplayName = "Realtek PCIe GBE Family Controller NetAdapter Sample Driver"
diff --git a/RtEthSample/RtEthSample.sln b/RtEthSample/RtEthSample.sln
index 685b48b..d5d9507 100644
--- a/RtEthSample/RtEthSample.sln
+++ b/RtEthSample/RtEthSample.sln
@@ -1,35 +1,27 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26730.3
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RtEthSample", "RtEthSample.vcxproj", "{EAC78963-C6D0-4C8C-918D-5B5996AE80AC}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.ActiveCfg = Debug|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.Build.0 = Debug|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.Deploy.0 = Debug|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x86.ActiveCfg = Debug|Win32
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x86.Build.0 = Debug|Win32
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x86.Deploy.0 = Debug|Win32
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.ActiveCfg = Release|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.Build.0 = Release|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.Deploy.0 = Release|x64
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x86.ActiveCfg = Release|Win32
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x86.Build.0 = Release|Win32
- {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x86.Deploy.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {C69DEFBE-663E-4A9D-872B-FEB337FBF98E}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33516.290
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RtEthSample", "RtEthSample.vcxproj", "{EAC78963-C6D0-4C8C-918D-5B5996AE80AC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.ActiveCfg = Debug|x64
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.Build.0 = Debug|x64
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Debug|x64.Deploy.0 = Debug|x64
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.ActiveCfg = Release|x64
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.Build.0 = Release|x64
+ {EAC78963-C6D0-4C8C-918D-5B5996AE80AC}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C69DEFBE-663E-4A9D-872B-FEB337FBF98E}
+ EndGlobalSection
+EndGlobal
diff --git a/RtEthSample/RtEthSample.vcxproj b/RtEthSample/RtEthSample.vcxproj
index 6677f9b..3348f76 100644
--- a/RtEthSample/RtEthSample.vcxproj
+++ b/RtEthSample/RtEthSample.vcxproj
@@ -9,14 +9,6 @@
Release
x64
-
- Debug
- Win32
-
-
- Release
- Win32
-
WindowsKernelModeDriver10.0
@@ -34,7 +26,7 @@
Windows10
true
2
- 0
+ 3
1
23
True
@@ -42,7 +34,7 @@
Universal
- true
+ false
@@ -65,7 +57,7 @@
precomp.h
- %(AdditionalIncludeDirectories)
+ %(AdditionalIncludeDirectories)C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\km\netcx\kmdf\adapter\2.2\
@@ -73,11 +65,18 @@
true
1.0
+
+ /fd SHA256 %(AdditionalOptions)
+
+
+ /fd SHA256 %(AdditionalOptions)
+
-
+
@@ -93,6 +92,8 @@
+
+
diff --git a/RtEthSample/RtEthSample.vcxproj.filters b/RtEthSample/RtEthSample.vcxproj.filters
index e22b892..cda9aeb 100644
--- a/RtEthSample/RtEthSample.vcxproj.filters
+++ b/RtEthSample/RtEthSample.vcxproj.filters
@@ -24,6 +24,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -68,28 +71,28 @@
-
+
Source Files
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
@@ -101,10 +104,10 @@
Source Files
-
+
Source Files
-
+
Source Files
diff --git a/RtEthSample/adapter.cpp b/RtEthSample/adapter.cpp
index a34430c..3af8b1c 100644
--- a/RtEthSample/adapter.cpp
+++ b/RtEthSample/adapter.cpp
@@ -11,8 +11,7 @@
#include "precomp.h"
-#include
-#include
+#include
#include "trace.h"
#include "device.h"
@@ -22,6 +21,9 @@
#include "eeprom.h"
#include "gigamac.h"
+// Uncomment the line below to use Checksum APIs from Netcx 2.0
+// #define USE_NETCX20_CHECKSUM
+
#define ETH_IS_ZERO(Address) ( \
(((PUCHAR)(Address))[0] == ((UCHAR)0x00)) && \
(((PUCHAR)(Address))[1] == ((UCHAR)0x00)) && \
@@ -30,7 +32,7 @@
(((PUCHAR)(Address))[4] == ((UCHAR)0x00)) && \
(((PUCHAR)(Address))[5] == ((UCHAR)0x00)))
-NTSTATUS
+NTSTATUS
RtInitializeAdapterContext(
_In_ RT_ADAPTER *adapter,
_In_ WDFDEVICE device,
@@ -52,7 +54,7 @@ Return Value:
--*/
{
TraceEntry();
-
+
NTSTATUS status = STATUS_SUCCESS;
adapter->NetAdapter = netAdapter;
@@ -82,22 +84,24 @@ Return Value:
}
-
void
RtAdapterUpdateHardwareChecksum(
_In_ RT_ADAPTER *adapter
)
{
USHORT cpcr = adapter->CSRAddress->CPCR;
-
+
// if one of the checksum offloads is needed
// or one of the LSO offloads is enabled,
// enable HW checksum
- if (adapter->IpHwChkSum ||
- adapter->TcpHwChkSum ||
- adapter->UdpHwChkSum ||
- adapter->LSOv4 == RtLsoOffloadEnabled ||
- adapter->LSOv6 == RtLsoOffloadEnabled)
+ if (adapter->TxIpHwChkSum ||
+ adapter->TxTcpHwChkSum ||
+ adapter->TxUdpHwChkSum ||
+ adapter->RxIpHwChkSum ||
+ adapter->RxTcpHwChkSum ||
+ adapter->RxUdpHwChkSum ||
+ adapter->LSOv4 == RtGsoOffloadEnabled ||
+ adapter->LSOv6 == RtGsoOffloadEnabled)
{
cpcr |= CPCR_RX_CHECKSUM;
}
@@ -109,68 +113,6 @@ RtAdapterUpdateHardwareChecksum(
adapter->CSRAddress->CPCR = cpcr;
}
-void
-RtAdapterQueryHardwareCapabilities(
- _Out_ NDIS_OFFLOAD *hardwareCaps
- )
-{
- // TODO: when vlan is implemented, each of TCP_OFFLOAD's encapsulation
- // type has to be updated to include NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q_IN_OOB
-
- RtlZeroMemory(hardwareCaps, sizeof(*hardwareCaps));
-
- hardwareCaps->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
- hardwareCaps->Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_5;
- hardwareCaps->Header.Revision = NDIS_OFFLOAD_REVISION_5;
-
- // IPv4 checksum offloads supported
- hardwareCaps->Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
-
- hardwareCaps->Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->Checksum.IPv4Receive.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Receive.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Receive.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Receive.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
-
- // IPv6 checksum offloads supported
- hardwareCaps->Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->Checksum.IPv6Transmit.IpExtensionHeadersSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Transmit.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Transmit.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
-
- hardwareCaps->Checksum.IPv6Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->Checksum.IPv6Receive.IpExtensionHeadersSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Receive.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Receive.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->Checksum.IPv6Receive.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
-
- // LSOv1 IPv4 offload NOT supported
- hardwareCaps->LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
- hardwareCaps->LsoV1.IPv4.MaxOffLoadSize = 0;
- hardwareCaps->LsoV1.IPv4.MinSegmentCount = 0;
- hardwareCaps->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
- hardwareCaps->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
-
- // LSOv2 IPv4 offload supported
- hardwareCaps->LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->LsoV2.IPv4.MaxOffLoadSize = RT_LSO_OFFLOAD_MAX_SIZE;
- hardwareCaps->LsoV2.IPv4.MinSegmentCount = RT_LSO_OFFLOAD_MIN_SEGMENT_COUNT;
-
- // LSOv2 IPv6 offload supported
- hardwareCaps->LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
- hardwareCaps->LsoV2.IPv6.MaxOffLoadSize = RT_LSO_OFFLOAD_MAX_SIZE;
- hardwareCaps->LsoV2.IPv6.MinSegmentCount = RT_LSO_OFFLOAD_MIN_SEGMENT_COUNT;
- hardwareCaps->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_SUPPORTED;
- hardwareCaps->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
-}
-
_Use_decl_annotations_
NTSTATUS
EvtAdapterCreateTxQueue(
@@ -184,8 +126,6 @@ EvtAdapterCreateTxQueue(
RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
-#pragma region Create NETTXQUEUE
-
WDF_OBJECT_ATTRIBUTES txAttributes;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&txAttributes, RT_TXQUEUE);
@@ -200,6 +140,8 @@ EvtAdapterCreateTxQueue(
txConfig.EvtStart = EvtTxQueueStart;
txConfig.EvtStop = EvtTxQueueStop;
+ const ULONG queueId = NetTxQueueInitGetQueueId(txQueueInit);
+
NETPACKETQUEUE txQueue;
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
NetTxQueueCreate(
@@ -208,26 +150,34 @@ EvtAdapterCreateTxQueue(
&txConfig,
&txQueue));
-#pragma endregion
-
-#pragma region Get packet extension offsets
RT_TXQUEUE *tx = RtGetTxQueueContext(txQueue);
+ tx->QueueId = queueId;
+ tx->Priority = TPPoll_NPQ;
+
NET_EXTENSION_QUERY extension;
NET_EXTENSION_QUERY_INIT(
&extension,
NET_PACKET_EXTENSION_CHECKSUM_NAME,
NET_PACKET_EXTENSION_CHECKSUM_VERSION_1,
NetExtensionTypePacket);
-
+
NetTxQueueGetExtension(txQueue, &extension, &tx->ChecksumExtension);
NET_EXTENSION_QUERY_INIT(
&extension,
- NET_PACKET_EXTENSION_LSO_NAME,
- NET_PACKET_EXTENSION_LSO_VERSION_1,
+ NET_PACKET_EXTENSION_GSO_NAME,
+ NET_PACKET_EXTENSION_GSO_VERSION_1,
+ NetExtensionTypePacket);
+
+ NetTxQueueGetExtension(txQueue, &extension, &tx->GsoExtension);
+
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_PACKET_EXTENSION_IEEE8021Q_NAME,
+ NET_PACKET_EXTENSION_IEEE8021Q_VERSION_1,
NetExtensionTypePacket);
- NetTxQueueGetExtension(txQueue, &extension, &tx->LsoExtension);
+ NetTxQueueGetExtension(txQueue, &extension, &tx->Ieee8021qExtension);
NET_EXTENSION_QUERY_INIT(
&extension,
@@ -245,15 +195,9 @@ EvtAdapterCreateTxQueue(
NetTxQueueGetExtension(txQueue, &extension, &tx->LogicalAddressExtension);
-#pragma endregion
-
-#pragma region Initialize RTL8168D Transmit Queue
-
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
RtTxQueueInitialize(txQueue, adapter));
-#pragma endregion
-
Exit:
TraceExitResult(status);
@@ -273,8 +217,6 @@ EvtAdapterCreateRxQueue(
RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
-#pragma region Create NETRXQUEUE
-
WDF_OBJECT_ATTRIBUTES rxAttributes;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&rxAttributes, RT_RXQUEUE);
@@ -294,8 +236,6 @@ EvtAdapterCreateRxQueue(
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
NetRxQueueCreate(rxQueueInit, &rxAttributes, &rxConfig, &rxQueue));
-#pragma endregion
-
RT_RXQUEUE *rx = RtGetRxQueueContext(rxQueue);
NET_EXTENSION_QUERY extension;
NET_EXTENSION_QUERY_INIT(
@@ -308,6 +248,14 @@ EvtAdapterCreateRxQueue(
NetRxQueueGetExtension(rxQueue, &extension, &rx->ChecksumExtension);
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_NAME,
+ NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_VERSION_1,
+ NetExtensionTypeFragment);
+
+ NetRxQueueGetExtension(rxQueue, &extension, &rx->VirtualAddressExtension);
+
NET_EXTENSION_QUERY_INIT(
&extension,
NET_FRAGMENT_EXTENSION_LOGICAL_ADDRESS_NAME,
@@ -316,13 +264,17 @@ EvtAdapterCreateRxQueue(
NetRxQueueGetExtension(rxQueue, &extension, &rx->LogicalAddressExtension);
-#pragma region Initialize RTL8168D Receive Queue
+ NET_EXTENSION_QUERY_INIT(
+ &extension,
+ NET_PACKET_EXTENSION_HASH_NAME,
+ NET_PACKET_EXTENSION_HASH_VERSION_1,
+ NetExtensionTypePacket);
+
+ NetRxQueueGetExtension(rxQueue, &extension, &rx->HashValueExtension);
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
RtRxQueueInitialize(rxQueue, adapter));
-#pragma endregion
-
Exit:
TraceExitResult(status);
@@ -405,6 +357,8 @@ EvtAdapterReceiveScalingEnable(
GOTO_IF_NOT_NT_SUCCESS(Exit, status,
RtReceiveScalingEnable(adapter, protocolType));
+ adapter->RssEnabled = true;
+
Exit:
TraceExitResult(status);
@@ -423,6 +377,8 @@ EvtAdapterReceiveScalingDisable(
{
WdfDeviceSetFailed(adapter->WdfDevice, WdfDeviceFailedAttemptRestart);
}
+
+ adapter->RssEnabled = false;
}
static
@@ -786,7 +742,7 @@ RtAdapterIssueFullReset(
}
}
-void
+void
RtAdapterUpdateInterruptModeration(
_In_ RT_ADAPTER *adapter
)
@@ -843,45 +799,31 @@ RtAdapterUpdateInterruptModeration(
}
void
-EvtSetPacketFilter(
- _In_ NETADAPTER netAdapter,
- _In_ NET_PACKET_FILTER_FLAGS PacketFilter
- )
-{
- RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
-
- WdfSpinLockAcquire(adapter->Lock); {
-
- adapter->PacketFilter = PacketFilter;
- RtAdapterUpdateRcr(adapter);
-
- // Changing the packet filter might require clearing the active MCList
- RtAdapterPushMulticastList(adapter);
-
- } WdfSpinLockRelease(adapter->Lock);
-}
-
-void
-EvtSetMulticastList(
+EvtSetReceiveFilter(
_In_ NETADAPTER NetAdapter,
- _In_ ULONG MulticastAddressCount,
- _In_ NET_ADAPTER_LINK_LAYER_ADDRESS * MulticastAddressList
+ _In_ NETRECEIVEFILTER Handle
)
{
RT_ADAPTER *adapter = RtGetAdapterContext(NetAdapter);
WdfSpinLockAcquire(adapter->Lock); {
- adapter->MCAddressCount = MulticastAddressCount;
+ adapter->PacketFilter = NetReceiveFilterGetPacketFilter(Handle);
+ RtAdapterUpdateRcr(adapter);
+
+ adapter->MCAddressCount = (UINT)NetReceiveFilterGetMulticastAddressCount(Handle);;
- RtlZeroMemory(adapter->MCList,
- sizeof(NET_ADAPTER_LINK_LAYER_ADDRESS) * RT_MAX_MCAST_LIST);
+ RtlZeroMemory(
+ adapter->MCList,
+ sizeof(NET_ADAPTER_LINK_LAYER_ADDRESS) * RT_MAX_MCAST_LIST);
- if (MulticastAddressCount != 0)
+ if (adapter->MCAddressCount != 0U)
{
- RtlCopyMemory(adapter->MCList,
+ NET_ADAPTER_LINK_LAYER_ADDRESS const * MulticastAddressList = NetReceiveFilterGetMulticastAddressList(Handle);
+ RtlCopyMemory(
+ adapter->MCList,
MulticastAddressList,
- sizeof(NET_ADAPTER_LINK_LAYER_ADDRESS) * MulticastAddressCount);
+ sizeof(NET_ADAPTER_LINK_LAYER_ADDRESS) * adapter->MCAddressCount);
}
RtAdapterPushMulticastList(adapter);
@@ -891,17 +833,18 @@ EvtSetMulticastList(
static
void
-RtAdapterSetMulticastCapabilities(
+RtAdapterSetReceiveFilterCapabilities(
_In_ RT_ADAPTER *adapter
)
{
- NET_ADAPTER_MULTICAST_CAPABILITIES multicastCapabilities;
- NET_ADAPTER_MULTICAST_CAPABILITIES_INIT(
- &multicastCapabilities,
- RT_MAX_MCAST_LIST,
- EvtSetMulticastList);
-
- NetAdapterSetMulticastCapabilities(adapter->NetAdapter, &multicastCapabilities);
+ NET_ADAPTER_RECEIVE_FILTER_CAPABILITIES receiveFilterCapabilities;
+ NET_ADAPTER_RECEIVE_FILTER_CAPABILITIES_INIT(
+ &receiveFilterCapabilities,
+ EvtSetReceiveFilter);
+ receiveFilterCapabilities.SupportedPacketFilters = RT_SUPPORTED_FILTERS;
+ receiveFilterCapabilities.MaximumMulticastAddresses = RT_MAX_MCAST_LIST;
+
+ NetAdapterSetReceiveFilterCapabilities(adapter->NetAdapter, &receiveFilterCapabilities);
}
static
@@ -919,17 +862,10 @@ RtAdapterSetLinkLayerCapabilities(
maxXmitLinkSpeed,
maxRcvLinkSpeed);
- NET_ADAPTER_PACKET_FILTER_CAPABILITIES packetFilterCapabilities;
- NET_ADAPTER_PACKET_FILTER_CAPABILITIES_INIT(
- &packetFilterCapabilities,
- RT_SUPPORTED_FILTERS,
- EvtSetPacketFilter);
-
NetAdapterSetLinkLayerCapabilities(adapter->NetAdapter, &linkLayerCapabilities);
NetAdapterSetLinkLayerMtuSize(adapter->NetAdapter, RT_MAX_PACKET_SIZE - ETH_LENGTH_OF_HEADER);
NetAdapterSetPermanentLinkLayerAddress(adapter->NetAdapter, &adapter->PermanentAddress);
NetAdapterSetCurrentLinkLayerAddress(adapter->NetAdapter, &adapter->CurrentAddress);
- NetAdapterSetPacketFilterCapabilities(adapter->NetAdapter, &packetFilterCapabilities);
}
static
@@ -938,24 +874,21 @@ RtAdapterSetReceiveScalingCapabilities(
_In_ RT_ADAPTER const *adapter
)
{
- if (adapter->RssEnabled)
- {
- NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES receiveScalingCapabilities;
- NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES_INIT(
- &receiveScalingCapabilities,
- 4, // NumberOfQueues
- NetAdapterReceiveScalingUnhashedTargetTypeHashIndex,
- NetAdapterReceiveScalingHashTypeToeplitz,
- NetAdapterReceiveScalingProtocolTypeIPv4 |
- NetAdapterReceiveScalingProtocolTypeIPv6 |
- NetAdapterReceiveScalingProtocolTypeTcp,
- EvtAdapterReceiveScalingEnable,
- EvtAdapterReceiveScalingDisable,
- EvtAdapterReceiveScalingSetHashSecretKey,
- EvtAdapterReceiveScalingSetIndirectionEntries);
- receiveScalingCapabilities.SynchronizeSetIndirectionEntries = true;
- NetAdapterSetReceiveScalingCapabilities(adapter->NetAdapter, &receiveScalingCapabilities);
- }
+ NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES receiveScalingCapabilities;
+ NET_ADAPTER_RECEIVE_SCALING_CAPABILITIES_INIT(
+ &receiveScalingCapabilities,
+ RT_NUMBER_OF_RX_QUEUES,
+ NetAdapterReceiveScalingUnhashedTargetTypeHashIndex,
+ NetAdapterReceiveScalingHashTypeToeplitz,
+ NetAdapterReceiveScalingProtocolTypeIPv4 |
+ NetAdapterReceiveScalingProtocolTypeIPv6 |
+ NetAdapterReceiveScalingProtocolTypeTcp,
+ EvtAdapterReceiveScalingEnable,
+ EvtAdapterReceiveScalingDisable,
+ EvtAdapterReceiveScalingSetHashSecretKey,
+ EvtAdapterReceiveScalingSetIndirectionEntries);
+ receiveScalingCapabilities.SynchronizeSetIndirectionEntries = true;
+ NetAdapterSetReceiveScalingCapabilities(adapter->NetAdapter, &receiveScalingCapabilities);
}
static
@@ -988,7 +921,7 @@ RtAdapterSetDatapathCapabilities(
txCapabilities.FragmentRingNumberOfElementsHint = adapter->NumTcb * RT_MAX_PHYS_BUF_COUNT;
txCapabilities.MaximumNumberOfFragments = RT_MAX_PHYS_BUF_COUNT;
-
+
NET_ADAPTER_DMA_CAPABILITIES rxDmaCapabilities;
NET_ADAPTER_DMA_CAPABILITIES_INIT(&rxDmaCapabilities, adapter->DmaEnabler);
@@ -1006,6 +939,7 @@ RtAdapterSetDatapathCapabilities(
}
+#ifdef USE_NETCX20_CHECKSUM
static
void
EvtAdapterOffloadSetChecksum(
@@ -1015,16 +949,49 @@ EvtAdapterOffloadSetChecksum(
{
RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
- adapter->IpHwChkSum = NetOffloadIsChecksumIPv4Enabled(offload);
- adapter->TcpHwChkSum = NetOffloadIsChecksumTcpEnabled(offload);
- adapter->UdpHwChkSum = NetOffloadIsChecksumUdpEnabled(offload);
+ adapter->TxIpHwChkSum = adapter->RxIpHwChkSum = NetOffloadIsChecksumIPv4Enabled(offload);
+ adapter->TxTcpHwChkSum = adapter->RxTcpHwChkSum = NetOffloadIsChecksumTcpEnabled(offload);
+ adapter->TxUdpHwChkSum = adapter->RxUdpHwChkSum = NetOffloadIsChecksumUdpEnabled(offload);
+
+ RtAdapterUpdateHardwareChecksum(adapter);
+}
+#else
+static
+void
+EvtAdapterOffloadSetTxChecksum(
+ _In_ NETADAPTER netAdapter,
+ _In_ NETOFFLOAD offload
+ )
+{
+ RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
+
+ adapter->TxIpHwChkSum = NetOffloadIsTxChecksumIPv4Enabled(offload);
+ adapter->TxTcpHwChkSum = NetOffloadIsTxChecksumTcpEnabled(offload);
+ adapter->TxUdpHwChkSum = NetOffloadIsTxChecksumUdpEnabled(offload);
RtAdapterUpdateHardwareChecksum(adapter);
}
static
void
-EvtAdapterOffloadSetLso(
+EvtAdapterOffloadSetRxChecksum(
+ _In_ NETADAPTER netAdapter,
+ _In_ NETOFFLOAD offload
+ )
+{
+ RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
+
+ adapter->RxIpHwChkSum = NetOffloadIsRxChecksumIPv4Enabled(offload);
+ adapter->RxTcpHwChkSum = NetOffloadIsRxChecksumTcpEnabled(offload);
+ adapter->RxUdpHwChkSum = NetOffloadIsRxChecksumUdpEnabled(offload);
+
+ RtAdapterUpdateHardwareChecksum(adapter);
+}
+#endif
+
+static
+void
+EvtAdapterOffloadSetGso(
_In_ NETADAPTER netAdapter,
_In_ NETOFFLOAD offload
)
@@ -1032,9 +999,9 @@ EvtAdapterOffloadSetLso(
RT_ADAPTER *adapter = RtGetAdapterContext(netAdapter);
adapter->LSOv4 = NetOffloadIsLsoIPv4Enabled(offload)
- ? RtLsoOffloadEnabled : RtLsoOffloadDisabled;
+ ? RtGsoOffloadEnabled : RtGsoOffloadDisabled;
adapter->LSOv6 = NetOffloadIsLsoIPv6Enabled(offload)
- ? RtLsoOffloadEnabled : RtLsoOffloadDisabled;
+ ? RtGsoOffloadEnabled : RtGsoOffloadDisabled;
RtAdapterUpdateHardwareChecksum(adapter);
}
@@ -1045,6 +1012,7 @@ RtAdapterSetOffloadCapabilities(
_In_ RT_ADAPTER const *adapter
)
{
+#ifdef USE_NETCX20_CHECKSUM
NET_ADAPTER_OFFLOAD_CHECKSUM_CAPABILITIES checksumOffloadCapabilities;
NET_ADAPTER_OFFLOAD_CHECKSUM_CAPABILITIES_INIT(
@@ -1055,18 +1023,69 @@ RtAdapterSetOffloadCapabilities(
EvtAdapterOffloadSetChecksum);
NetAdapterOffloadSetChecksumCapabilities(adapter->NetAdapter, &checksumOffloadCapabilities);
+#else
+ NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES txChecksumOffloadCapabilities;
- NET_ADAPTER_OFFLOAD_LSO_CAPABILITIES lsoOffloadCapabilities;
+ auto const layer3Flags = NetAdapterOffloadLayer3FlagIPv4NoOptions |
+ NetAdapterOffloadLayer3FlagIPv4WithOptions |
+ NetAdapterOffloadLayer3FlagIPv6NoExtensions |
+ NetAdapterOffloadLayer3FlagIPv6WithExtensions;
- NET_ADAPTER_OFFLOAD_LSO_CAPABILITIES_INIT(
- &lsoOffloadCapabilities,
- TRUE,
- TRUE,
- RT_LSO_OFFLOAD_MAX_SIZE,
- RT_LSO_OFFLOAD_MIN_SEGMENT_COUNT,
- EvtAdapterOffloadSetLso);
+ auto const layer4Flags = NetAdapterOffloadLayer4FlagTcpNoOptions |
+ NetAdapterOffloadLayer4FlagTcpWithOptions |
+ NetAdapterOffloadLayer4FlagUdp;
+
+ NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT(
+ &txChecksumOffloadCapabilities,
+ layer3Flags,
+ EvtAdapterOffloadSetTxChecksum);
+
+ txChecksumOffloadCapabilities.Layer4Flags = layer4Flags;
+ txChecksumOffloadCapabilities.Layer4HeaderOffsetLimit = RT_CHECKSUM_OFFLOAD_LAYER_4_HEADER_OFFSET_LIMIT;
+
+ NetAdapterOffloadSetTxChecksumCapabilities(adapter->NetAdapter, &txChecksumOffloadCapabilities);
+
+ NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES rxChecksumOffloadCapabilities;
+
+ NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT(
+ &rxChecksumOffloadCapabilities,
+ EvtAdapterOffloadSetRxChecksum);
+
+ NetAdapterOffloadSetRxChecksumCapabilities(adapter->NetAdapter, &rxChecksumOffloadCapabilities);
+#endif
+
+ NET_ADAPTER_OFFLOAD_GSO_CAPABILITIES gsoOffloadCapabilities;
+
+ auto const layer3GsoFlags = NetAdapterOffloadLayer3FlagIPv4NoOptions |
+ NetAdapterOffloadLayer3FlagIPv4WithOptions |
+ NetAdapterOffloadLayer3FlagIPv6NoExtensions |
+ NetAdapterOffloadLayer3FlagIPv6WithExtensions;
+
+ auto const layer4GsoFlags = NetAdapterOffloadLayer4FlagTcpNoOptions |
+ NetAdapterOffloadLayer4FlagTcpWithOptions;
+
+ NET_ADAPTER_OFFLOAD_GSO_CAPABILITIES_INIT(
+ &gsoOffloadCapabilities,
+ layer3GsoFlags,
+ layer4GsoFlags,
+ RT_GSO_OFFLOAD_MAX_SIZE,
+ RT_GSO_OFFLOAD_MIN_SEGMENT_COUNT,
+ EvtAdapterOffloadSetGso);
+
+ gsoOffloadCapabilities.Layer4HeaderOffsetLimit = RT_GSO_OFFLOAD_LAYER_4_HEADER_OFFSET_LIMIT;
+
+ NetAdapterOffloadSetGsoCapabilities(adapter->NetAdapter, &gsoOffloadCapabilities);
+
+ auto const ieee8021qTaggingFlag = NetAdapterOffloadIeee8021PriorityTaggingFlag |
+ NetAdapterOffloadIeee8021VlanTaggingFlag;
+
+ NET_ADAPTER_OFFLOAD_IEEE8021Q_TAG_CAPABILITIES ieee8021qTagOffloadCapabilities;
+
+ NET_ADAPTER_OFFLOAD_IEEE8021Q_TAG_CAPABILITIES_INIT(
+ &ieee8021qTagOffloadCapabilities,
+ ieee8021qTaggingFlag);
- NetAdapterOffloadSetLsoCapabilities(adapter->NetAdapter, &lsoOffloadCapabilities);
+ NetAdapterOffloadSetIeee8021qTagCapabilities(adapter->NetAdapter, &ieee8021qTagOffloadCapabilities);
}
_Use_decl_annotations_
@@ -1081,7 +1100,7 @@ RtAdapterStart(
RtAdapterSetLinkLayerCapabilities(adapter);
- RtAdapterSetMulticastCapabilities(adapter);
+ RtAdapterSetReceiveFilterCapabilities(adapter);
RtAdapterSetReceiveScalingCapabilities(adapter);
diff --git a/RtEthSample/adapter.h b/RtEthSample/adapter.h
index 08c62b2..6315704 100644
--- a/RtEthSample/adapter.h
+++ b/RtEthSample/adapter.h
@@ -14,8 +14,6 @@
typedef struct _RT_INTERRUPT RT_INTERRUPT;
typedef struct _RT_TALLY RT_TALLY;
-#pragma region Setting Enumerations
-
typedef enum _RT_DUPLEX_STATE : UCHAR {
RtDuplexNone = 0,
RtDuplexHalf = 1,
@@ -30,14 +28,16 @@ typedef enum _RT_CHKSUM_OFFLOAD : UCHAR
RtChecksumOffloadTxRxEnabled = 3,
} RT_CHKSUM_OFFLOAD;
-typedef enum _RT_LSO_OFFLOAD : UCHAR
+typedef enum _RT_GSO_OFFLOAD : UCHAR
{
- RtLsoOffloadDisabled = 0,
- RtLsoOffloadEnabled = 1,
-} RT_LSO_OFFLOAD;
+ RtGsoOffloadDisabled = 0,
+ RtGsoOffloadEnabled = 1,
+} RT_GSO_OFFLOAD;
-#define RT_LSO_OFFLOAD_MAX_SIZE 64000
-#define RT_LSO_OFFLOAD_MIN_SEGMENT_COUNT 2
+#define RT_GSO_OFFLOAD_MAX_SIZE 64000
+#define RT_GSO_OFFLOAD_MIN_SEGMENT_COUNT 2
+#define RT_GSO_OFFLOAD_LAYER_4_HEADER_OFFSET_LIMIT 127
+#define RT_CHECKSUM_OFFLOAD_LAYER_4_HEADER_OFFSET_LIMIT 1023
typedef enum _RT_IM_MODE
{
@@ -79,8 +79,6 @@ typedef enum _RT_SPEED_DUPLEX_MODE {
} RT_SPEED_DUPLEX_MODE;
-#pragma endregion
-
// Context for NETADAPTER
typedef struct _RT_ADAPTER
{
@@ -89,8 +87,8 @@ typedef struct _RT_ADAPTER
WDFDEVICE WdfDevice;
// Handle to default Tx and Rx Queues
- NETPACKETQUEUE TxQueue;
- NETPACKETQUEUE RxQueues[RT_NUMBER_OF_QUEUES];
+ NETPACKETQUEUE TxQueues[RT_NUMBER_OF_TX_QUEUES];
+ NETPACKETQUEUE RxQueues[RT_NUMBER_OF_RX_QUEUES];
// Pointer to interrupt object
RT_INTERRUPT *Interrupt;
@@ -114,17 +112,6 @@ typedef struct _RT_ADAPTER
UINT MCAddressCount;
NET_ADAPTER_LINK_LAYER_ADDRESS MCList[RT_MAX_MCAST_LIST];
- // Packet counts
- ULONG64 InUcastOctets;
- ULONG64 InMulticastOctets;
- ULONG64 InBroadcastOctets;
- ULONG64 OutUCastPkts;
- ULONG64 OutMulticastPkts;
- ULONG64 OutBroadcastPkts;
- ULONG64 OutUCastOctets;
- ULONG64 OutMulticastOctets;
- ULONG64 OutBroadcastOctets;
-
ULONG64 TotalTxErr;
ULONG TotalRxErr;
@@ -159,9 +146,13 @@ typedef struct _RT_ADAPTER
USHORT ReceiveBuffers;
USHORT TransmitBuffers;
- BOOLEAN IpHwChkSum;
- BOOLEAN TcpHwChkSum;
- BOOLEAN UdpHwChkSum;
+ BOOLEAN TxIpHwChkSum;
+ BOOLEAN TxTcpHwChkSum;
+ BOOLEAN TxUdpHwChkSum;
+
+ BOOLEAN RxIpHwChkSum;
+ BOOLEAN RxTcpHwChkSum;
+ BOOLEAN RxUdpHwChkSum;
ULONG ChksumErrRxIpv4Cnt;
ULONG ChksumErrRxTcpIpv6Cnt;
@@ -184,13 +175,13 @@ typedef struct _RT_ADAPTER
bool EEPROMInUse;
// ReceiveScaling
+ bool RssEnabled;
UINT32 RssIndirectionTable[RT_INDIRECTION_TABLE_SIZE];
RT_FLOW_CONTROL FlowControl;
- RT_LSO_OFFLOAD LSOv4;
- RT_LSO_OFFLOAD LSOv6;
- bool RssEnabled;
+ RT_GSO_OFFLOAD LSOv4;
+ RT_GSO_OFFLOAD LSOv6;
} RT_ADAPTER;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RT_ADAPTER, RtGetAdapterContext);
diff --git a/RtEthSample/common.h b/RtEthSample/common.h
new file mode 100644
index 0000000..5b33688
--- /dev/null
+++ b/RtEthSample/common.h
@@ -0,0 +1,798 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE AND NONINFRINGEMENT.
+//
+//*********************************************************
+#ifndef __WIL_COMMON_INCLUDED
+#define __WIL_COMMON_INCLUDED
+
+#if defined(_KERNEL_MODE ) && !defined(__WIL_MIN_KERNEL)
+// This define indicates that the WIL usage is in a kernel mode context where
+// a high degree of WIL functionality is desired.
+//
+// Use (sparingly) to change behavior based on whether WIL is being used in kernel
+// mode or user mode.
+#define WIL_KERNEL_MODE
+#endif
+
+// Defining WIL_HIDE_DEPRECATED will hide everything deprecated.
+// Each wave of deprecation will add a new WIL_HIDE_DEPRECATED_YYMM number that can be used to lock deprecation at
+// a particular point, allowing components to avoid backslide and catch up to the current independently.
+#ifdef WIL_HIDE_DEPRECATED
+#define WIL_HIDE_DEPRECATED_1809
+#endif
+#ifdef WIL_HIDE_DEPRECATED_1809
+#define WIL_HIDE_DEPRECATED_1612
+#endif
+#ifdef WIL_HIDE_DEPRECATED_1612
+#define WIL_HIDE_DEPRECATED_1611
+#endif
+
+// Implementation side note: ideally the deprecation would be done with the function-level declspec
+// as it allows you to utter the error text when used. The declspec works, but doing it selectively with
+// a macro makes intellisense deprecation comments not work. So we just use the #pragma deprecation.
+#ifdef WIL_WARN_DEPRECATED
+#define WIL_WARN_DEPRECATED_1809
+#endif
+#ifdef WIL_WARN_DEPRECATED_1809
+#define WIL_WARN_DEPRECATED_1612
+#endif
+#ifdef WIL_WARN_DEPRECATED_1612
+#define WIL_WARN_DEPRECATED_1611
+#endif
+#ifdef WIL_WARN_DEPRECATED_1809
+#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
+#else
+#define WIL_WARN_DEPRECATED_1809_PRAGMA(...)
+#endif
+#ifdef WIL_WARN_DEPRECATED_1611
+#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
+#else
+#define WIL_WARN_DEPRECATED_1611_PRAGMA(...)
+#endif
+#ifdef WIL_WARN_DEPRECATED_1612
+#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
+#else
+#define WIL_WARN_DEPRECATED_1612_PRAGMA(...)
+#endif
+
+#if defined(_MSVC_LANG)
+#define __WI_SUPPRESS_4127_S __pragma(warning(push)) __pragma(warning(disable:4127)) __pragma(warning(disable:26498)) __pragma(warning(disable:4245))
+#define __WI_SUPPRESS_4127_E __pragma(warning(pop))
+#define __WI_SUPPRESS_NULLPTR_ANALYSIS __pragma(warning(suppress:28285)) __pragma(warning(suppress:6504))
+#define __WI_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495))
+#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439))
+#else
+#define __WI_SUPPRESS_4127_S
+#define __WI_SUPPRESS_4127_E
+#define __WI_SUPPRESS_NULLPTR_ANALYSIS
+#define __WI_SUPPRESS_NONINIT_ANALYSIS
+#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS
+#endif
+
+#include
+
+// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can
+// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to
+// basic macros without the function for common use cases.
+/// @cond
+#define _Success_return_ _Success_(return)
+#define _Success_true_ _Success_(true)
+#define __declspec_noinline_ __declspec(noinline)
+#define __declspec_selectany_ __declspec(selectany)
+/// @endcond
+
+//! @defgroup macrobuilding Macro Composition
+//! The following macros are building blocks primarily intended for authoring other macros.
+//! @{
+
+//! Re-state a macro value (indirection for composition)
+#define WI_FLATTEN(...) __VA_ARGS__
+
+/// @cond
+#define __WI_PASTE_imp(a, b) a##b
+/// @endcond
+
+//! This macro is for use in other macros to paste two tokens together, such as a constant and the __LINE__ macro.
+#define WI_PASTE(a, b) __WI_PASTE_imp(a, b)
+
+/// @cond
+#define __WI_HAS_VA_OPT_IMPL(F, T, ...) T
+#define __WI_HAS_VA_OPT_(...) __WI_HAS_VA_OPT_IMPL(__VA_OPT__(0,) 1, 0)
+/// @endcond
+
+//! Evaluates to '1' when support for '__VA_OPT__' is available, else '0'
+#define WI_HAS_VA_OPT __WI_HAS_VA_OPT_(unused)
+
+/// @cond
+#define __WI_ARGS_COUNT1(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, \
+ A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, \
+ A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, \
+ A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, count, ...) count
+#define __WI_ARGS_COUNT0(...) WI_FLATTEN(__WI_ARGS_COUNT1(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \
+ 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
+ 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+#define __WI_ARGS_COUNT_PREFIX(...) 0, __VA_ARGS__
+/// @endcond
+
+//! This variadic macro returns the number of arguments passed to it (up to 99).
+#if WI_HAS_VA_OPT
+#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(0 __VA_OPT__(, __VA_ARGS__))
+#else
+#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(__WI_ARGS_COUNT_PREFIX(__VA_ARGS__))
+#endif
+
+/// @cond
+#define __WI_FOR_imp0( fn)
+#define __WI_FOR_imp1( fn, arg) fn(arg)
+#define __WI_FOR_imp2( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp1(fn, __VA_ARGS__))
+#define __WI_FOR_imp3( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp2(fn, __VA_ARGS__))
+#define __WI_FOR_imp4( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp3(fn, __VA_ARGS__))
+#define __WI_FOR_imp5( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp4(fn, __VA_ARGS__))
+#define __WI_FOR_imp6( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp5(fn, __VA_ARGS__))
+#define __WI_FOR_imp7( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp6(fn, __VA_ARGS__))
+#define __WI_FOR_imp8( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp7(fn, __VA_ARGS__))
+#define __WI_FOR_imp9( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp8(fn, __VA_ARGS__))
+#define __WI_FOR_imp10(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp9(fn, __VA_ARGS__))
+#define __WI_FOR_imp11(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp10(fn, __VA_ARGS__))
+#define __WI_FOR_imp12(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp11(fn, __VA_ARGS__))
+#define __WI_FOR_imp13(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp12(fn, __VA_ARGS__))
+#define __WI_FOR_imp14(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp13(fn, __VA_ARGS__))
+#define __WI_FOR_imp15(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp14(fn, __VA_ARGS__))
+#define __WI_FOR_imp16(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp15(fn, __VA_ARGS__))
+#define __WI_FOR_imp17(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp16(fn, __VA_ARGS__))
+#define __WI_FOR_imp18(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp17(fn, __VA_ARGS__))
+#define __WI_FOR_imp19(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp18(fn, __VA_ARGS__))
+#define __WI_FOR_imp20(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp19(fn, __VA_ARGS__))
+#define __WI_FOR_imp21(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp20(fn, __VA_ARGS__))
+#define __WI_FOR_imp22(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp21(fn, __VA_ARGS__))
+#define __WI_FOR_imp23(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp22(fn, __VA_ARGS__))
+#define __WI_FOR_imp24(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp23(fn, __VA_ARGS__))
+#define __WI_FOR_imp25(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp24(fn, __VA_ARGS__))
+#define __WI_FOR_imp26(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp25(fn, __VA_ARGS__))
+#define __WI_FOR_imp27(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp26(fn, __VA_ARGS__))
+#define __WI_FOR_imp28(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp27(fn, __VA_ARGS__))
+#define __WI_FOR_imp29(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp28(fn, __VA_ARGS__))
+#define __WI_FOR_imp30(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp29(fn, __VA_ARGS__))
+#define __WI_FOR_imp31(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp30(fn, __VA_ARGS__))
+#define __WI_FOR_imp32(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp31(fn, __VA_ARGS__))
+#define __WI_FOR_imp33(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp32(fn, __VA_ARGS__))
+#define __WI_FOR_imp34(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp33(fn, __VA_ARGS__))
+#define __WI_FOR_imp35(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp34(fn, __VA_ARGS__))
+#define __WI_FOR_imp36(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp35(fn, __VA_ARGS__))
+#define __WI_FOR_imp37(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp36(fn, __VA_ARGS__))
+#define __WI_FOR_imp38(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp37(fn, __VA_ARGS__))
+#define __WI_FOR_imp39(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp38(fn, __VA_ARGS__))
+#define __WI_FOR_imp40(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp39(fn, __VA_ARGS__))
+#define __WI_FOR_imp41(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp40(fn, __VA_ARGS__))
+#define __WI_FOR_imp42(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp41(fn, __VA_ARGS__))
+#define __WI_FOR_imp43(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp42(fn, __VA_ARGS__))
+#define __WI_FOR_imp44(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp43(fn, __VA_ARGS__))
+#define __WI_FOR_imp45(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp44(fn, __VA_ARGS__))
+#define __WI_FOR_imp46(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp45(fn, __VA_ARGS__))
+#define __WI_FOR_imp47(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp46(fn, __VA_ARGS__))
+#define __WI_FOR_imp48(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp47(fn, __VA_ARGS__))
+#define __WI_FOR_imp49(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp48(fn, __VA_ARGS__))
+#define __WI_FOR_imp50(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp49(fn, __VA_ARGS__))
+#define __WI_FOR_imp51(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp50(fn, __VA_ARGS__))
+#define __WI_FOR_imp52(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp51(fn, __VA_ARGS__))
+#define __WI_FOR_imp53(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp52(fn, __VA_ARGS__))
+#define __WI_FOR_imp54(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp53(fn, __VA_ARGS__))
+#define __WI_FOR_imp55(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp54(fn, __VA_ARGS__))
+#define __WI_FOR_imp56(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp55(fn, __VA_ARGS__))
+#define __WI_FOR_imp57(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp56(fn, __VA_ARGS__))
+#define __WI_FOR_imp58(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp57(fn, __VA_ARGS__))
+#define __WI_FOR_imp59(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp58(fn, __VA_ARGS__))
+#define __WI_FOR_imp60(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp59(fn, __VA_ARGS__))
+#define __WI_FOR_imp61(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp60(fn, __VA_ARGS__))
+#define __WI_FOR_imp62(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp61(fn, __VA_ARGS__))
+#define __WI_FOR_imp63(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp62(fn, __VA_ARGS__))
+#define __WI_FOR_imp64(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp63(fn, __VA_ARGS__))
+#define __WI_FOR_imp65(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp64(fn, __VA_ARGS__))
+#define __WI_FOR_imp66(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp65(fn, __VA_ARGS__))
+#define __WI_FOR_imp67(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp66(fn, __VA_ARGS__))
+#define __WI_FOR_imp68(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp67(fn, __VA_ARGS__))
+#define __WI_FOR_imp69(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp68(fn, __VA_ARGS__))
+#define __WI_FOR_imp70(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp69(fn, __VA_ARGS__))
+#define __WI_FOR_imp71(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp70(fn, __VA_ARGS__))
+#define __WI_FOR_imp72(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp71(fn, __VA_ARGS__))
+#define __WI_FOR_imp73(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp72(fn, __VA_ARGS__))
+#define __WI_FOR_imp74(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp73(fn, __VA_ARGS__))
+#define __WI_FOR_imp75(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp74(fn, __VA_ARGS__))
+#define __WI_FOR_imp76(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp75(fn, __VA_ARGS__))
+#define __WI_FOR_imp77(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp76(fn, __VA_ARGS__))
+#define __WI_FOR_imp78(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp77(fn, __VA_ARGS__))
+#define __WI_FOR_imp79(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp78(fn, __VA_ARGS__))
+#define __WI_FOR_imp80(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp79(fn, __VA_ARGS__))
+#define __WI_FOR_imp81(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp80(fn, __VA_ARGS__))
+#define __WI_FOR_imp82(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp81(fn, __VA_ARGS__))
+#define __WI_FOR_imp83(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp82(fn, __VA_ARGS__))
+#define __WI_FOR_imp84(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp83(fn, __VA_ARGS__))
+#define __WI_FOR_imp85(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp84(fn, __VA_ARGS__))
+#define __WI_FOR_imp86(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp85(fn, __VA_ARGS__))
+#define __WI_FOR_imp87(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp86(fn, __VA_ARGS__))
+#define __WI_FOR_imp88(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp87(fn, __VA_ARGS__))
+#define __WI_FOR_imp89(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp88(fn, __VA_ARGS__))
+#define __WI_FOR_imp90(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp89(fn, __VA_ARGS__))
+#define __WI_FOR_imp91(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp90(fn, __VA_ARGS__))
+#define __WI_FOR_imp92(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp91(fn, __VA_ARGS__))
+#define __WI_FOR_imp93(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp92(fn, __VA_ARGS__))
+#define __WI_FOR_imp94(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp93(fn, __VA_ARGS__))
+#define __WI_FOR_imp95(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp94(fn, __VA_ARGS__))
+#define __WI_FOR_imp96(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp95(fn, __VA_ARGS__))
+#define __WI_FOR_imp97(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp96(fn, __VA_ARGS__))
+#define __WI_FOR_imp98(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp97(fn, __VA_ARGS__))
+#define __WI_FOR_imp99(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp98(fn, __VA_ARGS__))
+
+#define __WI_FOR_imp(n, fnAndArgs) WI_PASTE(__WI_FOR_imp, n) fnAndArgs
+/// @endcond
+
+//! Iterates through each of the given arguments invoking the specified macro against each one.
+#define WI_FOREACH(fn, ...) __WI_FOR_imp(WI_ARGS_COUNT(__VA_ARGS__), (fn, ##__VA_ARGS__))
+
+//! Dispatches a single macro name to separate macros based on the number of arguments passed to it.
+#define WI_MACRO_DISPATCH(name, ...) WI_PASTE(WI_PASTE(name, WI_ARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
+
+//! @} // Macro composition helpers
+
+#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL)
+
+#define WI_ODR_PRAGMA(NAME, TOKEN)
+#define WI_NOEXCEPT
+
+#else
+#pragma warning(push)
+#pragma warning(disable:4714) // __forceinline not honored
+
+// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage
+#include "wistd_type_traits.h"
+
+//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
+#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
+
+#ifdef WIL_KERNEL_MODE
+WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
+#else
+WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
+#endif
+
+#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(WIL_SUPPRESS_EXCEPTIONS)
+/** This define is automatically set when exceptions are enabled within wil.
+It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in
+_CPPUNWIND or __EXCEPTIONS flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil
+header. All exception-based WIL methods and classes are included behind:
+~~~~
+#ifdef WIL_ENABLE_EXCEPTIONS
+// code
+#endif
+~~~~
+This enables exception-free code to directly include WIL headers without worrying about exception-based
+routines suddenly becoming available. */
+#define WIL_ENABLE_EXCEPTIONS
+#endif
+/// @endcond
+
+/// @cond
+#if defined(WIL_EXCEPTION_MODE)
+static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode");
+#elif !defined(WIL_LOCK_EXCEPTION_MODE)
+#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together
+#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0")
+#elif defined(WIL_ENABLE_EXCEPTIONS)
+#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled
+#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1")
+#else
+#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions
+#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2")
+#endif
+
+#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS)
+#error Must enable exceptions when WIL_EXCEPTION_MODE == 1
+#endif
+
+// block for documentation only
+#if defined(WIL_DOXYGEN)
+/** This define can be explicitly set to disable exception usage within wil.
+Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking
+at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based
+classes and methods from WIL, define this macro ahead of including the first WIL header. */
+#define WIL_SUPPRESS_EXCEPTIONS
+
+/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS.
+Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to
+do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations
+when linking libraries together with different exception handling semantics. */
+#define WIL_LOCK_EXCEPTION_MODE
+
+/** This define explicit sets the exception mode for the process to control optimizations.
+Three exception modes are available:
+0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that
+ use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR
+ violations when linking libraries together with different exception handling semantics.
+1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled.
+2) This locks the binary to libraries built without exceptions. */
+#define WIL_EXCEPTION_MODE
+#endif
+
+#if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
+#define WIL_HAS_CXX_17 1
+#else
+#define WIL_HAS_CXX_17 0
+#endif
+
+// Until we'll have C++17 enabled in our code base, we're falling back to SAL
+#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE
+
+#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t::value, void*> = nullptr
+#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t::value, void*> = nullptr
+
+//! @defgroup bitwise Bitwise Inspection and Manipulation
+//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations.
+//! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist
+//! for two primary purposes:
+//!
+//! 1. To improve the readability of bitwise comparisons and manipulation.
+//!
+//! The macro names are the more concise, readable form of what's being done and do not require that any flags
+//! or variables be specified multiple times for the comparisons.
+//!
+//! 2. To reduce the error rate associated with bitwise operations.
+//!
+//! The readability improvements naturally lend themselves to this by cutting down the number of concepts.
+//! Using `WI_IsFlagSet(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison
+//! operator and repetition in the flag value.
+//!
+//! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag
+//! operations so that compile-time errors are generated for bitwise operations which are likely incorrect,
+//! such as: `WI_IsFlagSet(var, MyEnum::None)` or `WI_IsFlagSet(var, MyEnum::ValidMask)`.
+//!
+//! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These
+//! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers
+//! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants.
+//!
+//! Common example usage (manipulation of flag variables):
+//! ~~~~
+//! WI_SetFlag(m_flags, MyFlags::Foo); // Set a single flag in the given variable
+//! WI_SetAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags
+//! WI_ClearFlagIf(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool
+//! WI_ClearAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable
+//! WI_ToggleFlag(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag
+//! WI_UpdateFlag(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based upon a bool value
+//! WI_UpdateFlagsInMask(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values from newFlagValues
+//! ~~~~
+//! Common example usage (inspection of flag variables):
+//! ~~~~
+//! if (WI_IsFlagSet(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable?
+//! if (WI_IsAnyFlagSet(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set?
+//! if (WI_AreAllFlagsClear(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear?
+//! if (WI_IsSingleFlagSet(m_flags)) // Is *exactly* one flag set in the given variable?
+//! ~~~~
+//! @{
+
+//! Returns the unsigned type of the same width and numeric value as the given enum
+#define WI_EnumValue(val) static_cast<::wil::integral_from_enum>(val)
+//! Validates that exactly ONE bit is set in compile-time constant `flag`
+#define WI_StaticAssertSingleBitSet(flag) static_cast(::wil::details::verify_single_flag_helper(WI_EnumValue(flag))>::value)
+
+//! @name Bitwise manipulation macros
+//! @{
+
+//! Set zero or more bitflags specified by `flags` in the variable `var`.
+#define WI_SetAllFlags(var, flags) ((var) |= (flags))
+//! Set a single compile-time constant `flag` in the variable `var`.
+#define WI_SetFlag(var, flag) WI_SetAllFlags(var, WI_StaticAssertSingleBitSet(flag))
+//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true.
+#define WI_SetFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_SetFlag(var, flag); } } while ((void)0, 0)
+
+//! Clear zero or more bitflags specified by `flags` from the variable `var`.
+#define WI_ClearAllFlags(var, flags) ((var) &= ~(flags))
+//! Clear a single compile-time constant `flag` from the variable `var`.
+#define WI_ClearFlag(var, flag) WI_ClearAllFlags(var, WI_StaticAssertSingleBitSet(flag))
+//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true.
+#define WI_ClearFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_ClearFlag(var, flag); } } while ((void)0, 0)
+
+//! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet` is false.
+#define WI_UpdateFlag(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SetFlag(var, flag) : WI_ClearFlag(var, flag))
+//! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`.
+#define WI_UpdateFlagsInMask(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags)
+
+//! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`.
+#define WI_ToggleAllFlags(var, flags) ((var) ^= (flags))
+//! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`.
+#define WI_ToggleFlag(var, flag) WI_ToggleAllFlags(var, WI_StaticAssertSingleBitSet(flag))
+//! @} // bitwise manipulation macros
+
+//! @name Bitwise inspection macros
+//! @{
+
+//! Evaluates as true if every bitflag specified in `flags` is set within `val`.
+#define WI_AreAllFlagsSet(val, flags) wil::details::AreAllFlagsSetHelper(val, flags)
+//! Evaluates as true if one or more bitflags specified in `flags` are set within `val`.
+#define WI_IsAnyFlagSet(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast(0))
+//! Evaluates as true if a single compile-time constant `flag` is set within `val`.
+#define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag))
+
+//! Evaluates as true if every bitflag specified in `flags` is clear within `val`.
+#define WI_AreAllFlagsClear(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast(0))
+//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`.
+#define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags))
+//! Evaluates as true if a single compile-time constant `flag` is clear within `val`.
+#define WI_IsFlagClear(val, flag) WI_AreAllFlagsClear(val, WI_StaticAssertSingleBitSet(flag))
+
+//! Evaluates as true if exactly one bit (any bit) is set within `val`.
+#define WI_IsSingleFlagSet(val) wil::details::IsSingleFlagSetHelper(val)
+//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`.
+#define WI_IsSingleFlagSetInMask(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask))
+//! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`.
+#define WI_IsClearOrSingleFlagSet(val) wil::details::IsClearOrSingleFlagSetHelper(val)
+//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask` set within `val`.
+#define WI_IsClearOrSingleFlagSetInMask(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask))
+//! @}
+
+#if defined(WIL_DOXYGEN)
+/** This macro provides a C++ header with a guaranteed initialization function.
+Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw
+the object away if it's unreferenced (which throws away the side-effects that the initialization function
+was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the
+provided function to elide that optimization.
+//!
+This functionality is primarily provided as a building block for header-based libraries (such as WIL)
+to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models
+of initialization should be used whenever they are available.
+~~~~
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+WI_HEADER_INITITALIZATION_FUNCTION(InitializeDesktopFamilyApis, []
+{
+ g_pfnGetModuleName = GetCurrentModuleName;
+ g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout;
+ return 1;
+});
+#endif
+~~~~
+The above example is used within WIL to decide whether or not the library containing WIL is allowed to use
+desktop APIs. Building this functionality as #IFDEFs within functions would create ODR violations, whereas
+doing it with global function pointers and header initialization allows a runtime determination. */
+#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn)
+#elif defined(_M_IX86)
+#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \
+ extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \
+ __pragma(comment(linker, "/INCLUDE:_g_header_init_" #name))
+#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
+#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \
+ extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \
+ __pragma(comment(linker, "/INCLUDE:g_header_init_" #name))
+#else
+ #error linker pragma must include g_header_init variation
+#endif
+
+
+/** All Windows Implementation Library classes and functions are located within the "wil" namespace.
+The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference
+the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using
+statement for wil to avoid introducing potential name collisions between wil and other namespaces. */
+namespace wil
+{
+ /// @cond
+ namespace details
+ {
+ template
+ class pointer_range
+ {
+ public:
+ pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_) {}
+ T begin() const { return m_begin; }
+ T end() const { return m_end; }
+ private:
+ T m_begin;
+ T m_end;
+ };
+ }
+ /// @endcond
+
+ /** Enables using range-based for between a begin and end object pointer.
+ ~~~~
+ for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { }
+ ~~~~ */
+ template
+ details::pointer_range make_range(T begin, T end)
+ {
+ return details::pointer_range(begin, end);
+ }
+
+ /** Enables using range-based for on a range when given the base pointer and the number of objects in the range.
+ ~~~~
+ for (auto& obj : make_range(objPointer, objCount)) { }
+ ~~~~ */
+ template
+ details::pointer_range make_range(T begin, size_t count)
+ {
+ return details::pointer_range(begin, begin + count);
+ }
+
+
+ //! @defgroup outparam Output Parameters
+ //! Improve the conciseness of assigning values to optional output parameters.
+ //! @{
+
+ /** Assign the given value to an optional output parameter.
+ Makes code more concise by removing trivial `if (outParam)` blocks. */
+ template
+ inline void assign_to_opt_param(_Out_opt_ T *outParam, T val)
+ {
+ if (outParam != nullptr)
+ {
+ *outParam = val;
+ }
+ }
+
+ /** Assign NULL to an optional output pointer parameter.
+ Makes code more concise by removing trivial `if (outParam)` blocks. */
+ template
+ inline void assign_null_to_opt_param(_Out_opt_ T *outParam)
+ {
+ if (outParam != nullptr)
+ {
+ *outParam = nullptr;
+ }
+ }
+ //! @} // end output parameter helpers
+
+ /** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation.
+ Example usage:
+ ~~~~
+ template
+ struct FeatureRequiredBy
+ {
+ static const bool enabled = wil::variadic_logical_or::enabled...>::value;
+ };
+ ~~~~ */
+ template struct variadic_logical_or;
+ /// @cond
+ template <> struct variadic_logical_or<> : wistd::false_type { };
+ template struct variadic_logical_or : wistd::true_type { };
+ template struct variadic_logical_or : variadic_logical_or::type { };
+ /// @endcond
+
+ /// @cond
+ namespace details
+ {
+ template
+ struct verify_single_flag_helper
+ {
+ static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found");
+ static const unsigned long long value = flag;
+ };
+ }
+ /// @endcond
+
+
+ //! @defgroup typesafety Type Validation
+ //! Helpers to validate variable types to prevent accidental, but allowed type conversions.
+ //! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types accepted
+ //! prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional layer of type
+ //! safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in the error handling helper
+ //! macros to validate the types given to various macro parameters.
+ //! @{
+
+ /** Verify that `val` can be evaluated as a logical bool.
+ Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL,
+ boolean, BOOLEAN, and classes with an explicit bool cast.
+ @param val The logical bool expression
+ @return A C++ bool representing the evaluation of `val`. */
+ template
+ _Post_satisfies_(return == static_cast(val))
+ __forceinline constexpr bool verify_bool(const T& val)
+ {
+ return static_cast(val);
+ }
+
+ template
+ __forceinline constexpr bool verify_bool(T /*val*/)
+ {
+ static_assert(!wistd::is_same::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
+ return false;
+ }
+
+ template <>
+ _Post_satisfies_(return == val)
+ __forceinline constexpr bool verify_bool(bool val)
+ {
+ return val;
+ }
+
+ template <>
+ _Post_satisfies_(return == (val != 0))
+ __forceinline constexpr bool verify_bool(int val)
+ {
+ return (val != 0);
+ }
+
+ template <>
+ _Post_satisfies_(return == (val != 0))
+ __forceinline constexpr bool verify_bool(unsigned char val)
+ {
+ return (val != 0);
+ }
+
+ /** Verify that `val` is a Win32 BOOL value.
+ Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will
+ accept any `int` value as long as that is the underlying typedef behind `BOOL`.
+ @param val The Win32 BOOL returning expression
+ @return A Win32 BOOL representing the evaluation of `val`. */
+ template
+ _Post_satisfies_(return == val)
+ __forceinline constexpr int verify_BOOL(T val)
+ {
+ // Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL;
+ static_assert((wistd::is_same::value), "Wrong Type: BOOL expected");
+ return val;
+ }
+
+ /** Verify that `hr` is an HRESULT value.
+ Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
+ underlying typedef behind HRESULT.
+ //!
+ Note that occasionally you might run into an HRESULT which is directly defined with a #define, such as:
+ ~~~~
+ #define UIA_E_NOTSUPPORTED 0x80040204
+ ~~~~
+ Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When
+ these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
+ their definition to match the manner in which `HRESULT` constants are defined in winerror.h:
+ ~~~~
+ #define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
+ ~~~~
+ When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
+ to use this value in a macro that utilizes `verify_hresult`, for example:
+ ~~~~
+ RETURN_HR_IF(static_cast(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
+ ~~~~
+ @param hr The HRESULT returning expression
+ @return An HRESULT representing the evaluation of `val`. */
+ template
+ _Post_satisfies_(return == hr)
+ inline constexpr long verify_hresult(T hr)
+ {
+ // Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
+ static_assert(wistd::is_same::value, "Wrong Type: HRESULT expected");
+ return hr;
+ }
+
+ /** Verify that `status` is an NTSTATUS value.
+ Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
+ underlying typedef behind NTSTATUS.
+ //!
+ Note that occasionally you might run into an NTSTATUS which is directly defined with a #define, such as:
+ ~~~~
+ #define STATUS_NOT_SUPPORTED 0x1
+ ~~~~
+ Though this looks like an `NTSTATUS`, this is actually an `unsigned long` (the hex specification forces this). When
+ these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
+ their definition to match the manner in which `NTSTATUS` constants are defined in ntstatus.h:
+ ~~~~
+ #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
+ ~~~~
+ When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
+ to use this value in a macro that utilizes `verify_ntstatus`, for example:
+ ~~~~
+ NT_RETURN_IF_FALSE(static_cast(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0));
+ ~~~~
+ @param status The NTSTATUS returning expression
+ @return An NTSTATUS representing the evaluation of `val`. */
+ template
+ _Post_satisfies_(return == status)
+ inline long verify_ntstatus(T status)
+ {
+ // Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long NTSTATUS
+ static_assert(wistd::is_same::value, "Wrong Type: NTSTATUS expected");
+ return status;
+ }
+
+ /** Verify that `error` is a Win32 error code.
+ Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
+ the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type
+ commonly used when manipulating Win32 error codes.
+ @param error The Win32 error code returning expression
+ @return An Win32 error code representing the evaluation of `error`. */
+ template
+ _Post_satisfies_(return == error)
+ inline T verify_win32(T error)
+ {
+ // Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned long).
+ // This accept both types.
+ static_assert(wistd::is_same::value || wistd::is_same::value, "Wrong Type: Win32 error code (long / unsigned long) expected");
+ return error;
+ }
+ /// @} // end type validation routines
+
+ /// @cond
+ // Implementation details for macros and helper functions... do not use directly.
+ namespace details
+ {
+ // Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value
+ #define __WI_MAKE_UNSIGNED(val) \
+ (__pragma(warning(push)) __pragma(warning(disable: 4310 4309)) (sizeof(val) == 1 ? static_cast(val) : \
+ sizeof(val) == 2 ? static_cast(val) : \
+ sizeof(val) == 4 ? static_cast(val) : \
+ static_cast(val)) __pragma(warning(pop)))
+ #define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1)))
+ #define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val))
+
+ template
+ __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags)
+ {
+ return ((val & flags) == static_cast(flags));
+ }
+
+ template
+ __forceinline constexpr bool IsSingleFlagSetHelper(TVal val)
+ {
+ return __WI_IS_SINGLE_FLAG_SET(val);
+ }
+
+ template
+ __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val)
+ {
+ return ((val == static_cast>(0)) || IsSingleFlagSetHelper(val));
+ }
+
+ template
+ __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags)
+ {
+ val = static_cast>((val & ~mask) | (flags & mask));
+ }
+
+ template
+ struct variable_size;
+
+ template <>
+ struct variable_size<1>
+ {
+ using type = unsigned char;
+ };
+
+ template <>
+ struct variable_size<2>
+ {
+ using type = unsigned short;
+ };
+
+ template <>
+ struct variable_size<4>
+ {
+ using type = unsigned long;
+ };
+
+ template <>
+ struct variable_size<8>
+ {
+ using type = unsigned long long;
+ };
+
+ template
+ struct variable_size_mapping
+ {
+ using type = typename variable_size::type;
+ };
+ } // details
+ /// @endcond
+
+ /** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type.
+ This allows code to generically convert any enum class to it's corresponding underlying type. */
+ template
+ using integral_from_enum = typename details::variable_size_mapping::type;
+
+ //! Declares a name that intentionally hides a name from an outer scope.
+ //! Use this to prevent accidental use of a parameter or lambda captured variable.
+ using hide_name = void(struct hidden_name);
+} // wil
+
+#pragma warning(pop)
+
+#endif // __cplusplus
+#endif // __WIL_COMMON_INCLUDED
diff --git a/RtEthSample/configuration.cpp b/RtEthSample/configuration.cpp
index 35ae800..b0aaac7 100644
--- a/RtEthSample/configuration.cpp
+++ b/RtEthSample/configuration.cpp
@@ -39,7 +39,6 @@ RT_ADVANCED_PROPERTY RtSupportedProperties[] =
{ NDIS_STRING_CONST("*WakeOnMagicPacket"), RT_OFFSET(WakeOnMagicPacketEnabled), RT_SIZE(WakeOnMagicPacketEnabled), true, false, true },
{ NDIS_STRING_CONST("*InterruptModeration"), RT_OFFSET(InterruptModerationMode), RT_SIZE(InterruptModerationMode), RtInterruptModerationEnabled, RtInterruptModerationDisabled, RtInterruptModerationEnabled },
{ NDIS_STRING_CONST("*FlowControl"), RT_OFFSET(FlowControl), RT_SIZE(FlowControl), RtFlowControlTxRxEnabled, RtFlowControlDisabled, RtFlowControlTxRxEnabled },
- { NDIS_STRING_CONST("*RSS"), RT_OFFSET(RssEnabled), RT_SIZE(RssEnabled), false, false, true },
// Custom Keywords
{ NDIS_STRING_CONST("InterruptModerationLevel"), RT_OFFSET(InterruptModerationLevel), RT_SIZE(InterruptModerationLevel), RtInterruptModerationLow, RtInterruptModerationLow, RtInterruptModerationMedium },
diff --git a/RtEthSample/interrupt.cpp b/RtEthSample/interrupt.cpp
index bf94654..1ff80cb 100644
--- a/RtEthSample/interrupt.cpp
+++ b/RtEthSample/interrupt.cpp
@@ -368,7 +368,7 @@ EvtInterruptDpc(
{
if (InterlockedExchange(&interrupt->TxNotifyArmed, false))
{
- NetTxQueueNotifyMoreCompletedPacketsAvailable(adapter->TxQueue);
+ NetTxQueueNotifyMoreCompletedPacketsAvailable(adapter->TxQueues[0]);
}
}
diff --git a/RtEthSample/interrupt.h b/RtEthSample/interrupt.h
index c7a0618..dfba186 100644
--- a/RtEthSample/interrupt.h
+++ b/RtEthSample/interrupt.h
@@ -17,19 +17,19 @@ typedef struct _RT_INTERRUPT
WDFINTERRUPT Handle;
// Armed Notifications
- LONG RxNotifyArmed[RT_NUMBER_OF_QUEUES];
+ LONG RxNotifyArmed[RT_NUMBER_OF_RX_QUEUES];
LONG TxNotifyArmed;
union {
volatile UINT16 * Address16;
volatile UINT8 * Address8;
- } Isr[RT_NUMBER_OF_QUEUES];
+ } Isr[RT_NUMBER_OF_RX_QUEUES];
union {
volatile UINT16 * Address16;
volatile UINT8 * Address8;
- } Imr[RT_NUMBER_OF_QUEUES];
+ } Imr[RT_NUMBER_OF_RX_QUEUES];
// Fired Notificiations
// Tracks un-served ISR interrupt fields. Masks in only
@@ -40,7 +40,7 @@ typedef struct _RT_INTERRUPT
ULONG64 NumInterrupts;
ULONG64 NumInterruptsNotOurs;
ULONG64 NumInterruptsDisabled;
- ULONG64 NumRxInterrupts[RT_NUMBER_OF_QUEUES];
+ ULONG64 NumRxInterrupts[RT_NUMBER_OF_RX_QUEUES];
ULONG64 NumTxInterrupts;
} RT_INTERRUPT;
diff --git a/RtEthSample/precomp.h b/RtEthSample/precomp.h
index 69a962f..08c263b 100644
--- a/RtEthSample/precomp.h
+++ b/RtEthSample/precomp.h
@@ -14,14 +14,16 @@
#include
#include
#include
-#include
-#include
+#include
+#include
#include
#include
#include
-#include
+#include
#include
+#include
+#include
// Avoid putting user headers into the precomp header.
// Exceptions here include:
diff --git a/RtEthSample/rt_def.h b/RtEthSample/rt_def.h
index eae2a75..3b3ab0d 100644
--- a/RtEthSample/rt_def.h
+++ b/RtEthSample/rt_def.h
@@ -17,8 +17,6 @@
#pragma once
-#pragma region Bit Definitions
-
#define BIT_0 0x0001
#define BIT_1 0x0002
#define BIT_2 0x0004
@@ -52,10 +50,6 @@
#define BIT_30 0x40000000
#define BIT_31 0x80000000
-#pragma endregion
-
-#pragma region Standards Limits
-
#define FRAME_CRC_SIZE 4
#define VLAN_HEADER_SIZE 4
#define RSVD_BUF_SIZE 8
@@ -63,10 +57,6 @@
// Ethernet Frame Sizes
#define ETHERNET_ADDRESS_LENGTH 6
-#pragma endregion
-
-#pragma region Hardware Limits
-
// packet and header sizes
#define RT_MAX_PACKET_SIZE (1514)
#define RT_MAX_FRAME_SIZE (RT_MAX_PACKET_SIZE + VLAN_HEADER_SIZE + FRAME_CRC_SIZE)
@@ -77,10 +67,6 @@
// Phy related constants
#define PHY_RESET_TIME (1250 * 4) // (1250 * 4 *100 = 500000) phy reset should complete within 500ms (from spec)
-#pragma endregion
-
-#pragma region Software Limits
-
// max number of physical fragments supported per TCB
#define RT_MAX_PHYS_BUF_COUNT 16
@@ -96,18 +82,10 @@
// compact receive scaling indirection table
#define RT_INDIRECTION_TABLE_SIZE 8
-#pragma endregion
-
-#pragma region Error Codes
-
// Error log definitions
#define ERRLOG_OUT_OF_SG_RESOURCES 0x00000409L
#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L
-#pragma endregion
-
-#pragma region Capabilities
-
// supported filters
#define RT_SUPPORTED_FILTERS ( \
NetPacketFilterFlagDirected | \
@@ -116,11 +94,8 @@
NetPacketFilterFlagPromiscuous | \
NetPacketFilterFlagAllMulticast)
-#define RT_NUMBER_OF_QUEUES 4
-
-#pragma endregion
-
-#pragma region Hardware Memory Descriptors
+#define RT_NUMBER_OF_TX_QUEUES 2
+#define RT_NUMBER_OF_RX_QUEUES 4
typedef struct _RT_TAG_802_1Q
{
@@ -184,10 +159,6 @@ typedef struct _RT_TALLY
USHORT TxUndrn; //only possible on jumbo frames
} RT_TALLY;
-#pragma endregion
-
-#pragma region Control Block
-
#pragma pack(1)
//-------------------------------------------------------------------------
@@ -350,10 +321,6 @@ static_assert(sizeof(RT_MAC) == 0x100, "Size of RT_MAC is specified by hardware"
#pragma pack()
-#pragma endregion
-
-#pragma region Register Constants
-
// MulticastReg7: 0x8
#define MAX_NIC_MULTICAST_REG 8
@@ -369,6 +336,7 @@ static_assert(sizeof(RT_MAC) == 0x100, "Size of RT_MAC is specified by hardware"
// TPPoll: 0x38
#define TPPoll_NPQ 0x40 // normal priority queue polling
+#define TPPoll_HPQ 0x80 // high priority queue polling
// IMR: 0x3C, ISR: 0x3E
#define ISRIMR_ROK BIT_0
@@ -504,10 +472,6 @@ typedef enum _RT_PHY_REG
#define CPCR_INT_MITI_TIMER_UNIT_0 BIT_0
#define CPCR_DISABLE_INT_MITI_PKT_NUM BIT_7
-#pragma endregion
-
-#pragma region Descriptor Constants
-
// Receive status
#define RXS_OWN BIT_15
#define RXS_EOR BIT_14
@@ -534,6 +498,10 @@ typedef enum _RT_PHY_REG
#define RXS_UDPF BIT_1
#define RXS_TCPF BIT_0
+#define RXS_IPV6RSS_RSS_IPV4 BIT_1
+#define RXS_IPV6RSS_RSS_IPV6 BIT_2
+#define RXS_IPV6RSS_RSS_TCP BIT_3
+
// receive extended status
#define RXS_IPV6RSS_IS_IPV6 BIT_15
#define RXS_IPV6RSS_IS_IPV4 BIT_14
@@ -581,4 +549,3 @@ typedef enum _RT_PHY_REG
#define RSS_MULTI_CPU_ENABLE (1<<16)
#define RSS_MULTI_CPU_DISABLE (0)
-#pragma endregion
diff --git a/RtEthSample/rtk.rc b/RtEthSample/rtk.rc
index 46cf8dc..72fc1a3 100644
--- a/RtEthSample/rtk.rc
+++ b/RtEthSample/rtk.rc
@@ -1,54 +1,54 @@
-/*++
-
- THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- PARTICULAR PURPOSE.
-
- Copyright (c) Microsoft Corporation. All rights reserved
-
-Module Name:
-
-rtk.rc
-
-Abstract:
-
-Internal resource file for filter.
-
---*/
-
-#include "windows.h"
-#include "ntverp.h"
-
-//
-// the spaces characters in string are reserved for patch tool
-//
-
-#define VER_FILETYPE VFT_DRV
-#define VER_FILESUBTYPE VFT2_DRV_NETWORK
-
-#define VER_FILEDESCRIPTION_STR "Realtek PCIe GBE Family Controller NetAdapter Sample Driver"
-
-#define VER_INTERNALNAME_STR "RtEthSample.sys"
-#define VER_ORIGINALFILENAME_STR "RtEthSample.sys"
-
-#define VER_FILEVERSION 1,0
-#define VER_FILEVERSION_STR "1.0"
-
-#undef VER_PRODUCTVERSION
-#define VER_PRODUCTVERSION VER_FILEVERSION
-
-#undef VER_PRODUCTVERSION_STR
-#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
-
-#define VER_LEGALCOPYRIGHT_STR "Copyright (c) Microsoft Corporation. All rights reserved."
-
-#undef VER_COMPANYNAME_STR
-#define VER_COMPANYNAME_STR "Realtek"
-
-#undef VER_PRODUCTNAME_STR
-#define VER_PRODUCTNAME_STR "Realtek PCIe GBE Family Adapters"
-
-#define VER_LANGNEUTRAL
-
-#include "common.ver"
+/*++
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+ ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+ PARTICULAR PURPOSE.
+
+ Copyright (c) Microsoft Corporation. All rights reserved
+
+Module Name:
+
+rtk.rc
+
+Abstract:
+
+Internal resource file for filter.
+
+--*/
+
+#include "windows.h"
+#include "ntverp.h"
+
+//
+// the spaces characters in string are reserved for patch tool
+//
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+
+#define VER_FILEDESCRIPTION_STR "Realtek PCIe GBE Family Controller NetAdapter Sample Driver"
+
+#define VER_INTERNALNAME_STR "RtEthSample.sys"
+#define VER_ORIGINALFILENAME_STR "RtEthSample.sys"
+
+#define VER_FILEVERSION 1,0
+#define VER_FILEVERSION_STR "1.0"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (c) Microsoft Corporation. All rights reserved."
+
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Realtek"
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Realtek PCIe GBE Family Adapters"
+
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
diff --git a/RtEthSample/rxqueue.cpp b/RtEthSample/rxqueue.cpp
index 19b3a26..2fb403a 100644
--- a/RtEthSample/rxqueue.cpp
+++ b/RtEthSample/rxqueue.cpp
@@ -11,6 +11,8 @@
#include "precomp.h"
+#include "common.h"
+
#include "device.h"
#include "rxqueue.h"
#include "trace.h"
@@ -18,33 +20,6 @@
#include "interrupt.h"
#include "gigamac.h"
-#include "netringiterator.h"
-
-void
-RtUpdateRecvStats(
- _In_ RT_RXQUEUE *rx,
- _In_ RT_RX_DESC const *rxd,
- ULONG length
- )
-{
- // Unlike for Tx, the hardware has counters for Broadcast, Multicast,
- // and Unicast inbound packets. So, we defer to the hardware counter for
- // # of Rx transmissions.
-
- if (rxd->RxDescDataIpv6Rss.status & RXS_BAR)
- {
- rx->Adapter->InBroadcastOctets += length;
- }
- else if (rxd->RxDescDataIpv6Rss.status & RXS_MAR)
- {
- rx->Adapter->InMulticastOctets += length;
- }
- else
- {
- rx->Adapter->InUcastOctets += length;
- }
-}
-
static
void
RxFillRtl8111DChecksumInfo(
@@ -60,7 +35,6 @@ RxFillRtl8111DChecksumInfo(
&rx->ChecksumExtension,
packetIndex);
- packet->Layout.Layer2Type = NetPacketLayer2TypeEthernet;
checksumInfo->Layer2 =
(rxd->RxDescDataIpv6Rss.status & RXS_CRC)
? NetPacketRxChecksumEvaluationInvalid
@@ -75,7 +49,7 @@ RxFillRtl8111DChecksumInfo(
{
packet->Layout.Layer3Type = NetPacketLayer3TypeIPv4UnspecifiedOptions;
- if (adapter->IpHwChkSum)
+ if (adapter->RxIpHwChkSum)
{
checksumInfo->Layer3 =
(rxd->RxDescDataIpv6Rss.status & RXS_IPF)
@@ -101,7 +75,7 @@ RxFillRtl8111DChecksumInfo(
{
packet->Layout.Layer4Type = NetPacketLayer4TypeTcp;
- if (adapter->TcpHwChkSum)
+ if (adapter->RxTcpHwChkSum)
{
checksumInfo->Layer4 =
(rxd->RxDescDataIpv6Rss.IpRssTava & RXS_IPV6RSS_TCPF)
@@ -113,7 +87,7 @@ RxFillRtl8111DChecksumInfo(
{
packet->Layout.Layer4Type = NetPacketLayer4TypeUdp;
- if (adapter->UdpHwChkSum)
+ if (adapter->RxUdpHwChkSum)
{
checksumInfo->Layer4 =
(rxd->RxDescDataIpv6Rss.IpRssTava & RXS_IPV6RSS_UDPF)
@@ -138,7 +112,6 @@ RxFillRtl8111EChecksumInfo(
&rx->ChecksumExtension,
packetIndex);
- packet->Layout.Layer2Type = NetPacketLayer2TypeEthernet;
checksumInfo->Layer2 =
(rxd->RxDescDataIpv6Rss.status & RXS_CRC)
? NetPacketRxChecksumEvaluationInvalid
@@ -153,7 +126,7 @@ RxFillRtl8111EChecksumInfo(
{
packet->Layout.Layer3Type = NetPacketLayer3TypeIPv4UnspecifiedOptions;
- if (adapter->IpHwChkSum)
+ if (adapter->RxIpHwChkSum)
{
checksumInfo->Layer3 =
(rxd->RxDescDataIpv6Rss.status & RXS_IPF)
@@ -179,7 +152,7 @@ RxFillRtl8111EChecksumInfo(
{
packet->Layout.Layer4Type = NetPacketLayer4TypeTcp;
- if (adapter->TcpHwChkSum)
+ if (adapter->RxTcpHwChkSum)
{
checksumInfo->Layer4 =
(rxd->RxDescDataIpv6Rss.TcpUdpFailure & TXS_TCPCS)
@@ -191,7 +164,7 @@ RxFillRtl8111EChecksumInfo(
{
packet->Layout.Layer4Type = NetPacketLayer4TypeUdp;
- if (adapter->UdpHwChkSum)
+ if (adapter->RxUdpHwChkSum)
{
checksumInfo->Layer4 =
(rxd->RxDescDataIpv6Rss.TcpUdpFailure & TXS_UDPCS)
@@ -224,56 +197,121 @@ RtFillRxChecksumInfo(
}
}
+static
+void
+RtFillReceiveScalingInfo(
+ _In_ RT_RXQUEUE const *rx,
+ _In_ RT_RX_DESC const *rxd,
+ _In_ UINT32 packetIndex
+ )
+{
+ NET_PACKET_HASH * hash =
+ NetExtensionGetPacketHash(
+ &rx->HashValueExtension,
+ packetIndex);
+
+ hash->ProtocolType = NetPacketHashProtocolTypeNone;
+ hash->HashValue = 0;
+
+ if (WI_IsFlagSet(rxd->RxDescDataIpv6Rss.IpRssTava, RXS_IPV6RSS_RSS_IPV4))
+ {
+ WI_SetFlag(hash->ProtocolType, NetPacketHashProtocolTypeIPv4);
+
+ if (WI_IsFlagSet(rxd->RxDescDataIpv6Rss.IpRssTava, RXS_IPV6RSS_RSS_TCP))
+ {
+ WI_SetFlag(hash->ProtocolType, NetPacketHashProtocolTypeTcp);
+ }
+ }
+
+ if (WI_IsFlagSet(rxd->RxDescDataIpv6Rss.IpRssTava, RXS_IPV6RSS_RSS_IPV6))
+ {
+ WI_SetFlag(hash->ProtocolType, NetPacketHashProtocolTypeIPv6);
+
+ if (WI_IsFlagSet(rxd->RxDescDataIpv6Rss.IpRssTava, RXS_IPV6RSS_RSS_TCP))
+ {
+ WI_SetFlag(hash->ProtocolType, NetPacketHashProtocolTypeTcp);
+ }
+ }
+
+ if (hash->ProtocolType)
+ {
+ auto fr = NetRingCollectionGetFragmentRing(rx->Rings);
+
+ auto fragmentVirtualAddress = NetExtensionGetFragmentVirtualAddress(&rx->VirtualAddressExtension, fr->BeginIndex);
+ auto hashValueAddress = reinterpret_cast(fragmentVirtualAddress->VirtualAddress) + rxd->RxDescDataIpv6Rss.length;
+ hashValueAddress += 3; // reversed
+
+ auto hashValue = reinterpret_cast(&hash->HashValue);
+ *hashValue++ = *hashValueAddress--;
+ *hashValue++ = *hashValueAddress--;
+ *hashValue++ = *hashValueAddress--;
+ *hashValue = *hashValueAddress;
+ }
+}
+
void
RxIndicateReceives(
_In_ RT_RXQUEUE *rx
)
{
- NET_RING_FRAGMENT_ITERATOR fi = NetRingGetDrainFragments(rx->Rings);
- NET_RING_PACKET_ITERATOR pi = NetRingGetAllPackets(rx->Rings);
- while (NetFragmentIteratorHasAny(&fi))
+ NET_RING * pr = NetRingCollectionGetPacketRing(rx->Rings);
+ NET_RING * fr = NetRingCollectionGetFragmentRing(rx->Rings);
+
+ while (fr->BeginIndex != fr->NextIndex)
{
- UINT32 index = NetFragmentIteratorGetIndex(&fi);
- RT_RX_DESC const * rxd = &rx->RxdBase[index];
+ UINT32 const fragmentIndex = fr->BeginIndex;
+ RT_RX_DESC const * rxd = &rx->RxdBase[fragmentIndex];
if (0 != (rxd->RxDescDataIpv6Rss.status & RXS_OWN))
break;
- NET_FRAGMENT * fragment = NetFragmentIteratorGetFragment(&fi);
+ if (pr->BeginIndex == pr->EndIndex)
+ break;
+
+ // If there is a packet available we are guaranteed to have a fragment as well
+ NT_FRE_ASSERT(fr->BeginIndex != fr->EndIndex);
+
+ NET_FRAGMENT * fragment = NetRingGetFragmentAtIndex(fr, fragmentIndex);
fragment->ValidLength = rxd->RxDescDataIpv6Rss.length - FRAME_CRC_SIZE;
+ fragment->Capacity = fragment->ValidLength;
fragment->Offset = 0;
- NET_PACKET * packet = NetPacketIteratorGetPacket(&pi);
- packet->FragmentIndex = index;
+ // Link fragment and packet
+ UINT32 const packetIndex = pr->BeginIndex;
+ NET_PACKET* packet = NetRingGetPacketAtIndex(pr, packetIndex);
+ packet->FragmentIndex = fragmentIndex;
packet->FragmentCount = 1;
if (rx->ChecksumExtension.Enabled)
{
// fill packetTcpChecksum
- RtFillRxChecksumInfo(rx, rxd, NetPacketIteratorGetIndex(&pi), packet);
+ RtFillRxChecksumInfo(rx, rxd, packetIndex, packet);
+ }
+
+ if (rx->HashValueExtension.Enabled && rx->Adapter->RssEnabled)
+ {
+ // fill packet hash value
+ RtFillReceiveScalingInfo(rx, rxd, packetIndex);
}
- RtUpdateRecvStats(rx, rxd, fragment->ValidLength);
+ packet->Layout.Layer2Type = NetPacketLayer2TypeEthernet;
- NetFragmentIteratorAdvance(&fi);
- NetPacketIteratorAdvance(&pi);
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+ fr->BeginIndex = NetRingIncrementIndex(fr, fr->BeginIndex);
}
- NetFragmentIteratorSet(&fi);
- NetPacketIteratorSet(&pi);
}
static
void
RtPostRxDescriptor(
_In_ RT_RX_DESC * desc,
- _In_ NET_FRAGMENT const * fragment,
_In_ NET_FRAGMENT_LOGICAL_ADDRESS const * logicalAddress,
_In_ UINT16 status
)
{
desc->BufferAddress = logicalAddress->LogicalAddress;
desc->RxDescDataIpv6Rss.TcpUdpFailure = 0;
- desc->RxDescDataIpv6Rss.length = fragment->Capacity;
+ desc->RxDescDataIpv6Rss.length = RT_MAX_FRAME_SIZE;
desc->RxDescDataIpv6Rss.VLAN_TAG.Value = 0;
MemoryBarrier();
@@ -288,21 +326,17 @@ RxPostBuffers(
)
{
NET_RING * fr = NetRingCollectionGetFragmentRing(rx->Rings);
- NET_RING_FRAGMENT_ITERATOR fi = NetRingGetPostFragments(rx->Rings);
- while (NetFragmentIteratorHasAny(&fi))
+ while (fr->NextIndex != fr->EndIndex)
{
- UINT32 const index = NetFragmentIteratorGetIndex(&fi);
- NET_FRAGMENT_LOGICAL_ADDRESS const * logicalAddress = NetExtensionGetFragmentLogicalAddress(
- &rx->LogicalAddressExtension, index);
+ UINT32 const index = fr->NextIndex;
RtPostRxDescriptor(&rx->RxdBase[index],
- NetFragmentIteratorGetFragment(&fi),
- logicalAddress,
+ NetExtensionGetFragmentLogicalAddress(&rx->LogicalAddressExtension, index),
RXS_OWN | (fr->ElementIndexMask == index ? RXS_EOR : 0));
- NetFragmentIteratorAdvance(&fi);
+
+ fr->NextIndex = NetRingIncrementIndex(fr, fr->NextIndex);
}
- NetFragmentIteratorSet(&fi);
}
NTSTATUS
@@ -425,7 +459,7 @@ EvtRxQueueStop(
WdfSpinLockAcquire(rx->Adapter->Lock);
- bool count = 0;
+ size_t count = 0;
for (size_t i = 0; i < ARRAYSIZE(rx->Adapter->RxQueues); i++)
{
if (rx->Adapter->RxQueues[i])
@@ -516,17 +550,18 @@ EvtRxQueueCancel(
// after cancel until all packets are returned to the framework.
RxIndicateReceives(rx);
- NET_RING_PACKET_ITERATOR pi = NetRingGetAllPackets(rx->Rings);
- while(NetPacketIteratorHasAny(&pi))
+ NET_RING * pr = NetRingCollectionGetPacketRing(rx->Rings);
+
+ while (pr->BeginIndex != pr->EndIndex)
{
- NetPacketIteratorGetPacket(&pi)->Ignore = 1;
- NetPacketIteratorAdvance(&pi);
+ NET_PACKET * packet = NetRingGetPacketAtIndex(pr, pr->BeginIndex);
+ packet->Ignore = 1;
+
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
}
- NetPacketIteratorSet(&pi);
- NET_RING_FRAGMENT_ITERATOR fi = NetRingGetAllFragments(rx->Rings);
- NetFragmentIteratorAdvanceToTheEnd(&fi);
- NetFragmentIteratorSet(&fi);
+ NET_RING * fr = NetRingCollectionGetFragmentRing(rx->Rings);
+ fr->BeginIndex = fr->EndIndex;
TraceExit();
}
diff --git a/RtEthSample/rxqueue.h b/RtEthSample/rxqueue.h
index baa941e..ac295db 100644
--- a/RtEthSample/rxqueue.h
+++ b/RtEthSample/rxqueue.h
@@ -23,7 +23,9 @@ struct RT_RXQUEUE
size_t RxdSize;
NET_EXTENSION ChecksumExtension;
+ NET_EXTENSION VirtualAddressExtension;
NET_EXTENSION LogicalAddressExtension;
+ NET_EXTENSION HashValueExtension;
ULONG QueueId;
};
diff --git a/RtEthSample/txqueue.cpp b/RtEthSample/txqueue.cpp
index f4ed95e..d3634c2 100644
--- a/RtEthSample/txqueue.cpp
+++ b/RtEthSample/txqueue.cpp
@@ -16,60 +16,8 @@
#include "trace.h"
#include "adapter.h"
#include "interrupt.h"
-
#include "netringiterator.h"
-void
-RtUpdateSendStats(
- _In_ RT_TXQUEUE * tx,
- _In_ NET_RING_PACKET_ITERATOR const * pi
- )
-{
- NET_PACKET const * packet = NetPacketIteratorGetPacket(pi);
- if (packet->Layout.Layer2Type != NetPacketLayer2TypeEthernet)
- {
- return;
- }
-
- NET_RING_FRAGMENT_ITERATOR fi = NetPacketIteratorGetFragments(pi);
- NET_FRAGMENT const * fragment = NetFragmentIteratorGetFragment(&fi);
- NET_FRAGMENT_VIRTUAL_ADDRESS const * virtualAddress = NetExtensionGetFragmentVirtualAddress(
- &tx->VirtualAddressExtension, packet->FragmentIndex);
- // Ethernet header should be in first fragment
- if (fragment->ValidLength < sizeof(ETHERNET_HEADER))
- {
- return;
- }
-
- PUCHAR ethHeader = (PUCHAR)virtualAddress->VirtualAddress + fragment->Offset;
-
- ULONG length = 0;
- while (NetFragmentIteratorHasAny(&fi))
- {
- fragment = NetFragmentIteratorGetFragment(&fi);
- length += (ULONG)fragment->ValidLength;
- NetFragmentIteratorAdvance(&fi);
- }
-
- RT_ADAPTER *adapter = tx->Adapter;
-
- if (ETH_IS_BROADCAST(ethHeader))
- {
- adapter->OutBroadcastPkts++;
- adapter->OutBroadcastOctets += length;
- }
- else if (ETH_IS_MULTICAST(ethHeader))
- {
- adapter->OutMulticastPkts++;
- adapter->OutMulticastOctets += length;
- }
- else
- {
- adapter->OutUCastPkts++;
- adapter->OutUCastOctets += length;
- }
-}
-
static
USHORT
RtGetPacketLsoStatusSetting(
@@ -80,6 +28,10 @@ RtGetPacketLsoStatusSetting(
packet->Layout.Layer2HeaderLength +
packet->Layout.Layer3HeaderLength;
+ NT_ASSERT(packet->Layout.Layer2HeaderLength != 0U);
+ NT_ASSERT(packet->Layout.Layer3HeaderLength != 0U);
+ NT_ASSERT(layer4HeaderOffset < 0xff);
+
if (NetPacketIsIpv4(packet))
{
return TXS_IPV6RSS_GTSEN_IPV4 | (USHORT)(layer4HeaderOffset << TXS_IPV4RSS_TCPHDR_OFFSET);
@@ -99,7 +51,7 @@ RtGetPacketLsoMss(
_In_ UINT32 packetIndex
)
{
- return NetExtensionGetPacketLso(extension, packetIndex)->TCP.Mss;
+ return NetExtensionGetPacketGso(extension, packetIndex)->TCP.Mss;
}
static
@@ -118,6 +70,17 @@ RtGetPacketChecksumSetting(
// Prioritize layer4 checksum first
if (checksumInfo->Layer4 == NetPacketTxChecksumActionRequired)
{
+
+ const USHORT layer4HeaderOffset =
+ packet->Layout.Layer2HeaderLength +
+ packet->Layout.Layer3HeaderLength;
+
+ UNREFERENCED_PARAMETER(layer4HeaderOffset);
+
+ NT_ASSERT(packet->Layout.Layer2HeaderLength != 0U);
+ NT_ASSERT(packet->Layout.Layer3HeaderLength != 0U);
+ NT_ASSERT(layer4HeaderOffset < 0xff);
+
if (packet->Layout.Layer4Type == NetPacketLayer4TypeTcp)
{
return TXS_IPV6RSS_TCPCS | TXS_IPV6RSS_IPV4CS;
@@ -146,6 +109,10 @@ RtGetPacketChecksumSetting(
packet->Layout.Layer2HeaderLength +
packet->Layout.Layer3HeaderLength;
+ NT_ASSERT(packet->Layout.Layer2HeaderLength != 0U);
+ NT_ASSERT(packet->Layout.Layer3HeaderLength != 0U);
+ NT_ASSERT(layer4HeaderOffset < 0xff);
+
if (packet->Layout.Layer4Type == NetPacketLayer4TypeTcp)
{
return TXS_IPV6RSS_TCPCS | TXS_IPV6RSS_IS_IPV6 |
@@ -180,15 +147,37 @@ RtProgramOffloadDescriptor(
txd->TxDescDataIpv6Rss_All.OffloadGsoMssTagc = 0;
RT_ADAPTER const * adapter = tx->Adapter;
- auto const lsoEnabled = tx->LsoExtension.Enabled &&
- (adapter->LSOv4 == RtLsoOffloadEnabled || adapter->LSOv6 == RtLsoOffloadEnabled);
+ auto const lsoEnabled = tx->GsoExtension.Enabled &&
+ (adapter->LSOv4 == RtGsoOffloadEnabled || adapter->LSOv6 == RtGsoOffloadEnabled);
auto const checksumEnabled = tx->ChecksumExtension.Enabled &&
- (adapter->TcpHwChkSum || adapter->IpHwChkSum || adapter->UdpHwChkSum);
+ (adapter->TxTcpHwChkSum || adapter->TxIpHwChkSum || adapter->TxUdpHwChkSum);
+
+ auto const ieee8021qEnabled = tx->Ieee8021qExtension.Enabled;
+
+ if (ieee8021qEnabled)
+ {
+ txd->TxDescDataIpv6Rss_All.OffloadGsoMssTagc |= TXS_IPV6RSS_TAGC;
+
+ auto const ieee8021q = NetExtensionGetPacketIeee8021Q(&tx->Ieee8021qExtension, packetIndex);
+
+ if (ieee8021q->TxTagging & NetPacketTxIeee8021qActionFlagPriorityRequired)
+ {
+ txd->TxDescDataIpv6Rss_All.VLAN_TAG.TagHeader.Priority = ieee8021q->PriorityCodePoint;
+ }
+
+ if (ieee8021q->TxTagging & NetPacketTxIeee8021qActionFlagVlanRequired)
+ {
+ auto const vlan = ieee8021q->VlanIdentifier;
+
+ txd->TxDescDataIpv6Rss_All.VLAN_TAG.TagHeader.VLanID2 = vlan & 0xFF;
+ txd->TxDescDataIpv6Rss_All.VLAN_TAG.TagHeader.VLanID1 = (vlan >> 8) & 0xF;
+ }
+ }
if (packet->Layout.Layer4Type == NetPacketLayer4TypeTcp && lsoEnabled)
{
- auto const mss = RtGetPacketLsoMss(&tx->LsoExtension, packetIndex);
+ auto const mss = RtGetPacketLsoMss(&tx->GsoExtension, packetIndex);
if (mss > 0)
{
status |= RtGetPacketLsoStatusSetting(packet);
@@ -263,7 +252,8 @@ RtFlushTransation(
)
{
MemoryBarrier();
- *tx->TPPoll = TPPoll_NPQ;
+
+ *tx->TPPoll = tx->Priority;
}
static
@@ -304,7 +294,6 @@ RtIsPacketTransferComplete(
txd->TxDescDataIpv6Rss_All.status = 0;
NetFragmentIteratorAdvance(&fi);
}
- RtUpdateSendStats(tx, pi);
fi.Iterator.Rings->Rings[NetRingTypeFragment]->BeginIndex
= NetFragmentIteratorGetIndex(&fi);
}
@@ -478,15 +467,25 @@ EvtTxQueueStart(
PHYSICAL_ADDRESS pa = WdfCommonBufferGetAlignedLogicalAddress(tx->TxdArray);
- // let hardware know where transmit descriptors are at
- adapter->CSRAddress->TNPDSLow = pa.LowPart;
- adapter->CSRAddress->TNPDSHigh = pa.HighPart;
+ switch (tx->Priority)
+ {
+ case TPPoll_NPQ:
+ adapter->CSRAddress->TNPDSLow = pa.LowPart;
+ adapter->CSRAddress->TNPDSHigh = pa.HighPart;
+ break;
+
+ case TPPoll_HPQ:
+ adapter->CSRAddress->THPDSLow = pa.LowPart;
+ adapter->CSRAddress->THPDSHigh = pa.HighPart;
+ break;
+ }
+ // XXX we need to only enable TE on "last" queue
adapter->CSRAddress->CmdReg |= CR_TE;
// data sheet says TCR should only be modified after the transceiver is enabled
adapter->CSRAddress->TCR = (TCR_RCR_MXDMA_UNLIMITED << TCR_MXDMA_OFFSET) | (TCR_IFG0 | TCR_IFG1 | TCR_BIT0);
- adapter->TxQueue = txQueue;
+ adapter->TxQueues[tx->QueueId] = txQueue;
WdfSpinLockRelease(adapter->Lock);
}
@@ -501,10 +500,22 @@ EvtTxQueueStop(
WdfSpinLockAcquire(tx->Adapter->Lock);
- tx->Adapter->CSRAddress->CmdReg &= ~CR_TE;
+ size_t count = 0;
+ for (size_t i = 0; i < ARRAYSIZE(tx->Adapter->TxQueues); i++)
+ {
+ if (tx->Adapter->TxQueues[i] != WDF_NO_HANDLE)
+ {
+ count++;
+ }
+ }
+
+ if (1 == count)
+ {
+ tx->Adapter->CSRAddress->CmdReg &= ~CR_TE;
+ RtTxQueueSetInterrupt(tx, false);
+ }
- RtTxQueueSetInterrupt(tx, false);
- tx->Adapter->TxQueue = WDF_NO_HANDLE;
+ tx->Adapter->TxQueues[tx->QueueId] = WDF_NO_HANDLE;
WdfSpinLockRelease(tx->Adapter->Lock);
}
diff --git a/RtEthSample/txqueue.h b/RtEthSample/txqueue.h
index ca30f80..1494b9a 100644
--- a/RtEthSample/txqueue.h
+++ b/RtEthSample/txqueue.h
@@ -40,9 +40,13 @@ typedef struct _RT_TXQUEUE
UCHAR volatile *TPPoll;
NET_EXTENSION ChecksumExtension;
- NET_EXTENSION LsoExtension;
+ NET_EXTENSION GsoExtension;
NET_EXTENSION VirtualAddressExtension;
NET_EXTENSION LogicalAddressExtension;
+ NET_EXTENSION Ieee8021qExtension;
+
+ ULONG QueueId;
+ UINT8 Priority;
} RT_TXQUEUE;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RT_TXQUEUE, RtGetTxQueueContext);
diff --git a/RtEthSample/wistd_config.h b/RtEthSample/wistd_config.h
new file mode 100644
index 0000000..128f0d6
--- /dev/null
+++ b/RtEthSample/wistd_config.h
@@ -0,0 +1,571 @@
+// -*- C++ -*-
+//===--------------------------- __config ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// STL common functionality
+//
+// Some aspects of STL are core language concepts that should be used from all C++ code, regardless
+// of whether exceptions are enabled in the component. Common library code that expects to be used
+// from exception-free components want these concepts, but including STL headers directly introduces
+// friction as it requires components not using STL to declare their STL version. Doing so creates
+// ambiguity around whether STL use is safe in a particular component and implicitly brings in
+// a long list of headers (including ) which can create further ambiguity around throwing new
+// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has
+// the potential to create naming conflicts or other implied dependencies.
+//
+// To promote the use of these core language concepts outside of STL-based binaries, this file is
+// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding
+// "std::" namespace STL functions and types should be preferred over these in code that is bound to
+// STL. The implementation and naming of all functions are taken directly from STL, instead using
+// "wistd" (Windows Implementation std) as the namespace.
+//
+// Routines in this namespace should always be considered a reflection of the *current* STL implementation
+// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here.
+//
+// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation.
+// Only code that is not exception-based and libraries that expect to be utilized across both exception
+// and non-exception based code should utilize this functionality.
+
+// This header mimics libc++'s '__config' header to the extent necessary to get the wistd::* definitions compiling. Note
+// that this has a few key differences since libc++'s MSVC compatability is currently not functional and a bit behind
+
+#ifndef _WISTD_CONFIG_H_
+#define _WISTD_CONFIG_H_
+
+// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
+#include // For size_t and other necessary types
+
+/// @cond
+#if defined(_MSC_VER) && !defined(__clang__)
+# if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# define __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+# endif
+#endif
+
+#ifndef __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+#pragma GCC system_header
+#endif
+
+#ifdef __GNUC__
+# define __WI_GNUC_VER (__GNUC__ * 100 + __GNUC_MINOR__)
+// The __WI_GNUC_VER_NEW macro better represents the new GCC versioning scheme
+// introduced in GCC 5.0.
+# define __WI_GNUC_VER_NEW (__WI_GNUC_VER * 10 + __GNUC_PATCHLEVEL__)
+#else
+# define __WI_GNUC_VER 0
+# define __WI_GNUC_VER_NEW 0
+#endif
+
+// _MSVC_LANG is the more accurate way to get the C++ version in MSVC
+#if defined(_MSVC_LANG) && (_MSVC_LANG > __cplusplus)
+#define __WI_CPLUSPLUS _MSVC_LANG
+#else
+#define __WI_CPLUSPLUS __cplusplus
+#endif
+
+#ifndef __WI_LIBCPP_STD_VER
+# if __WI_CPLUSPLUS <= 201103L
+# define __WI_LIBCPP_STD_VER 11
+# elif __WI_CPLUSPLUS <= 201402L
+# define __WI_LIBCPP_STD_VER 14
+# elif __WI_CPLUSPLUS <= 201703L
+# define __WI_LIBCPP_STD_VER 17
+# else
+# define __WI_LIBCPP_STD_VER 18 // current year, or date of c++2a ratification
+# endif
+#endif // __WI_LIBCPP_STD_VER
+
+#if __WI_CPLUSPLUS < 201103L
+#define __WI_LIBCPP_CXX03_LANG
+#endif
+
+#if defined(__ELF__)
+# define __WI_LIBCPP_OBJECT_FORMAT_ELF 1
+#elif defined(__MACH__)
+# define __WI_LIBCPP_OBJECT_FORMAT_MACHO 1
+#elif defined(_WIN32)
+# define __WI_LIBCPP_OBJECT_FORMAT_COFF 1
+#elif defined(__wasm__)
+# define __WI_LIBCPP_OBJECT_FORMAT_WASM 1
+#else
+# error Unknown object file format
+#endif
+
+#if defined(__clang__)
+# define __WI_LIBCPP_COMPILER_CLANG
+#elif defined(__GNUC__)
+# define __WI_LIBCPP_COMPILER_GCC
+#elif defined(_MSC_VER)
+# define __WI_LIBCPP_COMPILER_MSVC
+#elif defined(__IBMCPP__)
+# define __WI_LIBCPP_COMPILER_IBM
+#endif
+
+#if defined(__WI_LIBCPP_COMPILER_MSVC)
+#define __WI_PUSH_WARNINGS __pragma(warning(push))
+#define __WI_POP_WARNINGS __pragma(warning(pop))
+#elif defined(__WI_LIBCPP_COMPILER_CLANG)
+#define __WI_PUSH_WARNINGS __pragma(clang diagnostic push)
+#define __WI_POP_WARNINGS __pragma(clang diagnostic pop)
+#else
+#define __WI_PUSH_WARNINGS
+#define __WI_POP_WARNINGS
+#endif
+
+#ifdef __WI_LIBCPP_COMPILER_MSVC
+#define __WI_MSVC_DISABLE_WARNING(id) __pragma(warning(disable: id))
+#else
+#define __WI_MSVC_DISABLE_WARNING(id)
+#endif
+
+#ifdef __WI_LIBCPP_COMPILER_CLANG
+#define __WI_CLANG_DISABLE_WARNING(warning) __pragma(clang diagnostic ignored #warning)
+#else
+#define __WI_CLANG_DISABLE_WARNING(warning)
+#endif
+
+// NOTE: MSVC, which is what we primarily target, is severly underrepresented in libc++ and checks such as
+// __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we
+// instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls
+// back to the __has_feature(...), etc. value otherwise. We intentionally leave '__has_feature', etc. undefined for MSVC
+// so that we don't accidentally use the incorrect behavior
+#ifndef __WI_LIBCPP_COMPILER_MSVC
+
+#ifndef __has_feature
+#define __has_feature(__x) 0
+#endif
+
+// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
+// the compiler and '1' otherwise.
+#ifndef __is_identifier
+#define __is_identifier(__x) 1
+#endif
+
+#ifndef __has_cpp_attribute
+#define __has_cpp_attribute(__x) 0
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(__x) 0
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(__x) 0
+#endif
+
+#if __has_feature(cxx_alignas)
+# define __WI_ALIGNAS_TYPE(x) alignas(x)
+# define __WI_ALIGNAS(x) alignas(x)
+#else
+# define __WI_ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x))))
+# define __WI_ALIGNAS(x) __attribute__((__aligned__(x)))
+#endif
+
+#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \
+ (!defined(__WI_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions
+# define __WI_LIBCPP_EXPLICIT explicit
+#else
+# define __WI_LIBCPP_EXPLICIT
+#endif
+
+#if __has_feature(cxx_attributes)
+# define __WI_LIBCPP_NORETURN [[noreturn]]
+#else
+# define __WI_LIBCPP_NORETURN __attribute__ ((noreturn))
+#endif
+
+#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
+#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS
+
+// The __WI_LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other
+// NODISCARD macros to the correct attribute.
+#if __has_cpp_attribute(nodiscard)
+# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]]
+#elif defined(__WI_LIBCPP_COMPILER_CLANG) && !defined(__WI_LIBCPP_CXX03_LANG)
+# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]]
+#else
+// We can't use GCC's [[gnu::warn_unused_result]] and
+// __attribute__((warn_unused_result)), because GCC does not silence them via
+// (void) cast.
+# define __WI_LIBCPP_NODISCARD_ATTRIBUTE
+#endif
+
+#define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union)
+#define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class)
+#define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum)
+#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to)
+#define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty)
+#define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic)
+#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor)
+#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS __has_feature(cxx_reference_qualified_functions)
+#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE __has_feature(is_constructible)
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE __has_feature(is_trivially_constructible)
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE __has_feature(is_trivially_assignable)
+#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR __has_feature(has_trivial_destructor)
+#define __WI_HAS_FEATURE_NOEXCEPT __has_feature(cxx_noexcept)
+#define __WI_HAS_FEATURE_IS_POD __has_feature(is_pod)
+#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT __has_feature(is_standard_layout)
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE __has_feature(is_trivially_copyable)
+#define __WI_HAS_FEATURE_IS_TRIVIAL __has_feature(is_trivial)
+#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR __has_feature(has_trivial_constructor) || (__WI_GNUC_VER >= 403)
+#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR __has_feature(has_nothrow_constructor) || (__WI_GNUC_VER >= 403)
+#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403)
+#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403)
+
+#if !(__has_feature(cxx_noexcept))
+#define __WI_LIBCPP_HAS_NO_NOEXCEPT
+#endif
+
+#if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700
+#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS
+#endif
+
+#if !(__has_feature(cxx_variadic_templates))
+#define __WI_LIBCPP_HAS_NO_VARIADICS
+#endif
+
+#if __has_feature(is_literal) || __WI_GNUC_VER >= 407
+#define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T)
+#endif
+
+#if __has_feature(underlying_type) || __WI_GNUC_VER >= 407
+#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T)
+#endif
+
+#if __has_feature(is_final) || __WI_GNUC_VER >= 407
+#define __WI_LIBCPP_HAS_IS_FINAL
+#endif
+
+#if __has_feature(is_base_of) || defined(__GNUC__) && __WI_GNUC_VER >= 403
+#define __WI_LIBCPP_HAS_IS_BASE_OF
+#endif
+
+#if __is_identifier(__is_aggregate) && (__WI_GNUC_VER_NEW < 7001)
+#define __WI_LIBCPP_HAS_NO_IS_AGGREGATE
+#endif
+
+#if !(__has_feature(cxx_rtti)) && !defined(__WI_LIBCPP_NO_RTTI)
+#define __WI_LIBCPP_NO_RTTI
+#endif
+
+#if !(__has_feature(cxx_variable_templates))
+#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
+#endif
+
+#if !(__has_feature(cxx_relaxed_constexpr))
+#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR
+#endif
+
+#if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700
+#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
+#endif
+
+#if __has_attribute(__no_sanitize__) && !defined(__WI_LIBCPP_COMPILER_GCC)
+# define __WI_LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi")))
+#else
+# define __WI_LIBCPP_NO_CFI
+#endif
+
+#define __WI_LIBCPP_ALWAYS_INLINE __attribute__ ((__always_inline__))
+
+#if __has_attribute(internal_linkage)
+# define __WI_LIBCPP_INTERNAL_LINKAGE __attribute__ ((internal_linkage))
+#else
+# define __WI_LIBCPP_INTERNAL_LINKAGE __WI_LIBCPP_ALWAYS_INLINE
+#endif
+
+#else
+
+// NOTE: Much of the following assumes a decently recent version of MSVC. Past versions can be supported, but will need
+// to be updated to contain the proper _MSC_VER check
+#define __WI_ALIGNAS_TYPE(x) alignas(x)
+#define __WI_ALIGNAS(x) alignas(x)
+#define __alignof__ __alignof
+
+#define __WI_LIBCPP_EXPLICIT explicit
+#define __WI_LIBCPP_NORETURN [[noreturn]]
+#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495))
+#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439))
+
+
+#if __WI_LIBCPP_STD_VER > 14
+#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]]
+#else
+#define __WI_LIBCPP_NODISCARD_ATTRIBUTE _Check_return_
+#endif
+
+#define __WI_HAS_FEATURE_IS_UNION 1
+#define __WI_HAS_FEATURE_IS_CLASS 1
+#define __WI_HAS_FEATURE_IS_ENUM 1
+#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 1
+#define __WI_HAS_FEATURE_IS_EMPTY 1
+#define __WI_HAS_FEATURE_IS_POLYMORPHIC 1
+#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR 1
+#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
+#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS 1
+#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE 1
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE 1
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE 1
+#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR 1
+#define __WI_HAS_FEATURE_NOEXCEPT 1
+#define __WI_HAS_FEATURE_IS_POD 1
+#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT 1
+#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE 1
+#define __WI_HAS_FEATURE_IS_TRIVIAL 1
+#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR 1
+#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR 1
+#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY 1
+#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN 1
+#define __WI_HAS_FEATURE_IS_DESTRUCTIBLE 1
+
+#if !defined(_CPPRTTI) && !defined(__WI_LIBCPP_NO_RTTI)
+#define __WI_LIBCPP_NO_RTTI
+#endif
+
+#define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T)
+#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T)
+#define __WI_LIBCPP_HAS_IS_FINAL
+#define __WI_LIBCPP_HAS_IS_BASE_OF
+
+#if __WI_LIBCPP_STD_VER < 14
+#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
+#endif
+
+#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
+#define __WI_LIBCPP_NO_CFI
+
+#define __WI_LIBCPP_ALWAYS_INLINE __forceinline
+#define __WI_LIBCPP_INTERNAL_LINKAGE
+
+#endif
+
+#ifndef _WIN32
+
+#ifdef __LITTLE_ENDIAN__
+# if __LITTLE_ENDIAN__
+# define __WI_LIBCPP_LITTLE_ENDIAN
+# endif // __LITTLE_ENDIAN__
+#endif // __LITTLE_ENDIAN__
+
+#ifdef __BIG_ENDIAN__
+# if __BIG_ENDIAN__
+# define __WI_LIBCPP_BIG_ENDIAN
+# endif // __BIG_ENDIAN__
+#endif // __BIG_ENDIAN__
+
+#ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define __WI_LIBCPP_LITTLE_ENDIAN
+# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define __WI_LIBCPP_BIG_ENDIAN
+# endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#endif // __BYTE_ORDER__
+
+#if !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN)
+# include
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# define __WI_LIBCPP_LITTLE_ENDIAN
+# elif __BYTE_ORDER == __BIG_ENDIAN
+# define __WI_LIBCPP_BIG_ENDIAN
+# else // __BYTE_ORDER == __BIG_ENDIAN
+# error unable to determine endian
+# endif
+#endif // !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN)
+
+#else // _WIN32
+
+#define __WI_LIBCPP_LITTLE_ENDIAN
+
+#endif // _WIN32
+
+#ifdef __WI_LIBCPP_HAS_NO_CONSTEXPR
+# define __WI_LIBCPP_CONSTEXPR
+#else
+# define __WI_LIBCPP_CONSTEXPR constexpr
+#endif
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr
+#else
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+#endif
+
+#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr
+#else
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14
+#endif
+
+#if __WI_LIBCPP_STD_VER > 17 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr
+#else
+# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17
+#endif
+
+#if !defined(__WI_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && \
+ (__WI_LIBCPP_STD_VER > 17 || defined(__WI_LIBCPP_ENABLE_NODISCARD))
+# define __WI_LIBCPP_NODISCARD_AFTER_CXX17 __WI_LIBCPP_NODISCARD_ATTRIBUTE
+#else
+# define __WI_LIBCPP_NODISCARD_AFTER_CXX17
+#endif
+
+#if __WI_LIBCPP_STD_VER > 14 && defined(__cpp_inline_variables) && (__cpp_inline_variables >= 201606L)
+# define __WI_LIBCPP_INLINE_VAR inline
+#else
+# define __WI_LIBCPP_INLINE_VAR
+#endif
+
+#ifdef __WI_LIBCPP_CXX03_LANG
+#define __WI_LIBCPP_HAS_NO_UNICODE_CHARS
+#define __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif
+
+#ifndef __SIZEOF_INT128__
+#define __WI_LIBCPP_HAS_NO_INT128
+#endif
+
+#if !__WI_HAS_FEATURE_NOEXCEPT && !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT)
+#define __WI_LIBCPP_HAS_NO_NOEXCEPT
+#endif
+
+#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT
+# define WI_NOEXCEPT noexcept
+# define __WI_NOEXCEPT_(x) noexcept(x)
+#else
+# define WI_NOEXCEPT throw()
+# define __WI_NOEXCEPT_(x)
+#endif
+
+#if defined(__WI_LIBCPP_OBJECT_FORMAT_COFF)
+#define __WI_LIBCPP_HIDDEN
+#define __WI_LIBCPP_TEMPLATE_VIS
+#endif // defined(__WI_LIBCPP_OBJECT_FORMAT_COFF)
+
+#ifndef __WI_LIBCPP_HIDDEN
+# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
+# define __WI_LIBCPP_HIDDEN __attribute__ ((__visibility__("hidden")))
+# else
+# define __WI_LIBCPP_HIDDEN
+# endif
+#endif
+
+#ifndef __WI_LIBCPP_TEMPLATE_VIS
+# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !defined(__WI_LIBCPP_COMPILER_MSVC)
+# if __has_attribute(__type_visibility__)
+# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__type_visibility__("default")))
+# else
+# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__visibility__("default")))
+# endif
+# else
+# define __WI_LIBCPP_TEMPLATE_VIS
+# endif
+#endif
+
+#define __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_HIDDEN __WI_LIBCPP_INTERNAL_LINKAGE
+
+namespace wistd // ("Windows Implementation" std)
+{
+ using nullptr_t = decltype(__nullptr);
+
+ template
+ struct __less
+ {
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
+
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T1& __x, const _T2& __y) const {return __x < __y;}
+
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T2& __x, const _T1& __y) const {return __x < __y;}
+
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T2& __x, const _T2& __y) const {return __x < __y;}
+ };
+
+ template
+ struct __less<_T1, _T1>
+ {
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
+ };
+
+ template
+ struct __less
+ {
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
+ };
+
+ template
+ struct __less<_T1, const _T1>
+ {
+ __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
+ };
+
+ // These are added to wistd to enable use of min/max without having to use the windows.h min/max
+ // macros that some clients might not have access to. Note: the STL versions of these have debug
+ // checking for the less than operator and support for iterators that these implementations lack.
+ // Use the STL versions when you require use of those features.
+
+ // min
+
+ template
+ inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ const _Tp&
+ (min)(const _Tp& __a, const _Tp& __b, _Compare __comp)
+ {
+ return __comp(__b, __a) ? __b : __a;
+ }
+
+ template
+ inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ const _Tp&
+ (min)(const _Tp& __a, const _Tp& __b)
+ {
+ return (min)(__a, __b, __less<_Tp>());
+ }
+
+ // max
+
+ template
+ inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ const _Tp&
+ (max)(const _Tp& __a, const _Tp& __b, _Compare __comp)
+ {
+ return __comp(__a, __b) ? __b : __a;
+ }
+
+ template
+ inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
+ const _Tp&
+ (max)(const _Tp& __a, const _Tp& __b)
+ {
+ return (max)(__a, __b, __less<_Tp>());
+ }
+
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS unary_function
+ {
+ using argument_type = _Arg;
+ using result_type = _Result;
+ };
+
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS binary_function
+ {
+ using first_argument_type = _Arg1;
+ using second_argument_type = _Arg2;
+ using result_type = _Result;
+ };
+}
+/// @endcond
+
+#endif // _WISTD_CONFIG_H_
diff --git a/RtEthSample/wistd_type_traits.h b/RtEthSample/wistd_type_traits.h
new file mode 100644
index 0000000..8f757ed
--- /dev/null
+++ b/RtEthSample/wistd_type_traits.h
@@ -0,0 +1,4504 @@
+// -*- C++ -*-
+//===------------------------ type_traits ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// STL common functionality
+//
+// Some aspects of STL are core language concepts that should be used from all C++ code, regardless
+// of whether exceptions are enabled in the component. Common library code that expects to be used
+// from exception-free components want these concepts, but including directly introduces
+// friction as it requires components not using STL to declare their STL version. Doing so creates
+// ambiguity around whether STL use is safe in a particular component and implicitly brings in
+// a long list of headers (including ) which can create further ambiguity around throwing new
+// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has
+// the potential to create naming conflicts or other implied dependencies.
+//
+// To promote the use of these core language concepts outside of STL-based binaries, this file is
+// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding
+// "std::" namespace STL functions and types should be preferred over these in code that is bound to
+// STL. The implementation and naming of all functions are taken directly from STL, instead using
+// "wistd" (Windows Implementation std) as the namespace.
+//
+// Routines in this namespace should always be considered a reflection of the *current* STL implementation
+// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here.
+//
+// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation.
+// Only code that is not exception-based and libraries that expect to be utilized across both exception
+// and non-exception based code should utilize this functionality.
+
+#ifndef _WISTD_TYPE_TRAITS_H_
+#define _WISTD_TYPE_TRAITS_H_
+
+// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
+#include "wistd_config.h"
+
+#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+/// @cond
+namespace wistd // ("Windows Implementation" std)
+{
+ template struct __WI_LIBCPP_TEMPLATE_VIS pair;
+ template class __WI_LIBCPP_TEMPLATE_VIS reference_wrapper;
+ template struct __WI_LIBCPP_TEMPLATE_VIS hash;
+
+ template
+ struct __void_t { typedef void type; };
+
+ template
+ struct __identity { typedef _Tp type; };
+
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {};
+
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _If type;};
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _Then type;};
+
+#if __WI_LIBCPP_STD_VER > 11
+ template using conditional_t = typename conditional<_Bp, _If, _Then>::type;
+#endif
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {typedef typename _Tp::type type;};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {typedef _Tp type;};
+
+#if __WI_LIBCPP_STD_VER > 11
+ template using enable_if_t = typename enable_if<_Bp, _Tp>::type;
+#endif
+
+ // addressof
+#ifndef __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
+
+ template
+ inline __WI_LIBCPP_CONSTEXPR_AFTER_CXX14
+ __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY
+ _Tp*
+ addressof(_Tp& __x) WI_NOEXCEPT
+ {
+ return __builtin_addressof(__x);
+ }
+
+#else
+
+ template
+ inline __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY
+ _Tp*
+ addressof(_Tp& __x) WI_NOEXCEPT
+ {
+ return reinterpret_cast<_Tp *>(
+ const_cast(&reinterpret_cast(__x)));
+ }
+
+#endif // __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
+
+#if !defined(__WI_LIBCPP_CXX03_LANG)
+ template _Tp* addressof(const _Tp&&) WI_NOEXCEPT = delete;
+#endif
+
+ struct __two {char __lx[2];};
+
+ // helper class:
+
+ template
+ struct __WI_LIBCPP_TEMPLATE_VIS integral_constant
+ {
+ static __WI_LIBCPP_CONSTEXPR const _Tp value = __v;
+ typedef _Tp value_type;
+ typedef integral_constant type;
+ __WI_LIBCPP_INLINE_VISIBILITY
+ __WI_LIBCPP_CONSTEXPR operator value_type() const WI_NOEXCEPT {return value;}
+#if __WI_LIBCPP_STD_VER > 11
+ __WI_LIBCPP_INLINE_VISIBILITY
+ constexpr value_type operator ()() const WI_NOEXCEPT {return value;}
+#endif
+ };
+
+ template
+ __WI_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;
+
+#if !defined(__WI_LIBCPP_CXX03_LANG)
+ template
+ using bool_constant = integral_constant;
+#define __WI_LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)>
+#else
+#define __WI_LIBCPP_BOOL_CONSTANT(__b) integral_constant
+#endif
+
+ typedef __WI_LIBCPP_BOOL_CONSTANT(true) true_type;
+ typedef __WI_LIBCPP_BOOL_CONSTANT(false) false_type;
+
+#if !defined(__WI_LIBCPP_CXX03_LANG)
+
+ // __lazy_and
+
+ template
+ struct __lazy_and_impl;
+
+ template
+ struct __lazy_and_impl : false_type {};
+
+ template <>
+ struct __lazy_and_impl : true_type {};
+
+ template
+ struct __lazy_and_impl : integral_constant {};
+
+ template
+ struct __lazy_and_impl : __lazy_and_impl<_Hp::type::value, _Tp...> {};
+
+ template
+ struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {};
+
+ // __lazy_or
+
+ template
+ struct __lazy_or_impl;
+
+ template
+ struct __lazy_or_impl : true_type {};
+
+ template <>
+ struct __lazy_or_impl : false_type {};
+
+ template
+ struct __lazy_or_impl
+ : __lazy_or_impl<_Hp::type::value, _Tp...> {};
+
+ template
+ struct __lazy_or : __lazy_or_impl<_P1::type::value, _Pr...> {};
+
+ // __lazy_not
+
+ template
+ struct __lazy_not : integral_constant {};
+
+ // __and_
+ template struct __and_;
+ template<> struct __and_<> : true_type {};
+
+ template struct __and_<_B0> : _B0 {};
+
+ template
+ struct __and_<_B0, _B1> : conditional<_B0::value, _B1, _B0>::type {};
+
+ template
+ struct __and_<_B0, _B1, _B2, _Bn...>
+ : conditional<_B0::value, __and_<_B1, _B2, _Bn...>, _B0>::type {};
+
+ // __or_
+ template struct __or_;
+ template<> struct __or_<> : false_type {};
+
+ template struct __or_<_B0> : _B0 {};
+
+ template
+ struct __or_<_B0, _B1> : conditional<_B0::value, _B0, _B1>::type {};
+
+ template
+ struct __or_<_B0, _B1, _B2, _Bn...>
+ : conditional<_B0::value, _B0, __or_<_B1, _B2, _Bn...> >::type {};
+
+ // __not_
+ template
+ struct __not_ : conditional<_Tp::value, false_type, true_type>::type {};
+
+#endif // !defined(__WI_LIBCPP_CXX03_LANG)
+
+ // is_const
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_const : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_const_v
+ = is_const<_Tp>::value;
+#endif
+
+ // is_volatile
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile<_Tp volatile> : public true_type {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_volatile_v
+ = is_volatile<_Tp>::value;
+#endif
+
+ // remove_const
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;};
+ template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;};
+#if __WI_LIBCPP_STD_VER > 11
+ template using remove_const_t = typename remove_const<_Tp>::type;
+#endif
+
+ // remove_volatile
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;};
+ template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;};
+#if __WI_LIBCPP_STD_VER > 11
+ template using remove_volatile_t = typename remove_volatile<_Tp>::type;
+#endif
+
+ // remove_cv
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS remove_cv
+ {typedef typename remove_volatile::type>::type type;};
+#if __WI_LIBCPP_STD_VER > 11
+ template using remove_cv_t = typename remove_cv<_Tp>::type;
+#endif
+
+ // is_void
+
+ template struct __libcpp_is_void : public false_type {};
+ template <> struct __libcpp_is_void : public true_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_void
+ : public __libcpp_is_void::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v
+ = is_void<_Tp>::value;
+#endif
+
+ // __is_nullptr_t
+
+ template struct __is_nullptr_t_impl : public false_type {};
+ template <> struct __is_nullptr_t_impl : public true_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t
+ : public __is_nullptr_t_impl::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer
+ : public __is_nullptr_t_impl::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_null_pointer_v
+ = is_null_pointer<_Tp>::value;
+#endif
+#endif
+
+ // is_integral
+
+ template struct __libcpp_is_integral : public false_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+#ifdef _MSC_VER
+ template <> struct __libcpp_is_integral<__wchar_t> : public true_type {};
+#else
+ template <> struct __libcpp_is_integral : public true_type {};
+#endif
+#ifndef __WI_LIBCPP_HAS_NO_UNICODE_CHARS
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+#endif // __WI_LIBCPP_HAS_NO_UNICODE_CHARS
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+ template <> struct __libcpp_is_integral : public true_type {};
+#ifndef __WI_LIBCPP_HAS_NO_INT128
+ template <> struct __libcpp_is_integral<__int128_t> : public true_type {};
+ template <> struct __libcpp_is_integral<__uint128_t> : public true_type {};
+#endif
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_integral
+ : public __libcpp_is_integral::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_integral_v
+ = is_integral<_Tp>::value;
+#endif
+
+ // is_floating_point
+
+ template struct __libcpp_is_floating_point : public false_type {};
+ template <> struct __libcpp_is_floating_point : public true_type {};
+ template <> struct __libcpp_is_floating_point : public true_type {};
+ template <> struct __libcpp_is_floating_point : public true_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_floating_point
+ : public __libcpp_is_floating_point::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_floating_point_v
+ = is_floating_point<_Tp>::value;
+#endif
+
+ // is_array
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_array
+ : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[]>
+ : public true_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[_Np]>
+ : public true_type {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_array_v
+ = is_array<_Tp>::value;
+#endif
+
+ // is_pointer
+
+ template struct __libcpp_is_pointer : public false_type {};
+ template struct __libcpp_is_pointer<_Tp*> : public true_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_pointer
+ : public __libcpp_is_pointer::type> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pointer_v
+ = is_pointer<_Tp>::value;
+#endif
+
+ // is_reference
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference<_Tp&> : public true_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference : public false_type {};
+#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference<_Tp&&> : public true_type {};
+#endif
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_reference : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&> : public true_type {};
+#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&&> : public true_type {};
+#endif
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_reference_v
+ = is_reference<_Tp>::value;
+
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_lvalue_reference_v
+ = is_lvalue_reference<_Tp>::value;
+
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_rvalue_reference_v
+ = is_rvalue_reference<_Tp>::value;
+#endif
+ // is_union
+
+#if __WI_HAS_FEATURE_IS_UNION || (__WI_GNUC_VER >= 403)
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_union
+ : public integral_constant {};
+
+#else
+
+ template struct __libcpp_union : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_union
+ : public __libcpp_union::type> {};
+
+#endif
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_union_v
+ = is_union<_Tp>::value;
+#endif
+
+ // is_class
+
+#if __WI_HAS_FEATURE_IS_CLASS || (__WI_GNUC_VER >= 403)
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_class
+ : public integral_constant {};
+
+#else
+
+ namespace __is_class_imp
+ {
+ template char __test(int _Tp::*);
+ template __two __test(...);
+ }
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_class
+ : public integral_constant(0)) == 1 && !is_union<_Tp>::value> {};
+
+#endif
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_class_v
+ = is_class<_Tp>::value;
+#endif
+
+ // is_same
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_same : public false_type {};
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_same<_Tp, _Tp> : public true_type {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template
+ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_same_v
+ = is_same<_Tp, _Up>::value;
+#endif
+
+ // is_function
+
+ namespace __libcpp_is_function_imp
+ {
+ struct __dummy_type {};
+ template char __test(_Tp*);
+ template char __test(__dummy_type);
+ template __two __test(...);
+ template _Tp& __source(int);
+ template __dummy_type __source(...);
+ }
+
+ template ::value ||
+ is_union<_Tp>::value ||
+ is_void<_Tp>::value ||
+ is_reference<_Tp>::value ||
+ __is_nullptr_t<_Tp>::value >
+ struct __libcpp_is_function
+ : public integral_constant(__libcpp_is_function_imp::__source<_Tp>(0))) == 1>
+ {};
+ template struct __libcpp_is_function<_Tp, true> : public false_type {};
+
+ template struct __WI_LIBCPP_TEMPLATE_VIS is_function
+ : public __libcpp_is_function<_Tp> {};
+
+#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES)
+ template