blob: 2fee5cc4bcbb5f6fc41f95dbcda3a7a4fa8e924a [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07002
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "net.hpp"
4#include "transporthandler.hpp"
5#include "types.hpp"
6#include "utils.hpp"
7
Patrick Venture5794fcf2017-10-26 11:11:14 -07008#include <arpa/inet.h>
9
Patrick Venture0b02be92018-08-31 11:55:55 -070010#include <fstream>
Patrick Venture5794fcf2017-10-26 11:11:14 -070011#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <phosphor-logging/log.hpp>
13#include <string>
14#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070015
16using namespace phosphor::logging;
17using namespace sdbusplus::xyz::openbmc_project::Common::Error;
18
19/** @struct GetChannelAccessRequest
20 *
21 * IPMI payload for Get Channel access command request.
22 */
23struct GetChannelAccessRequest
24{
Patrick Venture0b02be92018-08-31 11:55:55 -070025 uint8_t channelNumber; //!< Channel number.
26 uint8_t volatileSetting; //!< Get non-volatile or the volatile setting.
Patrick Venture5794fcf2017-10-26 11:11:14 -070027} __attribute__((packed));
28
29/** @struct GetChannelAccessResponse
30 *
31 * IPMI payload for Get Channel access command response.
32 */
33struct GetChannelAccessResponse
34{
Patrick Venture0b02be92018-08-31 11:55:55 -070035 uint8_t settings; //!< Channel settings.
36 uint8_t privilegeLimit; //!< Channel privilege level limit.
Patrick Venture5794fcf2017-10-26 11:11:14 -070037} __attribute__((packed));
38
Patrick Venture5794fcf2017-10-26 11:11:14 -070039ipmi_ret_t ipmi_get_channel_access(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070040 ipmi_request_t request,
41 ipmi_response_t response,
42 ipmi_data_len_t data_len,
43 ipmi_context_t context)
Patrick Venture5794fcf2017-10-26 11:11:14 -070044{
Patrick Venture0b02be92018-08-31 11:55:55 -070045 auto requestData =
46 reinterpret_cast<const GetChannelAccessRequest*>(request);
Patrick Venture5794fcf2017-10-26 11:11:14 -070047 std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -070048 auto responseData =
49 reinterpret_cast<GetChannelAccessResponse*>(outPayload.data());
Patrick Venture5794fcf2017-10-26 11:11:14 -070050
Patrick Venture5794fcf2017-10-26 11:11:14 -070051 /*
52 * The value Eh is used as a way to identify the current channel that
53 * the command is being received from.
54 */
55 constexpr auto channelE = 0x0E;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080056 int channel = requestData->channelNumber;
57 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -070058
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080059 if (channel != channelE && ethdevice.empty())
Patrick Venture5794fcf2017-10-26 11:11:14 -070060 {
61 *data_len = 0;
62 return IPMI_CC_INVALID_FIELD_REQUEST;
63 }
64
65 /*
66 * [7:6] - reserved
67 * [5] - 1b = Alerting disabled
68 * [4] - 1b = per message authentication disabled
69 * [3] - 0b = User level authentication enabled
70 * [2:0] - 2h = always available
71 */
72 constexpr auto channelSetting = 0x32;
73
74 responseData->settings = channelSetting;
Patrick Venture0b02be92018-08-31 11:55:55 -070075 // Defaulting the channel privilege to administrator level.
Patrick Venture5794fcf2017-10-26 11:11:14 -070076 responseData->privilegeLimit = PRIVILEGE_ADMIN;
77
78 *data_len = outPayload.size();
79 memcpy(response, outPayload.data(), *data_len);
80
81 return IPMI_CC_OK;
82}
83
84// ATTENTION: This ipmi function is very hardcoded on purpose
85// OpenBMC does not fully support IPMI. This command is useful
86// to have around because it enables testing of interfaces with
87// the IPMI tool.
88#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
89// IPMI Table 6-2
90#define IPMI_CHANNEL_TYPE_IPMB 1
91// IPMI Table 6-3
92#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
93
94ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070095 ipmi_request_t request,
96 ipmi_response_t response,
97 ipmi_data_len_t data_len,
98 ipmi_context_t context)
Patrick Venture5794fcf2017-10-26 11:11:14 -070099{
100 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700101 uint8_t resp[] = {1,
102 IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
103 IPMI_CHANNEL_TYPE_IPMB,
104 1,
105 0x41,
106 0xA7,
107 0x00,
108 0,
109 0};
110 uint8_t* p = (uint8_t*)request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800111 int channel = (*p) & CHANNEL_MASK;
112 std::string ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700113
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800114 // The supported channels numbers are those which are configured.
Patrick Venture5794fcf2017-10-26 11:11:14 -0700115 // Channel Number E is used as way to identify the current channel
116 // that the command is being is received from.
Patrick Venture0b02be92018-08-31 11:55:55 -0700117 if (channel != 0xe && ethdevice.empty())
118 {
Patrick Venture5794fcf2017-10-26 11:11:14 -0700119 rc = IPMI_CC_PARM_OUT_OF_RANGE;
120 *data_len = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700121 }
122 else
123 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800124 *data_len = sizeof(resp);
125 memcpy(response, resp, *data_len);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700126 }
127
128 return rc;
129}
Tom Joseph7cbe2282018-03-21 21:17:33 +0530130
131namespace cipher
132{
133
134/** @brief Get the supported Cipher records
135 *
136 * The cipher records are read from the JSON file and converted into cipher
137 * suite record format mentioned in the IPMI specification. The records can be
138 * either OEM or standard cipher. Each json entry is parsed and converted into
139 * the cipher record format and pushed into the vector.
140 *
141 * @return vector containing all the cipher suite records.
142 *
143 */
144std::vector<uint8_t> getCipherRecords()
145{
146 std::vector<uint8_t> records;
147
148 std::ifstream jsonFile(configFile);
149 if (!jsonFile.is_open())
150 {
151 log<level::ERR>("Channel Cipher suites file not found");
152 elog<InternalFailure>();
153 }
154
155 auto data = Json::parse(jsonFile, nullptr, false);
156 if (data.is_discarded())
157 {
158 log<level::ERR>("Parsing channel cipher suites JSON failed");
159 elog<InternalFailure>();
160 }
161
162 for (const auto& record : data)
163 {
164 if (record.find(oem) != record.end())
165 {
166 // OEM cipher suite - 0xC1
167 records.push_back(oemCipherSuite);
168 // Cipher Suite ID
169 records.push_back(record.value(cipher, 0));
170 // OEM IANA - 3 bytes
171 records.push_back(record.value(oem, 0));
172 records.push_back(record.value(oem, 0) >> 8);
173 records.push_back(record.value(oem, 0) >> 16);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530174 }
175 else
176 {
177 // OEM cipher suite - 0xC0
178 records.push_back(stdCipherSuite);
179 // Cipher Suite ID
180 records.push_back(record.value(cipher, 0));
181 }
182
183 // Authentication algorithm number
184 records.push_back(record.value(auth, 0));
185 // Integrity algorithm number
186 records.push_back(record.value(integrity, 0) | integrityTag);
187 // Confidentiality algorithm number
188 records.push_back(record.value(conf, 0) | confTag);
189 }
190
191 return records;
192}
193
Patrick Venture0b02be92018-08-31 11:55:55 -0700194} // namespace cipher
Tom Joseph7cbe2282018-03-21 21:17:33 +0530195
Patrick Venture0b02be92018-08-31 11:55:55 -0700196ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Tom Joseph7cbe2282018-03-21 21:17:33 +0530197 ipmi_request_t request,
198 ipmi_response_t response,
199 ipmi_data_len_t data_len,
200 ipmi_context_t context)
201{
202 static std::vector<uint8_t> records;
203 static auto recordInit = false;
204
205 auto requestData =
206 reinterpret_cast<const GetChannelCipherRequest*>(request);
207
Tom Joseph7cbe2282018-03-21 21:17:33 +0530208 if (*data_len < sizeof(GetChannelCipherRequest))
209 {
210 *data_len = 0;
211 return IPMI_CC_REQ_DATA_LEN_INVALID;
212 }
213
214 *data_len = 0;
215
216 // Support only for list algorithms by cipher suite
217 if (cipher::listCipherSuite !=
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 (requestData->listIndex & cipher::listTypeMask))
Tom Joseph7cbe2282018-03-21 21:17:33 +0530219 {
220 return IPMI_CC_INVALID_FIELD_REQUEST;
221 }
222
223 if (!recordInit)
224 {
225 try
226 {
227 records = cipher::getCipherRecords();
228 recordInit = true;
229 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700230 catch (const std::exception& e)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530231 {
232 return IPMI_CC_UNSPECIFIED_ERROR;
233 }
234 }
235
236 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
237 // set of 16 and so on.
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 auto index =
239 static_cast<size_t>(requestData->listIndex & cipher::listIndexMask);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530240
241 // Calculate the number of record data bytes to be returned.
242 auto start = std::min(index * cipher::respSize, records.size());
Patrick Venture0b02be92018-08-31 11:55:55 -0700243 auto end =
244 std::min((index * cipher::respSize) + cipher::respSize, records.size());
Tom Joseph7cbe2282018-03-21 21:17:33 +0530245 auto size = end - start;
246
Patrick Venture0b02be92018-08-31 11:55:55 -0700247 auto responseData = reinterpret_cast<GetChannelCipherRespHeader*>(response);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530248 responseData->channelNumber = cipher::defaultChannelNumber;
249
250 if (!size)
251 {
252 *data_len = sizeof(GetChannelCipherRespHeader);
253 }
254 else
255 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 std::copy_n(records.data() + start, size,
Tom Joseph7cbe2282018-03-21 21:17:33 +0530257 static_cast<uint8_t*>(response) + 1);
258 *data_len = size + sizeof(GetChannelCipherRespHeader);
259 }
260
261 return IPMI_CC_OK;
262}