316 lines
13 KiB
C#
316 lines
13 KiB
C#
using System;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
|
|
namespace RMCPPingSample
|
|
{
|
|
/// <summary>
|
|
/// AMT platform data. e.g. provisioning state.
|
|
/// </summary>
|
|
public struct PlatformData
|
|
{
|
|
//The prime number 397 was suggested by ReSharper.
|
|
private const int PRIME_NUMBER = 397;
|
|
|
|
#region Members
|
|
|
|
/// <summary>
|
|
/// The provisioning state of the AMT machine.
|
|
/// </summary>
|
|
public ProvisioningState ProvisioningState { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The major version of the AMT machine.
|
|
/// </summary>
|
|
public uint MajorVersion { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The minor version of the AMT machine.
|
|
/// </summary>
|
|
public uint MinorVersion { get; internal set; }
|
|
|
|
#endregion
|
|
|
|
#region Public Functions
|
|
|
|
/// <summary>
|
|
/// Indicates whether the current object is equal to another object of the same type.
|
|
/// </summary>
|
|
/// <param name="other">An object to compare with this object.</param>
|
|
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serves as a hash function for a particular type.
|
|
/// </summary>
|
|
/// <returns> A hash code for the current <see cref="T:System.Object"/></returns>
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int result = ProvisioningState.GetHashCode();
|
|
result = (result * PRIME_NUMBER) ^ MajorVersion.GetHashCode();
|
|
result = (result * PRIME_NUMBER ^ MinorVersion.GetHashCode());
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
|
|
/// </returns>
|
|
/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>. </param><exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception><filterpriority>2</filterpriority>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two Capabilities.
|
|
/// </summary>
|
|
/// <param name="left">A Capabilities instance to compare.</param>
|
|
/// <param name="right">A Capabilities instance to compare.</param>
|
|
/// <returns>true if the two Capabilities are equal; otherwise, false</returns>
|
|
public static bool operator ==(PlatformData left, PlatformData right)
|
|
{
|
|
return Equals(left, right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two Capabilities.
|
|
/// </summary>
|
|
/// <param name="left">A Capabilities instance to compare.</param>
|
|
/// <param name="right">A Capabilities instance to compare.</param>
|
|
/// <returns>false if the two Capabilities are equal; otherwise, true</returns>
|
|
public static bool operator !=(PlatformData left, PlatformData right)
|
|
{
|
|
return !Equals(left, right);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// The provisioning state of the AMT machine.
|
|
/// </summary>
|
|
public enum ProvisioningState
|
|
{
|
|
|
|
/// <summary>
|
|
/// The setup operation has not started.
|
|
/// </summary>
|
|
Pre = 0,
|
|
|
|
/// <summary>
|
|
/// The setup operation is in progress.
|
|
/// </summary>
|
|
In = 1,
|
|
|
|
/// <summary>
|
|
/// Intel(R) AMT is configured.
|
|
/// </summary>
|
|
Post = 2,
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
Unknown
|
|
}
|
|
|
|
public class RMCPPingApi
|
|
{
|
|
public RMCPPingApi()
|
|
{
|
|
|
|
}
|
|
|
|
public static string CreateUsage()
|
|
{
|
|
return "Usage: \n RMCPPing -host <Hostname> \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();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse the received pong buffer to platform data fields.
|
|
/// </summary>
|
|
/// <param name="pongBuffer">Pong buffer received data.</param>
|
|
/// <returns>Parsed platform data fields.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get byte array with the RMCP ping data.
|
|
/// </summary>
|
|
/// <returns>Byte array with the RMCP ping data.</returns>
|
|
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;
|
|
}
|
|
|
|
}
|
|
}
|