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;
}
}
}