//---------------------------------------------------------------------------- // // Copyright (c) Intel Corporation, 2011 - 2013 All Rights Reserved. // // File: ConnectionInfoEX.cs // // Contents: High Level API: connection Info. // // Notes: // //---------------------------------------------------------------------------- using System; using System.Net; using System.Runtime.InteropServices; using System.Security; using Intel.Manageability.Exceptions; using Intel.Manageability.Heci; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Net.Security; using HLAPI.Wireless; using System.Threading; // This class replaces the ConnectionInfo class. // A new user of the HLAPI will have to use this connection object. // Anyway, the IWSManClient.dll and the DotNetWSManClient.dll are still needed // because the DotNetWSManClient is part of the AMTInstance API. // This connection info object supports Secure password and TCP forwarding. namespace Intel.Manageability { /// /// The ConnectionInfoEX is an extension of ConnectionInfo. /// it supports Secure password and TCP forwarding. /// public class ConnectionInfoEX : IDisposable { #region Consts /// /// consts defining username and password limits /// public const int MAX_PWD_LENGTH = 32; public const int MIN_PWD_LENGTH = 8; public const int MAX_USERNAME_LENGTH = 32; public const int MIN_USERNAME_LENGTH = 1; // Max timeout is 100 seconds. This is the default timeout for httpClient timeout // (https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=netframework-4.8) private const int MAX_TIME_OUT = 100000; private const int DEFAULT_TIME_OUT = 30000; #endregion #region Enums /// /// Enum that represents the authentication type /// public enum AuthMethod { /// /// HTTP Digest access authentication /// Digest, /// /// HTTP Kerberos access authentication /// Kerberos } #endregion #region classes /// /// Class that represents a SOCKS proxy. /// public class SocksProxy : IDisposable { #region Consts /// /// consts defining username and password limits /// public const int MAX_PWD_LENGTH = 32; public const int MIN_PWD_LENGTH = 8; public const int MAX_USERNAME_LENGTH = 32; public const int MIN_USERNAME_LENGTH = 1; internal const int MAX_PORT_NUMBER = 65535; #endregion #region members /// /// If true, the HLAPI will request the AMT to drop the connection to the proxy /// before invoking dispose. /// public bool DropAtEnd { get; set; } /// /// Hostname / IP of the machine to connect. /// private string host; public string Host { get { return host; } set { //Validate IP address if (Uri.CheckHostName(value) == UriHostNameType.Unknown) throw new ManageabilityIllegalInputException("Argument error - Unknown Host name"); host = value; } } /// /// Port of the machine to connect. /// private int port; public int Port { get { return port; } set { if (value < 0 || value > MAX_PORT_NUMBER) throw new ManageabilityIllegalInputException("Argument error - Invalid port number"); port = value; } } /// /// User name of the machine to connect. /// private string userName; public string UserName { get { return userName; } set { if (string.IsNullOrEmpty(value)) userName = ""; else { if (userName.Length > MAX_USERNAME_LENGTH) throw new ManageabilityIllegalInputException("Invalid Argument - Username can contain up to 32 characters."); userName = value; } } } /// /// Password of the machine to connect as SecureString. /// private SecureString password; /// /// Password of the machine to connect. /// public SecureString Password { get { return password; } set { if (value == null || value.Length == 0) { password?.Dispose(); password = new SecureString(); } else { if (value.Length < MIN_PWD_LENGTH || value.Length > MAX_PWD_LENGTH) throw new ManageabilityIllegalInputException("invalid password, password must contain between 8 to 32 characters"); password?.Dispose(); password = value; } } } #endregion #region constructor /// /// Initialize a new instance of SocksProxy /// /// Hostname / IP of the machine to connect. /// Port of the machine to connect. /// UserName of the machine to connect. /// Password of the machine to connect. public SocksProxy(string host, int port, string userName, SecureString password) { Host = host; Port = port; UserName = userName; Password = password; } #endregion #region Idisposible private bool _disposed = false; protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { Password?.Dispose(); } _disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~SocksProxy() { Dispose(false); } #endregion } /// /// Class that represents overriding parameters. /// public struct TcpForwarder { /// /// The forwarder's hostname. /// private string host; public string Host { get { return host; } set { //Validate host name if (Uri.CheckHostName(value) == UriHostNameType.Unknown) throw new ManageabilityIllegalInputException("Argument error - Unknown Host name"); host = value; } } /// /// The overriding port to use for SOAP/WSMAN. /// private int mainPort; public int MainPort { get { return mainPort; } set { if (value < 0 || value > SocksProxy.MAX_PORT_NUMBER) throw new ManageabilityIllegalInputException("Argument error - Invalid port number"); mainPort = value; } } /// /// The overriding port to use for redirection. /// private int redirectionPort; public int RedirectPort { get { return redirectionPort; } set { if (value < 0 || value > SocksProxy.MAX_PORT_NUMBER) throw new ManageabilityIllegalInputException("Argument error - Invalid port number"); redirectionPort = value; } } /// /// The overriding port to use for RFB for KVM. /// private int rfbPort; public int RFBPort { get { return rfbPort; } set { if (value < 0 || value > SocksProxy.MAX_PORT_NUMBER) throw new ManageabilityIllegalInputException("Argument error - Invalid port number"); rfbPort = value; } } /// /// Initialize a new instance of TcpForwarder. /// /// The forwarder's hostname. /// The overriding port to use for SOAP/WSMAN. /// The overriding port to use to redirection. /// The overriding port to use for RFB. public TcpForwarder(string host, int mainPort, int redirectPort, int rfbPort) : this() { Host = host; MainPort = mainPort; RedirectPort = redirectPort; RFBPort = rfbPort; } } #endregion /// /// Verifies the remote server certificate used for authentication. /// /// The certificate used to authenticate /// The certificate chain. /// One or more errors associated with the remote certificate. /// bool, determines whether the specified certificate is accepted for authentication. /// accept the certificate when there is an error is less secure. public delegate bool ServerCertificateValidationCallback(X509Certificate certificate, X509Chain chain, SslPolicyErrors errors); #region Constructor /// /// Initialize a new instance of ConnectionInfoEX. /// public ConnectionInfoEX() { } /// /// Initialize a new instance of ConnectionInfoEX. /// /// Hostname / IP of the machine to connect. /// User name of the machine to connect. /// Password of the machine to connect. /// Indicates whether or not to use TLS in the connection. /// Certificate name (as it appears in the subject field of the certificate). /// Enum that represents the authentication type. /// Indicates whether or not to use a proxy in the connection. /// Indicates whether to use a SOCKS proxy. /// Indicates whether to use TcpForwarder. /// Accept Self-signed certificate for TLS connection public ConnectionInfoEX(string host, string userName, SecureString password, bool secure, string certificate, AuthMethod auth, SocksProxy proxy, SocksProxy redirectionProxy, TcpForwarder? tcpForwarder, bool acceptSelfSignedCertificate = false) : this() { Host = host; Auth = auth; UserName = userName; Password = password; Secure = secure; Certificate = certificate; Proxy = proxy; RedirectionProxy = redirectionProxy; Forwarder = tcpForwarder; Timeout = DEFAULT_TIME_OUT; AcceptSelfSignedCertificate = acceptSelfSignedCertificate; if (acceptSelfSignedCertificate) { CertificateValidationCallback = SelfSignedCertificateCallback; } } /// /// Initialize a new instance of ConnectionInfoEX. /// /// Hostname / IP of the machine to connect. /// User name of the machine to connect. /// Digest Master Password in base 64 string. /// Indicates whether or not to use TLS in the connection. /// Certificate name (as it appears in the subject field of the certificate). /// Enum that represents the authentication type. /// Indicates whether or not to use a proxy in the connection. /// Indicates whether to use a SOCKS proxy. /// Indicates whether to use TcpForwarder. /// Indicate whether or not to use DMP in the connection. /// Accept self-Signed certificate for TLS connection public ConnectionInfoEX(string host, string userName, SecureString password, bool secure, string certificate, AuthMethod auth, SocksProxy proxy, SocksProxy redirectionProxy, TcpForwarder? tcpForwarder, bool digestMasterPassword, bool acceptSelfSignedCertificate = false) : this() { Host = host; Auth = auth; UserName = userName; Password = password; Secure = secure; Certificate = certificate; Proxy = proxy; RedirectionProxy = redirectionProxy; Forwarder = tcpForwarder; UseDigestMasterPassword = digestMasterPassword; Timeout = DEFAULT_TIME_OUT; AcceptSelfSignedCertificate = acceptSelfSignedCertificate; if (acceptSelfSignedCertificate) { CertificateValidationCallback = SelfSignedCertificateCallback; } } /// /// Initialize a new instance of ConnectionInfoEX. /// /// Hostname / IP of the machine to connect. /// User name of the machine to connect. /// Password of the machine to connect. /// Indicates whether or not to use TLS in the connection. /// Certificate name (as it appears in the subject field of the certificate). /// Enum that represents the authentication type. /// Indicates whether or not to use a proxy in the connection. /// Indicates whether to use a SOCKS proxy. /// Indicates whether to use TcpForwarder. /// Sets the time-out value, in milliseconds. /// Accept Self-signed certificate for TLS connection public ConnectionInfoEX(string host, string userName, SecureString password, bool secure, string certificate, AuthMethod auth, SocksProxy proxy, SocksProxy redirectionProxy, TcpForwarder? tcpForwarder, int timeout, bool acceptSelfSignedCertificate = false) : this() { Host = host; Auth = auth; UserName = userName; Password = password; Secure = secure; Certificate = certificate; Proxy = proxy; RedirectionProxy = redirectionProxy; Forwarder = tcpForwarder; Timeout = timeout; AcceptSelfSignedCertificate = acceptSelfSignedCertificate; if (acceptSelfSignedCertificate) { CertificateValidationCallback = SelfSignedCertificateCallback; } } /// /// Initialize a new instance of ConnectionInfoEX. /// /// Hostname / IP of the machine to connect. /// User name of the machine to connect. /// Digest Master Password in base 64 string. /// Indicates whether or not to use TLS in the connection. /// Certificate name (as it appears in the subject field of the certificate). /// Enum that represents the authentication type. /// Indicates whether or not to use a proxy in the connection. /// Indicates whether to use a SOCKS proxy. /// Indicates whether to use TcpForwarder. /// Indicate whether or not to use DMP in the connection. /// Sets the time-out value, in milliseconds. /// Accept Self-signed certificate for TLS connection public ConnectionInfoEX(string host, string userName, SecureString password, bool secure, string certificate, AuthMethod auth, SocksProxy proxy, SocksProxy redirectionProxy, TcpForwarder? tcpForwarder, bool digestMasterPassword, int timeout, bool acceptSelfSignedCertificate = false) : this() { Host = host; Auth = auth; UserName = userName; Password = password; Secure = secure; Certificate = certificate; Proxy = proxy; RedirectionProxy = redirectionProxy; Forwarder = tcpForwarder; UseDigestMasterPassword = digestMasterPassword; Timeout = timeout; AcceptSelfSignedCertificate = acceptSelfSignedCertificate; if (acceptSelfSignedCertificate) { CertificateValidationCallback = SelfSignedCertificateCallback; } } #endregion #region Public Members ///// ///// Gets or sets the callback for custom validation by the client of the server certificate. ///// In WSMan Commands all errors are supported, in Redirection command only NameMismatch error is supported. ///// public ServerCertificateValidationCallback CertificateValidationCallback { set; get; } /// /// Hostname / IP of the machine to connect. /// private string _host; public string Host { get { return _host; } set { //Validate IP address if (Uri.CheckHostName(value) == UriHostNameType.Unknown) throw new ManageabilityIllegalInputException("Invalid Argument - Unknown Host name."); _host = value; } } private string _userName; /// /// User name of the machine to connect. /// public string UserName { get { return _userName; } set { if (String.IsNullOrEmpty(value)) { //Accepting null value for Kerberos connection (setting value to empty string) if (Auth == AuthMethod.Kerberos) _userName = ""; else throw new ManageabilityIllegalInputException("Invalid Argument - Username is null or an empty string."); } else { _userName = value; if (_userName.Length > MAX_USERNAME_LENGTH) throw new ManageabilityIllegalInputException("Invalid Argument - Username can contain up to 32 characters."); } } } private int _timeout; /// /// Connection time-out value (in milliseconds) /// public int Timeout { set { _timeout = value > MAX_TIME_OUT ? MAX_TIME_OUT : value; } get { return _timeout; } } /// /// Password of the machine to connect as SecureString. /// private SecureString _password; /// /// Password of the machine to connect. /// public SecureString Password { get { return _password; } set { if (value == null || value.Length == 0) { //Accepting null value for Kerberos connection (setting value to empty string) if (Auth == AuthMethod.Kerberos) { _password?.Dispose(); _password = new SecureString(); } else throw new ManageabilityIllegalInputException("Invalid Argument - Password is null or an empty string."); } else { if (value.Length < MIN_PWD_LENGTH || value.Length > MAX_PWD_LENGTH) throw new ManageabilityIllegalInputException("invalid password, password must contain between 8 to 32 characters"); _password?.Dispose(); _password = value; } } } /// /// Indicates whether or not to use TLS in the connection. /// public bool Secure { set; get; } /// /// Indicates whether or not to accept self-signed certificate in a TLS connection. /// public bool AcceptSelfSignedCertificate { set; get; } /// /// Certificate name (as it appears in the subject field of the certificate) /// private string _certificate; public string Certificate { get { return _certificate; } set { if (value == null) _certificate = ""; else _certificate = value; // In the common name field of the CN of a X509 certificate, , the limit is up to 64 characters if (_certificate.Length > 64) throw new ManageabilityIllegalInputException("Argument error - Invalid certificate"); } } /// /// Enum that represents the authentication type /// public AuthMethod Auth { set; get; } /// /// Indicates whether or not to use a proxy in the connection. /// public SocksProxy Proxy {set; get; } /// /// Use a proxy. Needed for redirection connections. /// public SocksProxy RedirectionProxy { get; set; } /// /// Use TCP forwarding parameters. Needed for redirected connections. /// public TcpForwarder? Forwarder { get; set; } /// /// Indicates whether the inserted password is Digest Master Password or not. /// public bool UseDigestMasterPassword { get; set; } #endregion #region Public Functions /// /// Get information about the AMT machine. /// Supported by RMCPPing from Intel AMT 6.0 and later. /// /// Information about the AMT machine, e.g. provisioning state, AMT version. public PlatformData GetPlatformData() { try { // Check if the host name is local machine and get platform data by HECI. if (true == Utils.Utils.IsLocalHost(this.Host)) { return GetPlatformDataByHECI(); } else { // If machine is not local - get platform data by rmcp ping. return GetPlatformDataByRMCPPing(this.Host.ToString()); } } catch { // If operation failed - the provisioning state is unknown. PlatformData platformData = new PlatformData(); platformData.ProvisioningState = ProvisioningState.Unknown; return platformData; } } /// Gets information about the AMT machine. #endregion #region Private Functions private static PlatformData GetPlatformDataByHECI() { PlatformData platformData = new PlatformData(); // Initialize new instance of HECI commands. PTHICommand heciCommand = new PTHICommand(); // Initialize the local HECI properties. heciCommand.Init(); PTHICommand.ProvisioningState state; // Get the provisioning state with HECI. heciCommand.GetProvisioningState(out state); // Parse the returned value to HLAPI value, and insert to platformData.provisioningState. platformData.ProvisioningState = ParseHECIProvisiongState(state); PTHICommand.AMT_VERSION_TYPE[] versions; string BIOS; // Get AMT's versions with HECI. // (List of versions for all firmware components as well as the version of the BIOS.) if (heciCommand.GetCodeVersions(out BIOS, out versions) == true) { // Run on the version list. foreach (PTHICommand.AMT_VERSION_TYPE version in versions) { // If the version is the Recovery Version (e.g. AMT version), keep the version in the struct platform data. if (version.Description.Text == "Recovery Version") { // AMT's version string in format - .. string[] amtVersions = version.Version.Text.Split('.'); // Keep the major version, which is located after the major version. platformData.MajorVersion = uint.Parse(amtVersions[0]); // Keep the minor version, which is located after the major version. platformData.MinorVersion = uint.Parse(amtVersions[1]); } } } else { PTHICommand.FWU_GET_VERSION_MSG_REPLY amtVersions; if (heciCommand.GetAMTCodeVersions(out amtVersions) == true) { platformData.MajorVersion = amtVersions.AMTVersion.Major; platformData.MinorVersion = amtVersions.AMTVersion.Minor; } } return platformData; } /// /// Get the Platform Data by RMCPPing protocol. /// Supported from AMT 6.0 and above. /// In earlier versions incorrect value may be returned. /// /// The machine address /// The Data about the machine platform private PlatformData GetPlatformDataByRMCPPing(string address) { #region Consts of RMCP ping format DATA. const int RMCP_PORT = 623; const int PONG_TIMEOUT = 5000; const int RMCP_HEADER_SIZE = 4; const int ASF_RMCP_DATA_MINIMUM_SIZE = 8; const int RMCP_RESENCE_PONG_DATA_SIZE = 16; const int DASH_SUPPORT_BYTE_OFFSET_DSP_0232_100B = 9; const int DASH_SUPPORT_INDICATING_BIT = 32; const int VERS_BYTE = 0; const int RSVD_BYTE = 1; const int SEQ_BYTE = 2; const int CLASS_BYTE = 3; const int VERS = 0x06; const int RSVD = 0x0; const int SEQ = 0x0; const int CLASS = 0x86; #endregion // Using UDP sockets. using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { try { // Server/AMT is listening on port 623. IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(address), RMCP_PORT); // Connect to the endpoint . clientSocket.Connect(ipEndPoint as EndPoint); // Open connection with the remote host. clientSocket.Connect(this.Host, RMCP_PORT); byte[] rmcpPingPacketData = GetRMCPPingPacketData(); // Send request to the AMT. clientSocket.Send(rmcpPingPacketData, 0, rmcpPingPacketData.Length, SocketFlags.None); clientSocket.ReceiveTimeout = PONG_TIMEOUT; byte[] byteData = new byte[4]; // Received the header. clientSocket.Receive(byteData, 0, byteData.Length, SocketFlags.None); // Check if the header is the requested request. if ((byteData[VERS_BYTE] == VERS) && (byteData[RSVD_BYTE] == RSVD) && (byteData[SEQ_BYTE] == SEQ) && (byteData[CLASS_BYTE] == CLASS)) { byte[] pongBuffer = new byte[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + RMCP_RESENCE_PONG_DATA_SIZE]; // Received the requested array from the AMT. clientSocket.Receive(pongBuffer, 0, RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + RMCP_RESENCE_PONG_DATA_SIZE, SocketFlags.None); // If found AMT machine. // Numbers 0x01 and 0x57 in bytes 14 and 15 catenated together present the Intel Corp (343) in decimal. if ((pongBuffer[12] == 0) && (pongBuffer[13] == 0) && (pongBuffer[14] == 0x01) && (pongBuffer[15] == 0x57)) { // 4.0 and 5.0 platforms support the RCMP pong according to DSP0232 1.0.0a which identifies the dash bit as // the 5th bit of the 9th byte of the pong response. // If the AMT machine version is lower than 5.1, provisioning state and AMT version are not supported. // 5.1 and newer platforms supports the RCMP pong according to DSP0232 1.0.0b which identifies the dash bit as // the 5th bit of the 10th byte of the pong response ushort dashSupportByteVersionB = pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + DASH_SUPPORT_BYTE_OFFSET_DSP_0232_100B]; // In version A, get AMT provisioning state. // When the dash supported version is B. if (0 != (dashSupportByteVersionB & DASH_SUPPORT_INDICATING_BIT)) { // Finish the operation if machine data has been found. return ParsePlatformDataFromRMCPPing(pongBuffer); } } } // If the operation comes to this line, and didn't return PlatformData yet, // means the operation failed; therefore - throw an exception. throw new ManageabilityException(""); } catch (Exception ex) { // Close the socket. throw new ManageabilityException("Failed to get platform DATA by RMCP ping", ex); } finally { clientSocket.Close(); } } } /// /// Parse the received pong buffer to platform data fields. /// /// Pong buffer received data. /// Parsed platform data fields. private static PlatformData ParsePlatformDataFromRMCPPing(byte[] pongBuffer) { const int RMCP_HEADER_SIZE = 4; const int ASF_RMCP_DATA_MINIMUM_SIZE = 8; const int CONFIGURATION_STATE_BYTE = 7; const int VERSION_BYTE = 6; PlatformData platformData = new PlatformData(); // Minor version. // Bits 0:3 in byte 7, contains the minor version. 15 number present the binary number 00001111. platformData.MinorVersion = (uint)((pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] & 0xf)); // Major version. // Bits 4:7 in byte 7, contains the major version. 240 number present the binary number 11110000. platformData.MajorVersion = (uint)((pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] & 0xf0) >> 4); // Provisioning state. (The provisioning state located in bit 0 and bit 1.) platformData.ProvisioningState = (ProvisioningState)(pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + CONFIGURATION_STATE_BYTE] & 0x3); return platformData; } /// /// Get byte array with the RMCP ping data. /// /// Byte array with the RMCP ping data. private static byte[] GetRMCPPingPacketData() { const int ASF_VERSION = 0x6; const int ASF_CLASS = 0x6; byte[] rmcpPingPacketData = new byte[12]; // RMCP_HEADER_SIZE+ASF_RMCP_DATA_MINIMUM_SIZE rmcpPingPacketData[0] = (byte)ASF_VERSION; rmcpPingPacketData[1] = 0; rmcpPingPacketData[2] = 0; rmcpPingPacketData[3] = (byte)ASF_CLASS; rmcpPingPacketData[4] = 0; rmcpPingPacketData[5] = 0; rmcpPingPacketData[6] = 0x11; // ((ASF_IANA_ENTERPRISE_NUMBER / 0x100) * 0x10000) rmcpPingPacketData[7] = 0xBE; // ((ASF_IANA_ENTERPRISE_NUMBER % 0x100) * 0x1000000) rmcpPingPacketData[8] = 0x80; // PRESENCE_PING_MESSAGE_TYPE rmcpPingPacketData[9] = 0; rmcpPingPacketData[10] = 0; rmcpPingPacketData[11] = 0; return rmcpPingPacketData; } /// /// Parse the fields of PTHICommand.ProvisioningState to HLAPI ProvisioningState. /// /// PTHICommand.ProvisioningState requested state to parse /// Parsed state to HLAPI ProvisioningState private static ProvisioningState ParseHECIProvisiongState(PTHICommand.ProvisioningState state) { switch (state) { case PTHICommand.ProvisioningState.In: { return ProvisioningState.In; } case PTHICommand.ProvisioningState.Post: { return ProvisioningState.Post; } case PTHICommand.ProvisioningState.Pre: { return ProvisioningState.Pre; } default: { return ProvisioningState.Unknown; } } } private static bool SelfSignedCertificateCallback(X509Certificate certificate, X509Chain chain, SslPolicyErrors error) { //If certificate is self signed, ignore all errors if (certificate.Subject.Equals(certificate.Issuer)) { return true; } if (error == SslPolicyErrors.None) { return true; } return false; } #endregion #region Idisposible // implement IDisposable method private bool _disposed = false; protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { Password?.Dispose(); Proxy?.Dispose(); RedirectionProxy?.Dispose(); } _disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~ConnectionInfoEX() { Dispose(false); } #endregion } /// /// AMT platform data. e.g. provisioning state. /// public struct PlatformData { //The prime number 397 was suggested by ReSharper. private const int PRIME_NUMBER = 397; #region Members /// /// The provisioning state of the AMT machine. /// public ProvisioningState ProvisioningState { get; internal set; } /// /// The major version of the AMT machine. /// public uint MajorVersion { get; internal set; } /// /// The minor version of the AMT machine. /// public uint MinorVersion { get; internal set; } #endregion #region Public Functions /// /// Indicates whether the current object is equal to another object of the same type. /// /// An object to compare with this object. /// true if the current object is equal to the parameter; otherwise, false. public bool Equals(PlatformData other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return other.ProvisioningState == ProvisioningState && other.MajorVersion == MajorVersion && other.MinorVersion == MinorVersion; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current public override int GetHashCode() { unchecked { int result = ProvisioningState.GetHashCode(); result = (result * PRIME_NUMBER) ^ MajorVersion.GetHashCode(); result = (result * PRIME_NUMBER ^ MinorVersion.GetHashCode()); return result; } } /// /// Determines whether the specified is equal to the current . /// /// /// true if the specified is equal to the current ; otherwise, false. /// /// The to compare with the current . The parameter is null.2 public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof(PlatformData)) return false; return Equals((PlatformData)obj); } /// /// Compares two Capabilities. /// /// A Capabilities instance to compare. /// A Capabilities instance to compare. /// true if the two Capabilities are equal; otherwise, false public static bool operator ==(PlatformData left, PlatformData right) { return Equals(left, right); } /// /// Compares two Capabilities. /// /// A Capabilities instance to compare. /// A Capabilities instance to compare. /// false if the two Capabilities are equal; otherwise, true public static bool operator !=(PlatformData left, PlatformData right) { return !Equals(left, right); } #endregion } /// /// The provisioning state of the AMT machine. /// public enum ProvisioningState { /// /// The setup operation has not started. /// Pre = 0, /// /// The setup operation is in progress. /// In = 1, /// /// Intel(R) AMT is configured. /// Post = 2, /// /// Intel(R) AMT is unreachable by RMCP ping or HECI. /// Can happen if AMT machine is lower than 5.1 version or the AMT machine does not exist. /// Unknown } }