blob: 322047448c95a8ce2275f1bfe5924627e2fda950 [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
Yong Lic3580e92019-08-15 14:36:47 +080017#include <bitset>
Vernon Mauerya3702c12019-05-22 13:20:59 -070018#include <bridgingcommands.hpp>
19#include <cstring>
Vernon Mauery15419dd2019-05-24 09:40:30 -070020#include <ipmid/api.hpp>
Yong Lic3580e92019-08-15 14:36:47 +080021#include <ipmid/utils.hpp>
Yong Liedbb4082020-03-06 17:38:25 +080022#include <manufacturingcommands.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070023#include <phosphor-logging/log.hpp>
24#include <sdbusplus/bus.hpp>
25#include <sdbusplus/bus/match.hpp>
26#include <sdbusplus/message.hpp>
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000027#include <storagecommands.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070028#include <vector>
29
Yong Lic3580e92019-08-15 14:36:47 +080030static constexpr const char *wdtService = "xyz.openbmc_project.Watchdog";
31static constexpr const char *wdtInterface =
32 "xyz.openbmc_project.State.Watchdog";
33static constexpr const char *wdtObjPath = "/xyz/openbmc_project/watchdog/host0";
34static constexpr const char *wdtInterruptFlagProp =
35 "PreTimeoutInterruptOccurFlag";
36
Vernon Mauerya3702c12019-05-22 13:20:59 -070037static constexpr const char *ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
38static constexpr const char *ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
39static constexpr const char *ipmbIntf = "org.openbmc.Ipmb";
40
41static Bridging bridging;
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000042static bool eventMessageBufferFlag = false;
Vernon Mauerya3702c12019-05-22 13:20:59 -070043
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +000044void Bridging::clearResponseQueue()
45{
46 responseQueue.clear();
47}
48
Vernon Mauerya3702c12019-05-22 13:20:59 -070049/**
50 * @brief utils for checksum
51 */
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000052static bool ipmbChecksumValidate(const uint8_t *data, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -070053{
54 if (data == nullptr)
55 {
56 return false;
57 }
58
59 uint8_t checksum = 0;
60
61 for (uint8_t idx = 0; idx < length; idx++)
62 {
63 checksum += data[idx];
64 }
65
66 if (0 == checksum)
67 {
68 return true;
69 }
70
71 return false;
72}
73
74static uint8_t ipmbChecksumCompute(uint8_t *data, uint8_t length)
75{
76 if (data == nullptr)
77 {
78 return 0;
79 }
80
81 uint8_t checksum = 0;
82
83 for (uint8_t idx = 0; idx < length; idx++)
84 {
85 checksum += data[idx];
86 }
87
88 checksum = (~checksum) + 1;
89 return checksum;
90}
91
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000092static inline bool
93 ipmbConnectionHeaderChecksumValidate(const ipmbHeader *ipmbHeader)
Vernon Mauerya3702c12019-05-22 13:20:59 -070094{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000095 return ipmbChecksumValidate(reinterpret_cast<const uint8_t *>(ipmbHeader),
Vernon Mauerya3702c12019-05-22 13:20:59 -070096 ipmbConnectionHeaderLength);
97}
98
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000099static inline bool ipmbDataChecksumValidate(const ipmbHeader *ipmbHeader,
Vernon Mauerya3702c12019-05-22 13:20:59 -0700100 uint8_t length)
101{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000102 return ipmbChecksumValidate((reinterpret_cast<const uint8_t *>(ipmbHeader) +
103 ipmbConnectionHeaderLength),
104 (length - ipmbConnectionHeaderLength));
Vernon Mauerya3702c12019-05-22 13:20:59 -0700105}
106
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000107static bool isFrameValid(const ipmbHeader *frame, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700108{
109 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength))
110 {
111 return false;
112 }
113
114 if (false == ipmbConnectionHeaderChecksumValidate(frame))
115 {
116 return false;
117 }
118
119 if (false == ipmbDataChecksumValidate(frame, length))
120 {
121 return false;
122 }
123
124 return true;
125}
126
127IpmbRequest::IpmbRequest(const ipmbHeader *ipmbBuffer, size_t bufferLength)
128{
129 address = ipmbBuffer->Header.Req.address;
130 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
131 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
132 rqSA = ipmbBuffer->Header.Req.rqSA;
133 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
134 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
135 cmd = ipmbBuffer->Header.Req.cmd;
136
137 size_t dataLength =
138 bufferLength - (ipmbConnectionHeaderLength +
139 ipmbRequestDataHeaderLength + ipmbChecksumSize);
140
141 if (dataLength > 0)
142 {
143 data.insert(data.end(), ipmbBuffer->Header.Req.data,
144 &ipmbBuffer->Header.Req.data[dataLength]);
145 }
146}
147
148IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
149 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
150 uint8_t cmd, uint8_t completionCode,
151 std::vector<uint8_t> &inputData) :
152 address(address),
153 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
154 completionCode(completionCode)
155{
156 data.reserve(ipmbMaxDataSize);
157
158 if (inputData.size() > 0)
159 {
160 data = std::move(inputData);
161 }
162}
163
164void IpmbResponse::ipmbToi2cConstruct(uint8_t *buffer, size_t *bufferLength)
165{
166 ipmbHeader *ipmbBuffer = (ipmbHeader *)buffer;
167
168 ipmbBuffer->Header.Resp.address = address;
169 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
170 ipmbBuffer->Header.Resp.rsSA = rsSA;
171 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
172 ipmbBuffer->Header.Resp.cmd = cmd;
173 ipmbBuffer->Header.Resp.completionCode = completionCode;
174
175 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
176 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
177
178 if (data.size() > 0)
179 {
180 std::copy(
181 data.begin(), data.end(),
182 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]);
183 }
184
185 *bufferLength = data.size() + ipmbResponseDataHeaderLength +
186 ipmbConnectionHeaderLength + ipmbChecksumSize;
187
188 buffer[*bufferLength - ipmbChecksumSize] =
189 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset],
190 (ipmbResponseDataHeaderLength + data.size()));
191}
192
193void IpmbRequest::prepareRequest(sdbusplus::message::message &mesg)
194{
195 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data);
196}
197
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530198static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
199{
200 return (netFn << 8) | cmd;
201}
202
203static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd)
204{
205 constexpr uint8_t netFnMeOEM = 0x2E;
Yong Liedbb4082020-03-06 17:38:25 +0800206 constexpr uint8_t netFnMeOEMGeneral = 0x3E;
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530207 constexpr uint8_t cmdMeOemSendRawPeci = 0x40;
208 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41;
209 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43;
210 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45;
211 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47;
212 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48;
213 constexpr uint8_t cmdMeOemSlotIpmb = 0x51;
214 constexpr uint8_t cmdMeOemSlotI2cMasterWriteRead = 0x52;
215 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9;
216 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7;
217 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC;
218
219 switch (makeCmdKey(netFn, cmd))
220 {
221 // Restrict ME Master write command
222 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
223 // Restrict ME OEM commands
224 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci):
225 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci):
226 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite):
227 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite):
228 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus):
229 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus):
Yong Liedbb4082020-03-06 17:38:25 +0800230 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotIpmb):
231 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cMasterWriteRead):
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530232 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus):
233 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion):
234 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus):
235 return false;
236 default:
237 return true;
238 }
239}
240
srikanta mondal36b3a872020-03-17 22:20:47 +0000241ipmi::Cc Bridging::handleIpmbChannel(ipmi::Context::ptr ctx,
242 const uint8_t tracking,
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000243 const std::vector<uint8_t> &msgData,
244 std::vector<uint8_t> &rspData)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700245{
Yong Liedbb4082020-03-06 17:38:25 +0800246 ipmi::Manufacturing mtm;
247
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000248 size_t msgLen = msgData.size();
249 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700250 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000251 phosphor::logging::log<phosphor::logging::level::INFO>(
252 "handleIpmbChannel, IPMB data length is invalid");
253 return ipmi::ccReqDataLenInvalid;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700254 }
255
srikanta mondale95b0e52020-03-18 10:35:19 +0000256 // Bridging to ME requires Administrator lvl
257 if ((ctx->priv) != ipmi::Privilege::Admin)
258 {
259 return ipmi::ccInsufficientPrivilege;
260 }
261
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000262 auto sendMsgReqData = reinterpret_cast<const ipmbHeader *>(msgData.data());
Vernon Mauerya3702c12019-05-22 13:20:59 -0700263
264 // allow bridging to ME only
265 if (sendMsgReqData->Header.Req.address != ipmbMeSlaveAddress)
266 {
267 phosphor::logging::log<phosphor::logging::level::INFO>(
268 "handleIpmbChannel, IPMB address invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000269 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700270 }
271
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530272 constexpr uint8_t shiftLUN = 2;
Yong Liedbb4082020-03-06 17:38:25 +0800273 if (mtm.getMfgMode() == ipmi::SpecialMode::none)
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530274 {
Yong Liedbb4082020-03-06 17:38:25 +0800275 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN),
276 sendMsgReqData->Header.Req.cmd))
277 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000278 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5;
279 return ccCmdNotSupportedInPresentState;
Yong Liedbb4082020-03-06 17:38:25 +0800280 }
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530281 }
282
Vernon Mauerya3702c12019-05-22 13:20:59 -0700283 // check allowed modes
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000284 if (tracking != modeNoTracking && tracking != modeTrackRequest)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700285 {
286 phosphor::logging::log<phosphor::logging::level::INFO>(
287 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000288 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700289 }
290
291 // check if request contains valid IPMB frame
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000292 if (!isFrameValid(sendMsgReqData, msgLen))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700293 {
294 phosphor::logging::log<phosphor::logging::level::INFO>(
295 "handleIpmbChannel, IPMB frame invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000296 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700297 }
298
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000299 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700300
srikanta mondal36b3a872020-03-17 22:20:47 +0000301 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
302 std::vector<uint8_t>>
303 IPMBResponse;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700304
305 // send request to IPMB
srikanta mondal36b3a872020-03-17 22:20:47 +0000306 boost::system::error_code ec;
307 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>(
308 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest",
309 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd,
310 ipmbRequest.data);
311 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700312 {
313 phosphor::logging::log<phosphor::logging::level::ERR>(
314 "handleIpmbChannel, dbus call exception");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000315 return ipmi::ccUnspecifiedError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700316 }
317
318 std::vector<uint8_t> dataReceived(0);
319 int status = -1;
320 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0;
321
322 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse;
323
324 auto respReceived =
325 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address,
326 ipmbRequest.seq, lun, cmd, cc, dataReceived);
327
328 // check IPMB layer status
329 if (status)
330 {
331 phosphor::logging::log<phosphor::logging::level::WARNING>(
332 "handleIpmbChannel, ipmb returned non zero status");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000333 return ipmi::ccResponseError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700334 }
335
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000336 switch (tracking)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700337 {
338 case modeNoTracking:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000339 {
340 if (getResponseQueueSize() == responseQueueMaxSize)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700341 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000342 return ipmi::ccBusy;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700343 }
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000344 insertMessageInQueue(respReceived);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700345 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000346 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700347 case modeTrackRequest:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000348 {
349 size_t dataLength = 0;
350 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength);
351 // resizing the rspData to its correct length
352 rspData.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700353 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000354 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700355 default:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000356 {
Vernon Mauerya3702c12019-05-22 13:20:59 -0700357 phosphor::logging::log<phosphor::logging::level::INFO>(
358 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000359 return ipmi::ccParmOutOfRange;
360 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700361 }
362
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000363 return ipmi::ccSuccess;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700364}
365
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000366void Bridging::insertMessageInQueue(IpmbResponse msg)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700367{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000368 responseQueue.insert(responseQueue.end(), std::move(msg));
369}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700370
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000371void Bridging::eraseMessageFromQueue()
372{
373 responseQueue.erase(responseQueue.begin());
374}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700375
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000376IpmbResponse Bridging::getMessageFromQueue()
377{
378 return responseQueue.front();
379}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700380
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000381/**
382 * @brief This command is used for bridging ipmi message between channels.
383 * @param channelNumber - channel number to send message to
384 * @param authenticationEnabled - authentication.
385 * @param encryptionEnabled - encryption
386 * @param Tracking - track request
387 * @param msg - message data
388 *
389 * @return IPMI completion code plus response data on success.
390 * - rspData - response data
391 **/
392ipmi::RspType<std::vector<uint8_t> // responseData
393 >
srikanta mondal36b3a872020-03-17 22:20:47 +0000394 ipmiAppSendMessage(ipmi::Context::ptr ctx, const uint4_t channelNumber,
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000395 const bool authenticationEnabled,
396 const bool encryptionEnabled, const uint2_t tracking,
397 ipmi::message::Payload &msg)
398{
Vernon Mauerya3702c12019-05-22 13:20:59 -0700399 // check message fields:
400 // encryption not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000401 if (encryptionEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700402 {
403 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000404 "ipmiAppSendMessage, encryption not supported");
405 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700406 }
407
408 // authentication not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000409 if (authenticationEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700410 {
411 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000412 "ipmiAppSendMessage, authentication not supported");
413 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700414 }
415
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000416 ipmi::Cc returnVal;
417 std::vector<uint8_t> rspData(ipmbMaxFrameLength);
418 size_t dataLength = 0;
419 std::vector<uint8_t> unpackMsg;
420
421 auto channelNo = static_cast<const uint8_t>(channelNumber);
422 // Get the channel number
423 switch (channelNo)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700424 {
425 // we only handle ipmb for now
426 case targetChannelIpmb:
427 case targetChannelOtherLan:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000428 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked())
429 {
430 return ipmi::responseReqDataLenInvalid();
431 }
432
433 returnVal = bridging.handleIpmbChannel(
srikanta mondal36b3a872020-03-17 22:20:47 +0000434 ctx, static_cast<const uint8_t>(tracking), unpackMsg, rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700435 break;
436 // fall through to default
437 case targetChannelIcmb10:
438 case targetChannelIcmb09:
439 case targetChannelLan:
440 case targetChannelSerialModem:
441 case targetChannelPciSmbus:
442 case targetChannelSmbus10:
443 case targetChannelSmbus20:
444 case targetChannelSystemInterface:
445 default:
446 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000447 "ipmiAppSendMessage, TargetChannel invalid");
448 return ipmi::responseParmOutOfRange();
449 }
450 if (returnVal != ipmi::ccSuccess)
451 {
452 return ipmi::response(returnVal);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700453 }
454
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000455 return ipmi::responseSuccess(rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700456}
457
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000458/**
459 * @brief This command is used to Get data from the receive message queue.
460 * This command should be executed executed via system interface only.
461 *
462 * @return IPMI completion code plus response data on success.
463 * - channelNumber
464 * - messageData
465 **/
466
467ipmi::RspType<uint8_t, // channelNumber
468 std::vector<uint8_t> // messageData
469 >
470 ipmiAppGetMessage()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700471{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000472 uint8_t channelData = 0;
473 std::vector<uint8_t> res(ipmbMaxFrameLength);
474 size_t dataLength = 0;
475
476 if (!bridging.getResponseQueueSize())
Vernon Mauerya3702c12019-05-22 13:20:59 -0700477 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000478 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700479 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000480 "ipmiAppGetMessage, no data available");
481 return ipmi::response(ipmiGetMessageCmdDataNotAvailable);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700482 }
483
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000484 // channel number set.
485 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700486
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000487 // Priviledge level set.
488 channelData |= SYSTEM_INTERFACE & 0xF0;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700489
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000490 // Get the first message from queue
491 auto respQueueItem = bridging.getMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700492
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000493 // construct response data.
494 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700495
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000496 // Remove the message from queue
497 bridging.eraseMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700498
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000499 // resizing the rspData to its correct length
500 res.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700501
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000502 return ipmi::responseSuccess(channelData, res);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700503}
504
Yong Lic3580e92019-08-15 14:36:47 +0800505std::size_t Bridging::getResponseQueueSize()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700506{
Yong Lic3580e92019-08-15 14:36:47 +0800507 return responseQueue.size();
508}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700509
Yong Lic3580e92019-08-15 14:36:47 +0800510/**
511@brief This command is used to retrive present message available states.
512
513@return IPMI completion code plus Flags as response data on success.
514**/
515ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags()
516{
517 std::bitset<8> getMsgFlagsRes;
518
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000519 // set event message buffer bit
520 if (!eventMessageBufferFlag)
521 {
522 getMsgFlagsRes.set(getMsgFlagEventMessageBit);
523 }
524 else
525 {
526 getMsgFlagsRes.reset(getMsgFlagEventMessageBit);
527 }
Yong Lic3580e92019-08-15 14:36:47 +0800528
529 // set message fields
530 if (bridging.getResponseQueueSize() > 0)
531 {
532 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit);
533 }
534 else
535 {
536 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit);
537 }
538
539 try
540 {
541 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
542 ipmi::Value variant = ipmi::getDbusProperty(
543 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp);
544 if (std::get<bool>(variant))
545 {
546 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit);
547 }
548 }
549 catch (sdbusplus::exception::SdBusError &e)
550 {
551 phosphor::logging::log<phosphor::logging::level::ERR>(
552 "ipmiAppGetMessageFlags, dbus call exception");
553 return ipmi::responseUnspecifiedError();
554 }
555
556 return ipmi::responseSuccess(getMsgFlagsRes);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700557}
558
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000559/** @brief This command is used to flush unread data from the receive
560 * message queue
561 * @param receiveMessage - clear receive message queue
562 * @param eventMsgBufFull - clear event message buffer full
563 * @param reserved2 - reserved bit
564 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
565 * @param reserved1 - reserved bit
566 * @param oem0 - clear OEM 0 data
567 * @param oem1 - clear OEM 1 data
568 * @param oem2 - clear OEM 2 data
569
570 * @return IPMI completion code on success
571 */
572ipmi::RspType<> ipmiAppClearMessageFlags(bool receiveMessage,
573 bool eventMsgBufFull, bool reserved2,
574 bool watchdogTimeout, bool reserved1,
575 bool oem0, bool oem1, bool oem2)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700576{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000577 if (reserved1 || reserved2)
578 {
579 return ipmi::responseInvalidFieldRequest();
580 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700581
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000582 if (receiveMessage)
583 {
584 bridging.clearResponseQueue();
585 }
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000586
587 if (eventMessageBufferFlag != true && eventMsgBufFull == true)
588 {
589 eventMessageBufferFlag = true;
590 }
591
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000592 try
593 {
594 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
595 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface,
596 wdtInterruptFlagProp, false);
597 }
598 catch (const sdbusplus::exception::SdBusError &e)
599 {
600 phosphor::logging::log<phosphor::logging::level::ERR>(
601 "ipmiAppClearMessageFlags: can't Clear/Set "
602 "PreTimeoutInterruptOccurFlag");
603 return ipmi::responseUnspecifiedError();
604 }
605
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000606 return ipmi::responseSuccess();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700607}
608
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000609using systemEventType = std::tuple<
610 uint16_t, // Generator ID
611 uint32_t, // Timestamp
612 uint8_t, // Sensor Type
613 uint8_t, // EvM Rev
614 uint8_t, // Sensor Number
615 uint7_t, // Event Type
616 bool, // Event Direction
617 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data
618using oemTsEventType = std::tuple<
619 uint32_t, // Timestamp
620 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data
621using oemEventType =
622 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data
623
624/** @brief implements of Read event message buffer command
625 *
626 * @returns IPMI completion code plus response data
627 * - recordID - SEL Record ID
628 * - recordType - Record Type
629 * - generatorID - Generator ID
630 * - timeStamp - Timestamp
631 * - sensorType - Sensor Type
632 * - eventMsgFormatRev - Event Message format version
633 * - sensorNumber - Sensor Number
634 * - eventType - Event Type
635 * - eventDir - Event Direction
636 * - eventData - Event Data field
637 */
638ipmi::RspType<uint16_t, // Record ID
639 uint8_t, // Record Type
640 std::variant<systemEventType, oemTsEventType,
641 oemEventType>> // Record Content
642 ipmiAppReadEventMessageBuffer()
643{
644 uint16_t recordId =
645 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55
646 uint16_t generatorId =
647 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41
648 constexpr uint8_t recordType = 0xC0;
649 constexpr uint8_t eventMsgFormatRev = 0x3A;
650 constexpr uint8_t sensorNumber = 0xFF;
651
652 // TODO need to be implemented.
653 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{};
654 // All '0xFF' since unused.
655 eventData.fill(0xFF);
656
657 // Set the event message buffer flag
658 eventMessageBufferFlag = true;
659
660 return ipmi::responseSuccess(
661 recordId, recordType,
662 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber,
663 static_cast<uint7_t>(0), false, eventData});
664}
665
Vernon Mauerya3702c12019-05-22 13:20:59 -0700666static void register_bridging_functions() __attribute__((constructor));
667static void register_bridging_functions()
668{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000669 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
670 ipmi::app::cmdClearMessageFlags,
671 ipmi::Privilege::User, ipmiAppClearMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700672
Yong Lic3580e92019-08-15 14:36:47 +0800673 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
674 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User,
675 ipmiAppGetMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700676
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000677 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
678 ipmi::app::cmdGetMessage, ipmi::Privilege::User,
679 ipmiAppGetMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700680
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000681 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
682 ipmi::app::cmdSendMessage, ipmi::Privilege::User,
683 ipmiAppSendMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700684
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000685 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
686 ipmi::app::cmdReadEventMessageBuffer,
687 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer);
688
Vernon Mauerya3702c12019-05-22 13:20:59 -0700689 return;
690}