blob: 7ae513cd5af252e705204e5813e31e254d05f44b [file] [log] [blame]
Vernon Mauerya3702c12019-05-22 13:20:59 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Vernon Mauerya3702c12019-05-22 13:20:59 -070017#include <bridgingcommands.hpp>
Vernon Mauery15419dd2019-05-24 09:40:30 -070018#include <ipmid/api.hpp>
Yong Lic3580e92019-08-15 14:36:47 +080019#include <ipmid/utils.hpp>
Yong Liedbb4082020-03-06 17:38:25 +080020#include <manufacturingcommands.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070021#include <phosphor-logging/log.hpp>
22#include <sdbusplus/bus.hpp>
23#include <sdbusplus/bus/match.hpp>
24#include <sdbusplus/message.hpp>
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000025#include <storagecommands.hpp>
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +000026#include <user_channel/channel_layer.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070027
28#include <bitset>
29#include <cstring>
Vernon Mauerya3702c12019-05-22 13:20:59 -070030#include <vector>
31
James Feistfcd2d3a2020-05-28 10:38:15 -070032static constexpr const char* wdtService = "xyz.openbmc_project.Watchdog";
33static constexpr const char* wdtInterface =
Yong Lic3580e92019-08-15 14:36:47 +080034 "xyz.openbmc_project.State.Watchdog";
James Feistfcd2d3a2020-05-28 10:38:15 -070035static constexpr const char* wdtObjPath = "/xyz/openbmc_project/watchdog/host0";
36static constexpr const char* wdtInterruptFlagProp =
Yong Lic3580e92019-08-15 14:36:47 +080037 "PreTimeoutInterruptOccurFlag";
38
James Feistfcd2d3a2020-05-28 10:38:15 -070039static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
40static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
41static constexpr const char* ipmbIntf = "org.openbmc.Ipmb";
Vernon Mauerya3702c12019-05-22 13:20:59 -070042
43static Bridging bridging;
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000044static bool eventMessageBufferFlag = false;
Vernon Mauerya3702c12019-05-22 13:20:59 -070045
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +000046void Bridging::clearResponseQueue()
47{
48 responseQueue.clear();
49}
50
Vernon Mauerya3702c12019-05-22 13:20:59 -070051/**
52 * @brief utils for checksum
53 */
James Feistfcd2d3a2020-05-28 10:38:15 -070054static bool ipmbChecksumValidate(const uint8_t* data, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -070055{
56 if (data == nullptr)
57 {
58 return false;
59 }
60
61 uint8_t checksum = 0;
62
63 for (uint8_t idx = 0; idx < length; idx++)
64 {
65 checksum += data[idx];
66 }
67
68 if (0 == checksum)
69 {
70 return true;
71 }
72
73 return false;
74}
75
James Feistfcd2d3a2020-05-28 10:38:15 -070076static uint8_t ipmbChecksumCompute(uint8_t* data, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -070077{
78 if (data == nullptr)
79 {
80 return 0;
81 }
82
83 uint8_t checksum = 0;
84
85 for (uint8_t idx = 0; idx < length; idx++)
86 {
87 checksum += data[idx];
88 }
89
90 checksum = (~checksum) + 1;
91 return checksum;
92}
93
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000094static inline bool
James Feistfcd2d3a2020-05-28 10:38:15 -070095 ipmbConnectionHeaderChecksumValidate(const ipmbHeader* ipmbHeader)
Vernon Mauerya3702c12019-05-22 13:20:59 -070096{
James Feistfcd2d3a2020-05-28 10:38:15 -070097 return ipmbChecksumValidate(reinterpret_cast<const uint8_t*>(ipmbHeader),
Vernon Mauerya3702c12019-05-22 13:20:59 -070098 ipmbConnectionHeaderLength);
99}
100
James Feistfcd2d3a2020-05-28 10:38:15 -0700101static inline bool ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader,
Vernon Mauerya3702c12019-05-22 13:20:59 -0700102 uint8_t length)
103{
James Feistfcd2d3a2020-05-28 10:38:15 -0700104 return ipmbChecksumValidate((reinterpret_cast<const uint8_t*>(ipmbHeader) +
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000105 ipmbConnectionHeaderLength),
106 (length - ipmbConnectionHeaderLength));
Vernon Mauerya3702c12019-05-22 13:20:59 -0700107}
108
James Feistfcd2d3a2020-05-28 10:38:15 -0700109static bool isFrameValid(const ipmbHeader* frame, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700110{
111 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength))
112 {
113 return false;
114 }
115
116 if (false == ipmbConnectionHeaderChecksumValidate(frame))
117 {
118 return false;
119 }
120
121 if (false == ipmbDataChecksumValidate(frame, length))
122 {
123 return false;
124 }
125
126 return true;
127}
128
James Feistfcd2d3a2020-05-28 10:38:15 -0700129IpmbRequest::IpmbRequest(const ipmbHeader* ipmbBuffer, size_t bufferLength)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700130{
131 address = ipmbBuffer->Header.Req.address;
132 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
133 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
134 rqSA = ipmbBuffer->Header.Req.rqSA;
135 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
136 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
137 cmd = ipmbBuffer->Header.Req.cmd;
138
139 size_t dataLength =
140 bufferLength - (ipmbConnectionHeaderLength +
141 ipmbRequestDataHeaderLength + ipmbChecksumSize);
142
143 if (dataLength > 0)
144 {
145 data.insert(data.end(), ipmbBuffer->Header.Req.data,
146 &ipmbBuffer->Header.Req.data[dataLength]);
147 }
148}
149
150IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
151 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
152 uint8_t cmd, uint8_t completionCode,
James Feistfcd2d3a2020-05-28 10:38:15 -0700153 std::vector<uint8_t>& inputData) :
Vernon Mauerya3702c12019-05-22 13:20:59 -0700154 address(address),
155 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
156 completionCode(completionCode)
157{
158 data.reserve(ipmbMaxDataSize);
159
160 if (inputData.size() > 0)
161 {
162 data = std::move(inputData);
163 }
164}
165
James Feistfcd2d3a2020-05-28 10:38:15 -0700166void IpmbResponse::ipmbToi2cConstruct(uint8_t* buffer, size_t* bufferLength)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700167{
James Feistfcd2d3a2020-05-28 10:38:15 -0700168 ipmbHeader* ipmbBuffer = (ipmbHeader*)buffer;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700169
170 ipmbBuffer->Header.Resp.address = address;
171 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
172 ipmbBuffer->Header.Resp.rsSA = rsSA;
173 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
174 ipmbBuffer->Header.Resp.cmd = cmd;
175 ipmbBuffer->Header.Resp.completionCode = completionCode;
176
177 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
178 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
179
180 if (data.size() > 0)
181 {
182 std::copy(
183 data.begin(), data.end(),
184 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]);
185 }
186
187 *bufferLength = data.size() + ipmbResponseDataHeaderLength +
188 ipmbConnectionHeaderLength + ipmbChecksumSize;
189
190 buffer[*bufferLength - ipmbChecksumSize] =
191 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset],
192 (ipmbResponseDataHeaderLength + data.size()));
193}
194
James Feistfcd2d3a2020-05-28 10:38:15 -0700195void IpmbRequest::prepareRequest(sdbusplus::message::message& mesg)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700196{
197 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data);
198}
199
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530200static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
201{
202 return (netFn << 8) | cmd;
203}
204
205static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd)
206{
207 constexpr uint8_t netFnMeOEM = 0x2E;
Yong Liedbb4082020-03-06 17:38:25 +0800208 constexpr uint8_t netFnMeOEMGeneral = 0x3E;
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530209 constexpr uint8_t cmdMeOemSendRawPeci = 0x40;
210 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41;
211 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43;
212 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45;
213 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47;
214 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48;
215 constexpr uint8_t cmdMeOemSlotIpmb = 0x51;
216 constexpr uint8_t cmdMeOemSlotI2cMasterWriteRead = 0x52;
217 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9;
218 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7;
219 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC;
220
221 switch (makeCmdKey(netFn, cmd))
222 {
223 // Restrict ME Master write command
224 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
225 // Restrict ME OEM commands
226 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci):
227 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci):
228 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite):
229 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite):
230 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus):
231 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus):
Yong Liedbb4082020-03-06 17:38:25 +0800232 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotIpmb):
233 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cMasterWriteRead):
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530234 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus):
235 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion):
236 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus):
237 return false;
238 default:
239 return true;
240 }
241}
242
srikanta mondal36b3a872020-03-17 22:20:47 +0000243ipmi::Cc Bridging::handleIpmbChannel(ipmi::Context::ptr ctx,
244 const uint8_t tracking,
James Feistfcd2d3a2020-05-28 10:38:15 -0700245 const std::vector<uint8_t>& msgData,
246 std::vector<uint8_t>& rspData)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700247{
Yong Liedbb4082020-03-06 17:38:25 +0800248 ipmi::Manufacturing mtm;
249
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000250 size_t msgLen = msgData.size();
251 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700252 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000253 phosphor::logging::log<phosphor::logging::level::INFO>(
254 "handleIpmbChannel, IPMB data length is invalid");
255 return ipmi::ccReqDataLenInvalid;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700256 }
257
srikanta mondale95b0e52020-03-18 10:35:19 +0000258 // Bridging to ME requires Administrator lvl
259 if ((ctx->priv) != ipmi::Privilege::Admin)
260 {
261 return ipmi::ccInsufficientPrivilege;
262 }
263
James Feistfcd2d3a2020-05-28 10:38:15 -0700264 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data());
Vernon Mauerya3702c12019-05-22 13:20:59 -0700265
266 // allow bridging to ME only
267 if (sendMsgReqData->Header.Req.address != ipmbMeSlaveAddress)
268 {
269 phosphor::logging::log<phosphor::logging::level::INFO>(
270 "handleIpmbChannel, IPMB address invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000271 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700272 }
273
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530274 constexpr uint8_t shiftLUN = 2;
Yong Liedbb4082020-03-06 17:38:25 +0800275 if (mtm.getMfgMode() == ipmi::SpecialMode::none)
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530276 {
Yong Liedbb4082020-03-06 17:38:25 +0800277 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN),
278 sendMsgReqData->Header.Req.cmd))
279 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000280 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5;
281 return ccCmdNotSupportedInPresentState;
Yong Liedbb4082020-03-06 17:38:25 +0800282 }
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530283 }
284
Vernon Mauerya3702c12019-05-22 13:20:59 -0700285 // check allowed modes
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000286 if (tracking != modeNoTracking && tracking != modeTrackRequest)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700287 {
288 phosphor::logging::log<phosphor::logging::level::INFO>(
289 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000290 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700291 }
292
293 // check if request contains valid IPMB frame
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000294 if (!isFrameValid(sendMsgReqData, msgLen))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700295 {
296 phosphor::logging::log<phosphor::logging::level::INFO>(
297 "handleIpmbChannel, IPMB frame invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000298 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700299 }
300
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000301 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700302
srikanta mondal36b3a872020-03-17 22:20:47 +0000303 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
304 std::vector<uint8_t>>
305 IPMBResponse;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700306
307 // send request to IPMB
srikanta mondal36b3a872020-03-17 22:20:47 +0000308 boost::system::error_code ec;
309 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>(
310 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest",
311 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd,
312 ipmbRequest.data);
313 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700314 {
315 phosphor::logging::log<phosphor::logging::level::ERR>(
316 "handleIpmbChannel, dbus call exception");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000317 return ipmi::ccUnspecifiedError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700318 }
319
320 std::vector<uint8_t> dataReceived(0);
321 int status = -1;
322 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0;
323
324 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse;
325
326 auto respReceived =
327 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address,
328 ipmbRequest.seq, lun, cmd, cc, dataReceived);
329
330 // check IPMB layer status
331 if (status)
332 {
333 phosphor::logging::log<phosphor::logging::level::WARNING>(
334 "handleIpmbChannel, ipmb returned non zero status");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000335 return ipmi::ccResponseError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700336 }
337
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000338 switch (tracking)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700339 {
340 case modeNoTracking:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000341 {
342 if (getResponseQueueSize() == responseQueueMaxSize)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700343 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000344 return ipmi::ccBusy;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700345 }
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000346 insertMessageInQueue(respReceived);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700347 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000348 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700349 case modeTrackRequest:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000350 {
351 size_t dataLength = 0;
352 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength);
353 // resizing the rspData to its correct length
354 rspData.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700355 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000356 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700357 default:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000358 {
Vernon Mauerya3702c12019-05-22 13:20:59 -0700359 phosphor::logging::log<phosphor::logging::level::INFO>(
360 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000361 return ipmi::ccParmOutOfRange;
362 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700363 }
364
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000365 return ipmi::ccSuccess;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700366}
367
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000368void Bridging::insertMessageInQueue(IpmbResponse msg)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700369{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000370 responseQueue.insert(responseQueue.end(), std::move(msg));
371}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700372
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000373void Bridging::eraseMessageFromQueue()
374{
375 responseQueue.erase(responseQueue.begin());
376}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700377
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000378IpmbResponse Bridging::getMessageFromQueue()
379{
380 return responseQueue.front();
381}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700382
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000383/**
384 * @brief This command is used for bridging ipmi message between channels.
385 * @param channelNumber - channel number to send message to
386 * @param authenticationEnabled - authentication.
387 * @param encryptionEnabled - encryption
388 * @param Tracking - track request
389 * @param msg - message data
390 *
391 * @return IPMI completion code plus response data on success.
392 * - rspData - response data
393 **/
394ipmi::RspType<std::vector<uint8_t> // responseData
395 >
srikanta mondal36b3a872020-03-17 22:20:47 +0000396 ipmiAppSendMessage(ipmi::Context::ptr ctx, const uint4_t channelNumber,
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000397 const bool authenticationEnabled,
398 const bool encryptionEnabled, const uint2_t tracking,
James Feistfcd2d3a2020-05-28 10:38:15 -0700399 ipmi::message::Payload& msg)
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000400{
Vernon Mauerya3702c12019-05-22 13:20:59 -0700401 // check message fields:
402 // encryption not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000403 if (encryptionEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700404 {
405 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000406 "ipmiAppSendMessage, encryption not supported");
407 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700408 }
409
410 // authentication not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000411 if (authenticationEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700412 {
413 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000414 "ipmiAppSendMessage, authentication not supported");
415 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700416 }
417
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000418 ipmi::Cc returnVal;
419 std::vector<uint8_t> rspData(ipmbMaxFrameLength);
420 size_t dataLength = 0;
421 std::vector<uint8_t> unpackMsg;
422
423 auto channelNo = static_cast<const uint8_t>(channelNumber);
424 // Get the channel number
425 switch (channelNo)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700426 {
427 // we only handle ipmb for now
428 case targetChannelIpmb:
429 case targetChannelOtherLan:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000430 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked())
431 {
432 return ipmi::responseReqDataLenInvalid();
433 }
434
435 returnVal = bridging.handleIpmbChannel(
srikanta mondal36b3a872020-03-17 22:20:47 +0000436 ctx, static_cast<const uint8_t>(tracking), unpackMsg, rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700437 break;
438 // fall through to default
439 case targetChannelIcmb10:
440 case targetChannelIcmb09:
441 case targetChannelLan:
442 case targetChannelSerialModem:
443 case targetChannelPciSmbus:
444 case targetChannelSmbus10:
445 case targetChannelSmbus20:
446 case targetChannelSystemInterface:
447 default:
448 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000449 "ipmiAppSendMessage, TargetChannel invalid");
450 return ipmi::responseParmOutOfRange();
451 }
452 if (returnVal != ipmi::ccSuccess)
453 {
454 return ipmi::response(returnVal);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700455 }
456
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000457 return ipmi::responseSuccess(rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700458}
459
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000460/**
461 * @brief This command is used to Get data from the receive message queue.
462 * This command should be executed executed via system interface only.
463 *
464 * @return IPMI completion code plus response data on success.
465 * - channelNumber
466 * - messageData
467 **/
468
469ipmi::RspType<uint8_t, // channelNumber
470 std::vector<uint8_t> // messageData
471 >
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000472 ipmiAppGetMessage(ipmi::Context::ptr ctx)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700473{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000474 ipmi::ChannelInfo chInfo;
475
476 try
477 {
478 getChannelInfo(ctx->channel, chInfo);
479 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500480 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000481 {
482 phosphor::logging::log<phosphor::logging::level::ERR>(
483 "ipmiAppGetMessage: Failed to get Channel Info",
484 phosphor::logging::entry("MSG: %s", e.description()));
485 return ipmi::responseUnspecifiedError();
486 }
487 if (chInfo.mediumType !=
488 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
489 {
490 phosphor::logging::log<phosphor::logging::level::ERR>(
491 "ipmiAppGetMessage: Error - supported only in System(SMS) "
492 "interface");
493 return ipmi::responseCommandNotAvailable();
494 }
495
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000496 uint8_t channelData = 0;
497 std::vector<uint8_t> res(ipmbMaxFrameLength);
498 size_t dataLength = 0;
499
500 if (!bridging.getResponseQueueSize())
Vernon Mauerya3702c12019-05-22 13:20:59 -0700501 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000502 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700503 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000504 "ipmiAppGetMessage, no data available");
505 return ipmi::response(ipmiGetMessageCmdDataNotAvailable);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700506 }
507
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000508 // channel number set.
509 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700510
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000511 // Priviledge level set.
512 channelData |= SYSTEM_INTERFACE & 0xF0;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700513
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000514 // Get the first message from queue
515 auto respQueueItem = bridging.getMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700516
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000517 // construct response data.
518 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700519
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000520 // Remove the message from queue
521 bridging.eraseMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700522
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000523 // resizing the rspData to its correct length
524 res.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700525
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000526 return ipmi::responseSuccess(channelData, res);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700527}
528
Yong Lic3580e92019-08-15 14:36:47 +0800529std::size_t Bridging::getResponseQueueSize()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700530{
Yong Lic3580e92019-08-15 14:36:47 +0800531 return responseQueue.size();
532}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700533
Yong Lic3580e92019-08-15 14:36:47 +0800534/**
535@brief This command is used to retrive present message available states.
536
537@return IPMI completion code plus Flags as response data on success.
538**/
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000539ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags(ipmi::Context::ptr ctx)
Yong Lic3580e92019-08-15 14:36:47 +0800540{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000541 ipmi::ChannelInfo chInfo;
542
543 try
544 {
545 getChannelInfo(ctx->channel, chInfo);
546 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500547 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000548 {
549 phosphor::logging::log<phosphor::logging::level::ERR>(
550 "ipmiAppGetMessageFlags: Failed to get Channel Info",
551 phosphor::logging::entry("MSG: %s", e.description()));
552 return ipmi::responseUnspecifiedError();
553 }
554 if (chInfo.mediumType !=
555 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
556 {
557 phosphor::logging::log<phosphor::logging::level::ERR>(
558 "ipmiAppGetMessageFlags: Error - supported only in System(SMS) "
559 "interface");
560 return ipmi::responseCommandNotAvailable();
561 }
562
Yong Lic3580e92019-08-15 14:36:47 +0800563 std::bitset<8> getMsgFlagsRes;
564
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000565 // set event message buffer bit
566 if (!eventMessageBufferFlag)
567 {
568 getMsgFlagsRes.set(getMsgFlagEventMessageBit);
569 }
570 else
571 {
572 getMsgFlagsRes.reset(getMsgFlagEventMessageBit);
573 }
Yong Lic3580e92019-08-15 14:36:47 +0800574
575 // set message fields
576 if (bridging.getResponseQueueSize() > 0)
577 {
578 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit);
579 }
580 else
581 {
582 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit);
583 }
584
585 try
586 {
587 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
588 ipmi::Value variant = ipmi::getDbusProperty(
589 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp);
590 if (std::get<bool>(variant))
591 {
592 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit);
593 }
594 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500595 catch (const sdbusplus::exception::exception& e)
Yong Lic3580e92019-08-15 14:36:47 +0800596 {
597 phosphor::logging::log<phosphor::logging::level::ERR>(
598 "ipmiAppGetMessageFlags, dbus call exception");
599 return ipmi::responseUnspecifiedError();
600 }
601
602 return ipmi::responseSuccess(getMsgFlagsRes);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700603}
604
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000605/** @brief This command is used to flush unread data from the receive
606 * message queue
607 * @param receiveMessage - clear receive message queue
608 * @param eventMsgBufFull - clear event message buffer full
609 * @param reserved2 - reserved bit
610 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
611 * @param reserved1 - reserved bit
612 * @param oem0 - clear OEM 0 data
613 * @param oem1 - clear OEM 1 data
614 * @param oem2 - clear OEM 2 data
615
616 * @return IPMI completion code on success
617 */
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000618ipmi::RspType<> ipmiAppClearMessageFlags(ipmi::Context::ptr ctx,
619 bool receiveMessage,
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000620 bool eventMsgBufFull, bool reserved2,
621 bool watchdogTimeout, bool reserved1,
622 bool oem0, bool oem1, bool oem2)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700623{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000624 ipmi::ChannelInfo chInfo;
625
626 try
627 {
628 getChannelInfo(ctx->channel, chInfo);
629 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500630 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000631 {
632 phosphor::logging::log<phosphor::logging::level::ERR>(
633 "ipmiAppClearMessageFlags: Failed to get Channel Info",
634 phosphor::logging::entry("MSG: %s", e.description()));
635 return ipmi::responseUnspecifiedError();
636 }
637 if (chInfo.mediumType !=
638 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
639 {
640 phosphor::logging::log<phosphor::logging::level::ERR>(
641 "ipmiAppClearMessageFlags: Error - supported only in System(SMS) "
642 "interface");
643 return ipmi::responseCommandNotAvailable();
644 }
645
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000646 if (reserved1 || reserved2)
647 {
648 return ipmi::responseInvalidFieldRequest();
649 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700650
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000651 if (receiveMessage)
652 {
653 bridging.clearResponseQueue();
654 }
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000655
656 if (eventMessageBufferFlag != true && eventMsgBufFull == true)
657 {
658 eventMessageBufferFlag = true;
659 }
660
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000661 try
662 {
663 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
664 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface,
Jayaprakash Mutyala429b0852022-05-10 18:46:50 +0000665 wdtInterruptFlagProp, watchdogTimeout);
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000666 }
Patrick Williams69245b72021-09-02 09:23:01 -0500667 catch (const sdbusplus::exception::exception& e)
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000668 {
669 phosphor::logging::log<phosphor::logging::level::ERR>(
670 "ipmiAppClearMessageFlags: can't Clear/Set "
671 "PreTimeoutInterruptOccurFlag");
672 return ipmi::responseUnspecifiedError();
673 }
674
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000675 return ipmi::responseSuccess();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700676}
677
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000678using systemEventType = std::tuple<
679 uint16_t, // Generator ID
680 uint32_t, // Timestamp
681 uint8_t, // Sensor Type
682 uint8_t, // EvM Rev
683 uint8_t, // Sensor Number
684 uint7_t, // Event Type
685 bool, // Event Direction
686 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data
687using oemTsEventType = std::tuple<
688 uint32_t, // Timestamp
689 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data
690using oemEventType =
691 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data
692
693/** @brief implements of Read event message buffer command
694 *
695 * @returns IPMI completion code plus response data
696 * - recordID - SEL Record ID
697 * - recordType - Record Type
698 * - generatorID - Generator ID
699 * - timeStamp - Timestamp
700 * - sensorType - Sensor Type
701 * - eventMsgFormatRev - Event Message format version
702 * - sensorNumber - Sensor Number
703 * - eventType - Event Type
704 * - eventDir - Event Direction
705 * - eventData - Event Data field
706 */
707ipmi::RspType<uint16_t, // Record ID
708 uint8_t, // Record Type
709 std::variant<systemEventType, oemTsEventType,
710 oemEventType>> // Record Content
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000711 ipmiAppReadEventMessageBuffer(ipmi::Context::ptr ctx)
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000712{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000713 ipmi::ChannelInfo chInfo;
714
715 try
716 {
717 getChannelInfo(ctx->channel, chInfo);
718 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500719 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000720 {
721 phosphor::logging::log<phosphor::logging::level::ERR>(
722 "ipmiAppReadEventMessageBuffer: Failed to get Channel Info",
723 phosphor::logging::entry("MSG: %s", e.description()));
724 return ipmi::responseUnspecifiedError();
725 }
726 if (chInfo.mediumType !=
727 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
728 {
729 phosphor::logging::log<phosphor::logging::level::ERR>(
730 "ipmiAppReadEventMessageBuffer: Error - supported only in "
731 "System(SMS) interface");
732 return ipmi::responseCommandNotAvailable();
733 }
734
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000735 uint16_t recordId =
736 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55
737 uint16_t generatorId =
738 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41
739 constexpr uint8_t recordType = 0xC0;
740 constexpr uint8_t eventMsgFormatRev = 0x3A;
741 constexpr uint8_t sensorNumber = 0xFF;
742
743 // TODO need to be implemented.
744 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{};
745 // All '0xFF' since unused.
746 eventData.fill(0xFF);
747
748 // Set the event message buffer flag
749 eventMessageBufferFlag = true;
750
751 return ipmi::responseSuccess(
752 recordId, recordType,
753 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber,
754 static_cast<uint7_t>(0), false, eventData});
755}
756
Vernon Mauerya3702c12019-05-22 13:20:59 -0700757static void register_bridging_functions() __attribute__((constructor));
758static void register_bridging_functions()
759{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000760 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
761 ipmi::app::cmdClearMessageFlags,
762 ipmi::Privilege::User, ipmiAppClearMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700763
Yong Lic3580e92019-08-15 14:36:47 +0800764 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
765 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User,
766 ipmiAppGetMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700767
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000768 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
769 ipmi::app::cmdGetMessage, ipmi::Privilege::User,
770 ipmiAppGetMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700771
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000772 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
773 ipmi::app::cmdSendMessage, ipmi::Privilege::User,
774 ipmiAppSendMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700775
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000776 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
777 ipmi::app::cmdReadEventMessageBuffer,
778 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer);
779
Vernon Mauerya3702c12019-05-22 13:20:59 -0700780 return;
781}