diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index 926ebf3580..c9de00df6d 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -928,6 +928,9 @@
Interop\Windows\Sni\SniNativeWrapper.cs
+
+ Interop\Windows\Sni\SniSslProtocols.cs
+
Interop\Windows\Sni\TransparentNetworkResolutionMode.cs
@@ -973,12 +976,13 @@
Microsoft\Data\SqlClient\TdsParserStateObjectFactory.Windows.cs
+
+ Microsoft\Data\SqlClient\TdsParserStateObjectNative.Windows.cs
+
Microsoft\Data\SqlTypes\SqlFileStream.Windows.cs
-
-
ILLink.Substitutions.xml
Resources\ILLink.Substitutions.Windows.xml
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs
deleted file mode 100644
index a553b43dde..0000000000
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs
+++ /dev/null
@@ -1,554 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Net;
-using System.Runtime.InteropServices;
-using System.Security.Authentication;
-using System.Threading.Tasks;
-using Interop.Windows.Sni;
-using Microsoft.Data.Common;
-using Microsoft.Data.ProviderBase;
-
-namespace Microsoft.Data.SqlClient
-{
- internal class TdsParserStateObjectNative : TdsParserStateObject
- {
- // protocol versions from native sni
- [Flags]
- private enum NativeProtocols
- {
- SP_PROT_SSL2_SERVER = 0x00000004,
- SP_PROT_SSL2_CLIENT = 0x00000008,
- SP_PROT_SSL3_SERVER = 0x00000010,
- SP_PROT_SSL3_CLIENT = 0x00000020,
- SP_PROT_TLS1_0_SERVER = 0x00000040,
- SP_PROT_TLS1_0_CLIENT = 0x00000080,
- SP_PROT_TLS1_1_SERVER = 0x00000100,
- SP_PROT_TLS1_1_CLIENT = 0x00000200,
- SP_PROT_TLS1_2_SERVER = 0x00000400,
- SP_PROT_TLS1_2_CLIENT = 0x00000800,
- SP_PROT_TLS1_3_SERVER = 0x00001000,
- SP_PROT_TLS1_3_CLIENT = 0x00002000,
- SP_PROT_NONE = 0x0
- }
-
- private SNIHandle _sessionHandle = null; // the SNI handle we're to work on
-
- private SNIPacket _sniPacket = null; // Will have to re-vamp this for MARS
- internal SNIPacket _sniAsyncAttnPacket = null; // Packet to use to send Attn
- private readonly WritePacketCache _writePacketCache = new WritePacketCache(); // Store write packets that are ready to be re-used
-
- private GCHandle _gcHandle; // keeps this object alive until we're closed.
-
- private readonly Dictionary _pendingWritePackets = new Dictionary(); // Stores write packets that have been sent to SNI, but have not yet finished writing (i.e. we are waiting for SNI's callback)
-
- internal TdsParserStateObjectNative(TdsParser parser, TdsParserStateObject physicalConnection, bool async)
- : base(parser, physicalConnection, async)
- {
- }
-
- internal TdsParserStateObjectNative(TdsParser parser)
- : base(parser)
- {
- }
-
- #region Properties
-
- internal SNIHandle Handle => _sessionHandle;
-
- internal override uint Status => _sessionHandle != null ? _sessionHandle.Status : TdsEnums.SNI_UNINITIALIZED;
-
- internal override SessionHandle SessionHandle => SessionHandle.FromNativeHandle(_sessionHandle);
-
- protected override PacketHandle EmptyReadPacket => PacketHandle.FromNativePointer(default);
-
- internal override Guid? SessionId => default;
-
- #endregion
-
- protected override void CreateSessionHandle(TdsParserStateObject physicalConnection, bool async)
- {
- Debug.Assert(physicalConnection is TdsParserStateObjectNative, "Expected a stateObject of type " + this.GetType());
- TdsParserStateObjectNative nativeSNIObject = physicalConnection as TdsParserStateObjectNative;
- ConsumerInfo myInfo = CreateConsumerInfo(async);
-
- SQLDNSInfo cachedDNSInfo;
- bool ret = SQLFallbackDNSCache.Instance.GetDNSInfo(_parser.FQDNforDNSCache, out cachedDNSInfo);
-
- _sessionHandle = new SNIHandle(myInfo, nativeSNIObject.Handle, _parser.Connection.ConnectionOptions.IPAddressPreference, cachedDNSInfo);
- }
-
- // Retrieve the IP and port number from native SNI for TCP protocol. The IP information is stored temporarily in the
- // pendingSQLDNSObject but not in the DNS Cache at this point. We only add items to the DNS Cache after we receive the
- // IsSupported flag as true in the feature ext ack from server.
- internal override void AssignPendingDNSInfo(string userProtocol, string DNSCacheKey, ref SQLDNSInfo pendingDNSInfo)
- {
- uint result;
- ushort portFromSNI = 0;
- string IPStringFromSNI = string.Empty;
- IPAddress IPFromSNI;
- _parser.isTcpProtocol = false;
- Provider providerNumber = Provider.INVALID_PROV;
-
- if (string.IsNullOrEmpty(userProtocol))
- {
-
- result = SniNativeWrapper.SniGetProviderNumber(Handle, ref providerNumber);
- Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetProviderNumber");
- _parser.isTcpProtocol = (providerNumber == Provider.TCP_PROV);
- }
- else if (userProtocol == TdsEnums.TCP)
- {
- _parser.isTcpProtocol = true;
- }
-
- // serverInfo.UserProtocol could be empty
- if (_parser.isTcpProtocol)
- {
- result = SniNativeWrapper.SniGetConnectionPort(Handle, ref portFromSNI);
- Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionPort");
-
- result = SniNativeWrapper.SniGetConnectionIpString(Handle, ref IPStringFromSNI);
- Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SniGetConnectionIPString");
-
- pendingDNSInfo = new SQLDNSInfo(DNSCacheKey, null, null, portFromSNI.ToString());
-
- if (IPAddress.TryParse(IPStringFromSNI, out IPFromSNI))
- {
- if (System.Net.Sockets.AddressFamily.InterNetwork == IPFromSNI.AddressFamily)
- {
- pendingDNSInfo.AddrIPv4 = IPStringFromSNI;
- }
- else if (System.Net.Sockets.AddressFamily.InterNetworkV6 == IPFromSNI.AddressFamily)
- {
- pendingDNSInfo.AddrIPv6 = IPStringFromSNI;
- }
- }
- }
- else
- {
- pendingDNSInfo = null;
- }
- }
-
- private ConsumerInfo CreateConsumerInfo(bool async)
- {
- ConsumerInfo myInfo = new ConsumerInfo();
-
- Debug.Assert(_outBuff.Length == _inBuff.Length, "Unexpected unequal buffers.");
-
- myInfo.defaultBufferSize = _outBuff.Length; // Obtain packet size from outBuff size.
-
- if (async)
- {
- myInfo.readDelegate = SNILoadHandle.SingletonInstance.ReadAsyncCallbackDispatcher;
- myInfo.writeDelegate = SNILoadHandle.SingletonInstance.WriteAsyncCallbackDispatcher;
- _gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
- myInfo.key = (IntPtr)_gcHandle;
- }
- return myInfo;
- }
-
- internal override void CreatePhysicalSNIHandle(
- string serverName,
- TimeoutTimer timeout,
- out byte[] instanceName,
- out ManagedSni.ResolvedServerSpn resolvedSpn,
- bool flushCache,
- bool async,
- bool fParallel,
- TransparentNetworkResolutionState transparentNetworkResolutionState,
- int totalTimeout,
- SqlConnectionIPAddressPreference iPAddressPreference,
- string cachedFQDN,
- ref SQLDNSInfo pendingDNSInfo,
- string serverSPN,
- bool isIntegratedSecurity,
- bool tlsFirst,
- string hostNameInCertificate,
- string serverCertificateFilename)
- {
- if (isIntegratedSecurity)
- {
- // now allocate proper length of buffer
- if (!string.IsNullOrEmpty(serverSPN))
- {
- // Native SNI requires the Unicode encoding and any other encoding like UTF8 breaks the code.
- SqlClientEventSource.Log.TryTraceEvent("<{0}.{1}|SEC> Server SPN `{2}` from the connection string is used.", nameof(TdsParserStateObjectNative), nameof(CreatePhysicalSNIHandle), serverSPN);
- }
- else
- {
- // This will signal to the interop layer that we need to retrieve the SPN
- serverSPN = string.Empty;
- }
- }
-
- ConsumerInfo myInfo = CreateConsumerInfo(async);
- SQLDNSInfo cachedDNSInfo;
- bool ret = SQLFallbackDNSCache.Instance.GetDNSInfo(cachedFQDN, out cachedDNSInfo);
-
- _sessionHandle = new SNIHandle(myInfo, serverName, ref serverSPN, timeout.MillisecondsRemainingInt, out instanceName,
- flushCache, !async, fParallel, iPAddressPreference, cachedDNSInfo, hostNameInCertificate);
- resolvedSpn = new(serverSPN.TrimEnd());
- }
-
- protected override uint SniPacketGetData(PacketHandle packet, byte[] _inBuff, ref uint dataSize)
- {
- Debug.Assert(packet.Type == PacketHandle.NativePointerType, "unexpected packet type when requiring NativePointer");
- return SniNativeWrapper.SniPacketGetData(packet.NativePointer, _inBuff, ref dataSize);
- }
-
- protected override bool CheckPacket(PacketHandle packet, TaskCompletionSource