using System; using System.Net.Sockets; using System.Net; namespace RMCPPingSample { /// /// 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 } public class RMCPPingApi { public RMCPPingApi() { } public static string CreateUsage() { return "Usage: \n RMCPPing -host \n Examples: \n \t -host 192.168.0.1"; } public static PlatformData GetPlatformData(string address) { return GetPlatformDataByRMCPPing(address); } private static 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(address, 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 Exception(""); } catch (Exception ex) { // Close the socket. throw new Exception("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; const int UPDATED_VERSION_BYTE = 10; PlatformData platformData = new PlatformData(); //If major and minor version are 0, updated to reflect new RMCP pong definitions. if (pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] == 0) { // Minor version. // Byte 12 contains the minor version. platformData.MinorVersion = (uint)(pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + UPDATED_VERSION_BYTE + 1]); // Major version. // Byte 11 contains the major version. platformData.MajorVersion = (uint)(pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + UPDATED_VERSION_BYTE] ); } //If major or minor are not 0, it's the same as before. else { // 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; } } }