View Javadoc
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 }