1 package org.metricshub.ipmi.core.coding.protocol.decoder;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * IPMI Java Client
6 * ჻჻჻჻჻჻
7 * Copyright 2023 Verax Systems, MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
26 import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanResponse;
27 import org.metricshub.ipmi.core.coding.payload.sol.SolInboundMessage;
28 import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
29 import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
30 import org.metricshub.ipmi.core.coding.protocol.PayloadType;
31 import org.metricshub.ipmi.core.coding.rmcp.RmcpClassOfMessage;
32 import org.metricshub.ipmi.core.coding.rmcp.RmcpMessage;
33 import org.metricshub.ipmi.core.coding.security.ConfidentialityAlgorithm;
34 import org.metricshub.ipmi.core.common.TypeConverter;
35
36 /**
37 * Decodes IPMI session header and retrieves encrypted payload. Payload must be
38 * IPMI LAN format message.
39 */
40 public abstract class ProtocolDecoder implements IpmiDecoder {
41
42 public ProtocolDecoder() {
43
44 }
45
46 /**
47 * Decodes IPMI message version independent fields.
48 *
49 * @param rmcpMessage
50 * - RMCP message to decode.
51 * @param message
52 * - A reference to message being decoded.
53 * @param sequenceNumberOffset
54 * - Protocol version specific offset to Session Sequence Number
55 * field in the header of the IPMI message.
56 * @param payloadLengthOffset
57 * - Protocol version specific offset to IPMI Payload Length
58 * field in the header of the IPMI message.
59 * @param payloadLengthLength
60 * - Length of the payload length field.
61 * @see IpmiMessage
62 * @return Offset to the session trailer.
63 * @throws IllegalArgumentException
64 * when delivered RMCP message does not contain encapsulated
65 * IPMI message.
66 *
67 * @deprecated this method is obolete. use {@link ProtocolDecoder#decode(RmcpMessage)} instead
68 */
69 @Deprecated
70 protected int decode(RmcpMessage rmcpMessage, IpmiMessage message,
71 int sequenceNumberOffset, int payloadLengthOffset,
72 int payloadLengthLength) {
73
74 if (rmcpMessage.getClassOfMessage() != RmcpClassOfMessage.Ipmi) {
75 throw new IllegalArgumentException("This is not an IPMI message");
76 }
77
78 byte[] raw = rmcpMessage.getData();
79
80 message.setAuthenticationType(decodeAuthenticationType(raw[0]));
81
82 message.setSessionSequenceNumber(decodeSessionSequenceNumber(raw,
83 sequenceNumberOffset));
84
85 message.setPayloadLength(decodePayloadLength(raw, payloadLengthOffset));
86
87 message.setPayload(decodePayload(raw, payloadLengthOffset
88 + payloadLengthLength, message.getPayloadLength(),
89 message.getConfidentialityAlgorithm(), PayloadType.Ipmi));
90
91 return payloadLengthOffset + payloadLengthLength
92 + message.getPayloadLength();
93 }
94
95 protected static AuthenticationType decodeAuthenticationType(byte authenticationType) {
96 authenticationType &= TypeConverter.intToByte(0x0f);
97
98 return AuthenticationType.parseInt(TypeConverter
99 .byteToInt(authenticationType));
100 }
101
102 /**
103 * Decodes {@link AuthenticationType} of the message so that the version of
104 * the IPMI protocol could be determined.
105 *
106 * @param message
107 * - RMCP message to decode.
108 * @return {@link AuthenticationType} of the message.
109 */
110 public static AuthenticationType decodeAuthenticationType(
111 RmcpMessage message) {
112 return decodeAuthenticationType(message.getData()[0]);
113 }
114
115 /**
116 * Decodes int in a little endian convention from raw message at given
117 * offset
118 *
119 * @param rawMessage
120 * - Raw message to be decoded
121 * @param offset
122 * @return Decoded integer
123 */
124 protected static int decodeInt(byte[] rawMessage, int offset) {
125 byte[] result = new byte[4];
126
127 System.arraycopy(rawMessage, offset, result, 0, 4);
128
129 return TypeConverter.littleEndianByteArrayToInt(result);
130 }
131
132 /**
133 * Decodes session sequence number.
134 *
135 * @param rawMessage
136 * - Byte array holding whole message data.
137 * @param offset
138 * - Offset to session sequence number in header.
139 * @return Session Sequence number.
140 */
141 protected int decodeSessionSequenceNumber(byte[] rawMessage, int offset) {
142 return decodeInt(rawMessage, offset);
143 }
144
145 /**
146 * Decodes session ID.
147 *
148 * @param rawMessage
149 * - Byte array holding whole message data.
150 * @param offset
151 * - Offset to session ID in header.
152 * @return Session ID.
153 */
154 protected static int decodeSessionID(byte[] rawMessage, int offset) {
155 return decodeInt(rawMessage, offset);
156 }
157
158 /**
159 * Decodes payload length.
160 *
161 * @param rawData
162 * - Byte array holding whole message data.
163 * @param offset
164 * - Offset to payload length in header.
165 * @return payload length.
166 */
167 protected abstract int decodePayloadLength(byte[] rawData, int offset);
168
169 /**
170 * Decodes payload.
171 *
172 * @param rawData
173 * - Byte array holding whole message data.
174 * @param offset
175 * - Offset to payload.
176 * @param length
177 * - Length of the payload.
178 * @param confidentialityAlgorithm
179 * - {@link ConfidentialityAlgorithm} required to decrypt
180 * payload.
181 * @return Payload decoded into {@link IpmiLanResponse}.
182 */
183 protected IpmiPayload decodePayload(byte[] rawData, int offset, int length,
184 ConfidentialityAlgorithm confidentialityAlgorithm, PayloadType payloadType) {
185 byte[] payload = null;
186 if (length > 0) {
187 payload = new byte[length];
188
189 System.arraycopy(rawData, offset, payload, 0, length);
190
191 payload = confidentialityAlgorithm.decrypt(payload);
192 }
193
194 if (payloadType == PayloadType.Sol) {
195 return new SolInboundMessage(payload);
196 } else {
197 return new IpmiLanResponse(payload);
198 }
199 }
200 }