blob: 3c011fd74e595f4095d6ea839188adef17392339 [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
2#include "types.hpp"
3#include "transporthandler.hpp"
4#include "utils.hpp"
Patrick Venturec7c1c3c2017-11-15 14:29:18 -08005#include "net.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07006
Tom Joseph7cbe2282018-03-21 21:17:33 +05307#include <fstream>
Patrick Venture5794fcf2017-10-26 11:11:14 -07008#include <string>
9#include <arpa/inet.h>
10
11#include <phosphor-logging/log.hpp>
12#include <phosphor-logging/elog-errors.hpp>
13#include "xyz/openbmc_project/Common/error.hpp"
14
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{
25 uint8_t channelNumber; //!< Channel number.
26 uint8_t volatileSetting; //!< Get non-volatile or the volatile setting.
27} __attribute__((packed));
28
29/** @struct GetChannelAccessResponse
30 *
31 * IPMI payload for Get Channel access command response.
32 */
33struct GetChannelAccessResponse
34{
35 uint8_t settings; //!< Channel settings.
36 uint8_t privilegeLimit; //!< Channel privilege level limit.
37} __attribute__((packed));
38
Patrick Venture5794fcf2017-10-26 11:11:14 -070039
40ipmi_ret_t ipmi_get_channel_access(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
41 ipmi_request_t request, ipmi_response_t response,
42 ipmi_data_len_t data_len, ipmi_context_t context)
43{
44 auto requestData = reinterpret_cast<const GetChannelAccessRequest*>
45 (request);
46 std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
47 auto responseData = reinterpret_cast<GetChannelAccessResponse*>
48 (outPayload.data());
49
Patrick Venture5794fcf2017-10-26 11:11:14 -070050 /*
51 * The value Eh is used as a way to identify the current channel that
52 * the command is being received from.
53 */
54 constexpr auto channelE = 0x0E;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080055 int channel = requestData->channelNumber;
56 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -070057
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080058 if (channel != channelE && ethdevice.empty())
Patrick Venture5794fcf2017-10-26 11:11:14 -070059 {
60 *data_len = 0;
61 return IPMI_CC_INVALID_FIELD_REQUEST;
62 }
63
64 /*
65 * [7:6] - reserved
66 * [5] - 1b = Alerting disabled
67 * [4] - 1b = per message authentication disabled
68 * [3] - 0b = User level authentication enabled
69 * [2:0] - 2h = always available
70 */
71 constexpr auto channelSetting = 0x32;
72
73 responseData->settings = channelSetting;
74 //Defaulting the channel privilege to administrator level.
75 responseData->privilegeLimit = PRIVILEGE_ADMIN;
76
77 *data_len = outPayload.size();
78 memcpy(response, outPayload.data(), *data_len);
79
80 return IPMI_CC_OK;
81}
82
83// ATTENTION: This ipmi function is very hardcoded on purpose
84// OpenBMC does not fully support IPMI. This command is useful
85// to have around because it enables testing of interfaces with
86// the IPMI tool.
87#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
88// IPMI Table 6-2
89#define IPMI_CHANNEL_TYPE_IPMB 1
90// IPMI Table 6-3
91#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
92
93ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
94 ipmi_request_t request, ipmi_response_t response,
95 ipmi_data_len_t data_len, ipmi_context_t context)
96{
97 ipmi_ret_t rc = IPMI_CC_OK;
98 uint8_t resp[] = {
99 1,
100 IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
101 IPMI_CHANNEL_TYPE_IPMB,
102 1,0x41,0xA7,0x00,0,0};
103 uint8_t *p = (uint8_t*) request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800104 int channel = (*p) & CHANNEL_MASK;
105 std::string ethdevice = ipmi::network::ChanneltoEthernet(channel);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700106
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800107 // The supported channels numbers are those which are configured.
Patrick Venture5794fcf2017-10-26 11:11:14 -0700108 // Channel Number E is used as way to identify the current channel
109 // that the command is being is received from.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800110 if (channel != 0xe && ethdevice.empty()) {
Patrick Venture5794fcf2017-10-26 11:11:14 -0700111 rc = IPMI_CC_PARM_OUT_OF_RANGE;
112 *data_len = 0;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800113 } else {
114 *data_len = sizeof(resp);
115 memcpy(response, resp, *data_len);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700116 }
117
118 return rc;
119}
Tom Joseph7cbe2282018-03-21 21:17:33 +0530120
121namespace cipher
122{
123
124/** @brief Get the supported Cipher records
125 *
126 * The cipher records are read from the JSON file and converted into cipher
127 * suite record format mentioned in the IPMI specification. The records can be
128 * either OEM or standard cipher. Each json entry is parsed and converted into
129 * the cipher record format and pushed into the vector.
130 *
131 * @return vector containing all the cipher suite records.
132 *
133 */
134std::vector<uint8_t> getCipherRecords()
135{
136 std::vector<uint8_t> records;
137
138 std::ifstream jsonFile(configFile);
139 if (!jsonFile.is_open())
140 {
141 log<level::ERR>("Channel Cipher suites file not found");
142 elog<InternalFailure>();
143 }
144
145 auto data = Json::parse(jsonFile, nullptr, false);
146 if (data.is_discarded())
147 {
148 log<level::ERR>("Parsing channel cipher suites JSON failed");
149 elog<InternalFailure>();
150 }
151
152 for (const auto& record : data)
153 {
154 if (record.find(oem) != record.end())
155 {
156 // OEM cipher suite - 0xC1
157 records.push_back(oemCipherSuite);
158 // Cipher Suite ID
159 records.push_back(record.value(cipher, 0));
160 // OEM IANA - 3 bytes
161 records.push_back(record.value(oem, 0));
162 records.push_back(record.value(oem, 0) >> 8);
163 records.push_back(record.value(oem, 0) >> 16);
164
165 }
166 else
167 {
168 // OEM cipher suite - 0xC0
169 records.push_back(stdCipherSuite);
170 // Cipher Suite ID
171 records.push_back(record.value(cipher, 0));
172 }
173
174 // Authentication algorithm number
175 records.push_back(record.value(auth, 0));
176 // Integrity algorithm number
177 records.push_back(record.value(integrity, 0) | integrityTag);
178 // Confidentiality algorithm number
179 records.push_back(record.value(conf, 0) | confTag);
180 }
181
182 return records;
183}
184
185} //namespace cipher
186
187ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn,
188 ipmi_cmd_t cmd,
189 ipmi_request_t request,
190 ipmi_response_t response,
191 ipmi_data_len_t data_len,
192 ipmi_context_t context)
193{
194 static std::vector<uint8_t> records;
195 static auto recordInit = false;
196
197 auto requestData =
198 reinterpret_cast<const GetChannelCipherRequest*>(request);
199
200
201 if (*data_len < sizeof(GetChannelCipherRequest))
202 {
203 *data_len = 0;
204 return IPMI_CC_REQ_DATA_LEN_INVALID;
205 }
206
207 *data_len = 0;
208
209 // Support only for list algorithms by cipher suite
210 if (cipher::listCipherSuite !=
211 (requestData->listIndex & cipher::listTypeMask))
212 {
213 return IPMI_CC_INVALID_FIELD_REQUEST;
214 }
215
216 if (!recordInit)
217 {
218 try
219 {
220 records = cipher::getCipherRecords();
221 recordInit = true;
222 }
223 catch (const std::exception &e)
224 {
225 return IPMI_CC_UNSPECIFIED_ERROR;
226 }
227 }
228
229 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
230 // set of 16 and so on.
231 auto index = static_cast<size_t>(
232 requestData->listIndex & cipher::listIndexMask);
233
234 // Calculate the number of record data bytes to be returned.
235 auto start = std::min(index * cipher::respSize, records.size());
236 auto end = std::min((index * cipher::respSize) + cipher::respSize,
237 records.size());
238 auto size = end - start;
239
240 auto responseData = reinterpret_cast<GetChannelCipherRespHeader*>
241 (response);
242 responseData->channelNumber = cipher::defaultChannelNumber;
243
244 if (!size)
245 {
246 *data_len = sizeof(GetChannelCipherRespHeader);
247 }
248 else
249 {
250 std::copy_n(records.data() + start,
251 size,
252 static_cast<uint8_t*>(response) + 1);
253 *data_len = size + sizeof(GetChannelCipherRespHeader);
254 }
255
256 return IPMI_CC_OK;
257}