blob: 3134683e9a8facbfbf869473d939577149fa634e [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
107 printf("IPMI APP GET CHANNEL INFO\n");
108
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800109 // The supported channels numbers are those which are configured.
Patrick Venture5794fcf2017-10-26 11:11:14 -0700110 // Channel Number E is used as way to identify the current channel
111 // that the command is being is received from.
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800112 if (channel != 0xe && ethdevice.empty()) {
Patrick Venture5794fcf2017-10-26 11:11:14 -0700113 rc = IPMI_CC_PARM_OUT_OF_RANGE;
114 *data_len = 0;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800115 } else {
116 *data_len = sizeof(resp);
117 memcpy(response, resp, *data_len);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700118 }
119
120 return rc;
121}
Tom Joseph7cbe2282018-03-21 21:17:33 +0530122
123namespace cipher
124{
125
126/** @brief Get the supported Cipher records
127 *
128 * The cipher records are read from the JSON file and converted into cipher
129 * suite record format mentioned in the IPMI specification. The records can be
130 * either OEM or standard cipher. Each json entry is parsed and converted into
131 * the cipher record format and pushed into the vector.
132 *
133 * @return vector containing all the cipher suite records.
134 *
135 */
136std::vector<uint8_t> getCipherRecords()
137{
138 std::vector<uint8_t> records;
139
140 std::ifstream jsonFile(configFile);
141 if (!jsonFile.is_open())
142 {
143 log<level::ERR>("Channel Cipher suites file not found");
144 elog<InternalFailure>();
145 }
146
147 auto data = Json::parse(jsonFile, nullptr, false);
148 if (data.is_discarded())
149 {
150 log<level::ERR>("Parsing channel cipher suites JSON failed");
151 elog<InternalFailure>();
152 }
153
154 for (const auto& record : data)
155 {
156 if (record.find(oem) != record.end())
157 {
158 // OEM cipher suite - 0xC1
159 records.push_back(oemCipherSuite);
160 // Cipher Suite ID
161 records.push_back(record.value(cipher, 0));
162 // OEM IANA - 3 bytes
163 records.push_back(record.value(oem, 0));
164 records.push_back(record.value(oem, 0) >> 8);
165 records.push_back(record.value(oem, 0) >> 16);
166
167 }
168 else
169 {
170 // OEM cipher suite - 0xC0
171 records.push_back(stdCipherSuite);
172 // Cipher Suite ID
173 records.push_back(record.value(cipher, 0));
174 }
175
176 // Authentication algorithm number
177 records.push_back(record.value(auth, 0));
178 // Integrity algorithm number
179 records.push_back(record.value(integrity, 0) | integrityTag);
180 // Confidentiality algorithm number
181 records.push_back(record.value(conf, 0) | confTag);
182 }
183
184 return records;
185}
186
187} //namespace cipher
188
189ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn,
190 ipmi_cmd_t cmd,
191 ipmi_request_t request,
192 ipmi_response_t response,
193 ipmi_data_len_t data_len,
194 ipmi_context_t context)
195{
196 static std::vector<uint8_t> records;
197 static auto recordInit = false;
198
199 auto requestData =
200 reinterpret_cast<const GetChannelCipherRequest*>(request);
201
202
203 if (*data_len < sizeof(GetChannelCipherRequest))
204 {
205 *data_len = 0;
206 return IPMI_CC_REQ_DATA_LEN_INVALID;
207 }
208
209 *data_len = 0;
210
211 // Support only for list algorithms by cipher suite
212 if (cipher::listCipherSuite !=
213 (requestData->listIndex & cipher::listTypeMask))
214 {
215 return IPMI_CC_INVALID_FIELD_REQUEST;
216 }
217
218 if (!recordInit)
219 {
220 try
221 {
222 records = cipher::getCipherRecords();
223 recordInit = true;
224 }
225 catch (const std::exception &e)
226 {
227 return IPMI_CC_UNSPECIFIED_ERROR;
228 }
229 }
230
231 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
232 // set of 16 and so on.
233 auto index = static_cast<size_t>(
234 requestData->listIndex & cipher::listIndexMask);
235
236 // Calculate the number of record data bytes to be returned.
237 auto start = std::min(index * cipher::respSize, records.size());
238 auto end = std::min((index * cipher::respSize) + cipher::respSize,
239 records.size());
240 auto size = end - start;
241
242 auto responseData = reinterpret_cast<GetChannelCipherRespHeader*>
243 (response);
244 responseData->channelNumber = cipher::defaultChannelNumber;
245
246 if (!size)
247 {
248 *data_len = sizeof(GetChannelCipherRespHeader);
249 }
250 else
251 {
252 std::copy_n(records.data() + start,
253 size,
254 static_cast<uint8_t*>(response) + 1);
255 *data_len = size + sizeof(GetChannelCipherRespHeader);
256 }
257
258 return IPMI_CC_OK;
259}