blob: 2f2c3fa926fcf90bb401a81e915389f474d90656 [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>
James Feistfcd2d3a2020-05-28 10:38:15 -070026
27#include <bitset>
28#include <cstring>
Vernon Mauerya3702c12019-05-22 13:20:59 -070029#include <vector>
30
James Feistfcd2d3a2020-05-28 10:38:15 -070031static constexpr const char* wdtService = "xyz.openbmc_project.Watchdog";
32static constexpr const char* wdtInterface =
Yong Lic3580e92019-08-15 14:36:47 +080033 "xyz.openbmc_project.State.Watchdog";
James Feistfcd2d3a2020-05-28 10:38:15 -070034static constexpr const char* wdtObjPath = "/xyz/openbmc_project/watchdog/host0";
35static constexpr const char* wdtInterruptFlagProp =
Yong Lic3580e92019-08-15 14:36:47 +080036 "PreTimeoutInterruptOccurFlag";
37
James Feistfcd2d3a2020-05-28 10:38:15 -070038static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
39static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
40static constexpr const char* ipmbIntf = "org.openbmc.Ipmb";
Vernon Mauerya3702c12019-05-22 13:20:59 -070041
42static Bridging bridging;
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000043static bool eventMessageBufferFlag = false;
Vernon Mauerya3702c12019-05-22 13:20:59 -070044
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +000045void Bridging::clearResponseQueue()
46{
47 responseQueue.clear();
48}
49
Vernon Mauerya3702c12019-05-22 13:20:59 -070050/**
51 * @brief utils for checksum
52 */
James Feistfcd2d3a2020-05-28 10:38:15 -070053static bool ipmbChecksumValidate(const uint8_t* data, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -070054{
55 if (data == nullptr)
56 {
57 return false;
58 }
59
60 uint8_t checksum = 0;
61
62 for (uint8_t idx = 0; idx < length; idx++)
63 {
64 checksum += data[idx];
65 }
66
67 if (0 == checksum)
68 {
69 return true;
70 }
71
72 return false;
73}
74
James Feistfcd2d3a2020-05-28 10:38:15 -070075static uint8_t ipmbChecksumCompute(uint8_t* data, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -070076{
77 if (data == nullptr)
78 {
79 return 0;
80 }
81
82 uint8_t checksum = 0;
83
84 for (uint8_t idx = 0; idx < length; idx++)
85 {
86 checksum += data[idx];
87 }
88
89 checksum = (~checksum) + 1;
90 return checksum;
91}
92
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +000093static inline bool
James Feistfcd2d3a2020-05-28 10:38:15 -070094 ipmbConnectionHeaderChecksumValidate(const ipmbHeader* ipmbHeader)
Vernon Mauerya3702c12019-05-22 13:20:59 -070095{
James Feistfcd2d3a2020-05-28 10:38:15 -070096 return ipmbChecksumValidate(reinterpret_cast<const uint8_t*>(ipmbHeader),
Vernon Mauerya3702c12019-05-22 13:20:59 -070097 ipmbConnectionHeaderLength);
98}
99
James Feistfcd2d3a2020-05-28 10:38:15 -0700100static inline bool ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader,
Vernon Mauerya3702c12019-05-22 13:20:59 -0700101 uint8_t length)
102{
James Feistfcd2d3a2020-05-28 10:38:15 -0700103 return ipmbChecksumValidate((reinterpret_cast<const uint8_t*>(ipmbHeader) +
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000104 ipmbConnectionHeaderLength),
105 (length - ipmbConnectionHeaderLength));
Vernon Mauerya3702c12019-05-22 13:20:59 -0700106}
107
James Feistfcd2d3a2020-05-28 10:38:15 -0700108static bool isFrameValid(const ipmbHeader* frame, uint8_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700109{
110 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength))
111 {
112 return false;
113 }
114
115 if (false == ipmbConnectionHeaderChecksumValidate(frame))
116 {
117 return false;
118 }
119
120 if (false == ipmbDataChecksumValidate(frame, length))
121 {
122 return false;
123 }
124
125 return true;
126}
127
James Feistfcd2d3a2020-05-28 10:38:15 -0700128IpmbRequest::IpmbRequest(const ipmbHeader* ipmbBuffer, size_t bufferLength)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700129{
130 address = ipmbBuffer->Header.Req.address;
131 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
132 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
133 rqSA = ipmbBuffer->Header.Req.rqSA;
134 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
135 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
136 cmd = ipmbBuffer->Header.Req.cmd;
137
138 size_t dataLength =
139 bufferLength - (ipmbConnectionHeaderLength +
140 ipmbRequestDataHeaderLength + ipmbChecksumSize);
141
142 if (dataLength > 0)
143 {
144 data.insert(data.end(), ipmbBuffer->Header.Req.data,
145 &ipmbBuffer->Header.Req.data[dataLength]);
146 }
147}
148
149IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
150 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
151 uint8_t cmd, uint8_t completionCode,
James Feistfcd2d3a2020-05-28 10:38:15 -0700152 std::vector<uint8_t>& inputData) :
Vernon Mauerya3702c12019-05-22 13:20:59 -0700153 address(address),
154 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
155 completionCode(completionCode)
156{
157 data.reserve(ipmbMaxDataSize);
158
159 if (inputData.size() > 0)
160 {
161 data = std::move(inputData);
162 }
163}
164
James Feistfcd2d3a2020-05-28 10:38:15 -0700165void IpmbResponse::ipmbToi2cConstruct(uint8_t* buffer, size_t* bufferLength)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700166{
James Feistfcd2d3a2020-05-28 10:38:15 -0700167 ipmbHeader* ipmbBuffer = (ipmbHeader*)buffer;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700168
169 ipmbBuffer->Header.Resp.address = address;
170 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
171 ipmbBuffer->Header.Resp.rsSA = rsSA;
172 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
173 ipmbBuffer->Header.Resp.cmd = cmd;
174 ipmbBuffer->Header.Resp.completionCode = completionCode;
175
176 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
177 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
178
179 if (data.size() > 0)
180 {
181 std::copy(
182 data.begin(), data.end(),
183 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]);
184 }
185
186 *bufferLength = data.size() + ipmbResponseDataHeaderLength +
187 ipmbConnectionHeaderLength + ipmbChecksumSize;
188
189 buffer[*bufferLength - ipmbChecksumSize] =
190 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset],
191 (ipmbResponseDataHeaderLength + data.size()));
192}
193
James Feistfcd2d3a2020-05-28 10:38:15 -0700194void IpmbRequest::prepareRequest(sdbusplus::message::message& mesg)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700195{
196 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data);
197}
198
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530199static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
200{
201 return (netFn << 8) | cmd;
202}
203
204static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd)
205{
206 constexpr uint8_t netFnMeOEM = 0x2E;
Yong Liedbb4082020-03-06 17:38:25 +0800207 constexpr uint8_t netFnMeOEMGeneral = 0x3E;
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530208 constexpr uint8_t cmdMeOemSendRawPeci = 0x40;
209 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41;
210 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43;
211 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45;
212 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47;
213 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48;
214 constexpr uint8_t cmdMeOemSlotIpmb = 0x51;
215 constexpr uint8_t cmdMeOemSlotI2cMasterWriteRead = 0x52;
216 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9;
217 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7;
218 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC;
219
220 switch (makeCmdKey(netFn, cmd))
221 {
222 // Restrict ME Master write command
223 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
224 // Restrict ME OEM commands
225 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci):
226 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci):
227 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite):
228 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite):
229 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus):
230 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus):
Yong Liedbb4082020-03-06 17:38:25 +0800231 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotIpmb):
232 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cMasterWriteRead):
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530233 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus):
234 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion):
235 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus):
236 return false;
237 default:
238 return true;
239 }
240}
241
srikanta mondal36b3a872020-03-17 22:20:47 +0000242ipmi::Cc Bridging::handleIpmbChannel(ipmi::Context::ptr ctx,
243 const uint8_t tracking,
James Feistfcd2d3a2020-05-28 10:38:15 -0700244 const std::vector<uint8_t>& msgData,
245 std::vector<uint8_t>& rspData)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700246{
Yong Liedbb4082020-03-06 17:38:25 +0800247 ipmi::Manufacturing mtm;
248
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000249 size_t msgLen = msgData.size();
250 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700251 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000252 phosphor::logging::log<phosphor::logging::level::INFO>(
253 "handleIpmbChannel, IPMB data length is invalid");
254 return ipmi::ccReqDataLenInvalid;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700255 }
256
srikanta mondale95b0e52020-03-18 10:35:19 +0000257 // Bridging to ME requires Administrator lvl
258 if ((ctx->priv) != ipmi::Privilege::Admin)
259 {
260 return ipmi::ccInsufficientPrivilege;
261 }
262
James Feistfcd2d3a2020-05-28 10:38:15 -0700263 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data());
Vernon Mauerya3702c12019-05-22 13:20:59 -0700264
265 // allow bridging to ME only
266 if (sendMsgReqData->Header.Req.address != ipmbMeSlaveAddress)
267 {
268 phosphor::logging::log<phosphor::logging::level::INFO>(
269 "handleIpmbChannel, IPMB address invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000270 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700271 }
272
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530273 constexpr uint8_t shiftLUN = 2;
Yong Liedbb4082020-03-06 17:38:25 +0800274 if (mtm.getMfgMode() == ipmi::SpecialMode::none)
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530275 {
Yong Liedbb4082020-03-06 17:38:25 +0800276 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN),
277 sendMsgReqData->Header.Req.cmd))
278 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000279 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5;
280 return ccCmdNotSupportedInPresentState;
Yong Liedbb4082020-03-06 17:38:25 +0800281 }
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530282 }
283
Vernon Mauerya3702c12019-05-22 13:20:59 -0700284 // check allowed modes
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000285 if (tracking != modeNoTracking && tracking != modeTrackRequest)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700286 {
287 phosphor::logging::log<phosphor::logging::level::INFO>(
288 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000289 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700290 }
291
292 // check if request contains valid IPMB frame
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000293 if (!isFrameValid(sendMsgReqData, msgLen))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700294 {
295 phosphor::logging::log<phosphor::logging::level::INFO>(
296 "handleIpmbChannel, IPMB frame invalid");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000297 return ipmi::ccParmOutOfRange;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700298 }
299
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000300 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700301
srikanta mondal36b3a872020-03-17 22:20:47 +0000302 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
303 std::vector<uint8_t>>
304 IPMBResponse;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700305
306 // send request to IPMB
srikanta mondal36b3a872020-03-17 22:20:47 +0000307 boost::system::error_code ec;
308 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>(
309 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest",
310 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd,
311 ipmbRequest.data);
312 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700313 {
314 phosphor::logging::log<phosphor::logging::level::ERR>(
315 "handleIpmbChannel, dbus call exception");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000316 return ipmi::ccUnspecifiedError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700317 }
318
319 std::vector<uint8_t> dataReceived(0);
320 int status = -1;
321 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0;
322
323 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse;
324
325 auto respReceived =
326 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address,
327 ipmbRequest.seq, lun, cmd, cc, dataReceived);
328
329 // check IPMB layer status
330 if (status)
331 {
332 phosphor::logging::log<phosphor::logging::level::WARNING>(
333 "handleIpmbChannel, ipmb returned non zero status");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000334 return ipmi::ccResponseError;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700335 }
336
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000337 switch (tracking)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700338 {
339 case modeNoTracking:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000340 {
341 if (getResponseQueueSize() == responseQueueMaxSize)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700342 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000343 return ipmi::ccBusy;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700344 }
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000345 insertMessageInQueue(respReceived);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700346 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000347 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700348 case modeTrackRequest:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000349 {
350 size_t dataLength = 0;
351 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength);
352 // resizing the rspData to its correct length
353 rspData.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700354 break;
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000355 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700356 default:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000357 {
Vernon Mauerya3702c12019-05-22 13:20:59 -0700358 phosphor::logging::log<phosphor::logging::level::INFO>(
359 "handleIpmbChannel, mode not supported");
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000360 return ipmi::ccParmOutOfRange;
361 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700362 }
363
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000364 return ipmi::ccSuccess;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700365}
366
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000367void Bridging::insertMessageInQueue(IpmbResponse msg)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700368{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000369 responseQueue.insert(responseQueue.end(), std::move(msg));
370}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700371
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000372void Bridging::eraseMessageFromQueue()
373{
374 responseQueue.erase(responseQueue.begin());
375}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700376
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000377IpmbResponse Bridging::getMessageFromQueue()
378{
379 return responseQueue.front();
380}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700381
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000382/**
383 * @brief This command is used for bridging ipmi message between channels.
384 * @param channelNumber - channel number to send message to
385 * @param authenticationEnabled - authentication.
386 * @param encryptionEnabled - encryption
387 * @param Tracking - track request
388 * @param msg - message data
389 *
390 * @return IPMI completion code plus response data on success.
391 * - rspData - response data
392 **/
393ipmi::RspType<std::vector<uint8_t> // responseData
394 >
srikanta mondal36b3a872020-03-17 22:20:47 +0000395 ipmiAppSendMessage(ipmi::Context::ptr ctx, const uint4_t channelNumber,
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000396 const bool authenticationEnabled,
397 const bool encryptionEnabled, const uint2_t tracking,
James Feistfcd2d3a2020-05-28 10:38:15 -0700398 ipmi::message::Payload& msg)
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000399{
Vernon Mauerya3702c12019-05-22 13:20:59 -0700400 // check message fields:
401 // encryption not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000402 if (encryptionEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700403 {
404 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000405 "ipmiAppSendMessage, encryption not supported");
406 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700407 }
408
409 // authentication not supported
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000410 if (authenticationEnabled)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700411 {
412 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000413 "ipmiAppSendMessage, authentication not supported");
414 return ipmi::responseParmOutOfRange();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700415 }
416
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000417 ipmi::Cc returnVal;
418 std::vector<uint8_t> rspData(ipmbMaxFrameLength);
419 size_t dataLength = 0;
420 std::vector<uint8_t> unpackMsg;
421
422 auto channelNo = static_cast<const uint8_t>(channelNumber);
423 // Get the channel number
424 switch (channelNo)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700425 {
426 // we only handle ipmb for now
427 case targetChannelIpmb:
428 case targetChannelOtherLan:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000429 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked())
430 {
431 return ipmi::responseReqDataLenInvalid();
432 }
433
434 returnVal = bridging.handleIpmbChannel(
srikanta mondal36b3a872020-03-17 22:20:47 +0000435 ctx, static_cast<const uint8_t>(tracking), unpackMsg, rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700436 break;
437 // fall through to default
438 case targetChannelIcmb10:
439 case targetChannelIcmb09:
440 case targetChannelLan:
441 case targetChannelSerialModem:
442 case targetChannelPciSmbus:
443 case targetChannelSmbus10:
444 case targetChannelSmbus20:
445 case targetChannelSystemInterface:
446 default:
447 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000448 "ipmiAppSendMessage, TargetChannel invalid");
449 return ipmi::responseParmOutOfRange();
450 }
451 if (returnVal != ipmi::ccSuccess)
452 {
453 return ipmi::response(returnVal);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700454 }
455
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000456 return ipmi::responseSuccess(rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700457}
458
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000459/**
460 * @brief This command is used to Get data from the receive message queue.
461 * This command should be executed executed via system interface only.
462 *
463 * @return IPMI completion code plus response data on success.
464 * - channelNumber
465 * - messageData
466 **/
467
468ipmi::RspType<uint8_t, // channelNumber
469 std::vector<uint8_t> // messageData
470 >
471 ipmiAppGetMessage()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700472{
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000473 uint8_t channelData = 0;
474 std::vector<uint8_t> res(ipmbMaxFrameLength);
475 size_t dataLength = 0;
476
477 if (!bridging.getResponseQueueSize())
Vernon Mauerya3702c12019-05-22 13:20:59 -0700478 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000479 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700480 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000481 "ipmiAppGetMessage, no data available");
482 return ipmi::response(ipmiGetMessageCmdDataNotAvailable);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700483 }
484
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000485 // channel number set.
486 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700487
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000488 // Priviledge level set.
489 channelData |= SYSTEM_INTERFACE & 0xF0;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700490
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000491 // Get the first message from queue
492 auto respQueueItem = bridging.getMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700493
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000494 // construct response data.
495 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700496
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000497 // Remove the message from queue
498 bridging.eraseMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700499
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000500 // resizing the rspData to its correct length
501 res.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700502
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000503 return ipmi::responseSuccess(channelData, res);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700504}
505
Yong Lic3580e92019-08-15 14:36:47 +0800506std::size_t Bridging::getResponseQueueSize()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700507{
Yong Lic3580e92019-08-15 14:36:47 +0800508 return responseQueue.size();
509}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700510
Yong Lic3580e92019-08-15 14:36:47 +0800511/**
512@brief This command is used to retrive present message available states.
513
514@return IPMI completion code plus Flags as response data on success.
515**/
516ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags()
517{
518 std::bitset<8> getMsgFlagsRes;
519
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000520 // set event message buffer bit
521 if (!eventMessageBufferFlag)
522 {
523 getMsgFlagsRes.set(getMsgFlagEventMessageBit);
524 }
525 else
526 {
527 getMsgFlagsRes.reset(getMsgFlagEventMessageBit);
528 }
Yong Lic3580e92019-08-15 14:36:47 +0800529
530 // set message fields
531 if (bridging.getResponseQueueSize() > 0)
532 {
533 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit);
534 }
535 else
536 {
537 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit);
538 }
539
540 try
541 {
542 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
543 ipmi::Value variant = ipmi::getDbusProperty(
544 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp);
545 if (std::get<bool>(variant))
546 {
547 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit);
548 }
549 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700550 catch (sdbusplus::exception::SdBusError& e)
Yong Lic3580e92019-08-15 14:36:47 +0800551 {
552 phosphor::logging::log<phosphor::logging::level::ERR>(
553 "ipmiAppGetMessageFlags, dbus call exception");
554 return ipmi::responseUnspecifiedError();
555 }
556
557 return ipmi::responseSuccess(getMsgFlagsRes);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700558}
559
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000560/** @brief This command is used to flush unread data from the receive
561 * message queue
562 * @param receiveMessage - clear receive message queue
563 * @param eventMsgBufFull - clear event message buffer full
564 * @param reserved2 - reserved bit
565 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
566 * @param reserved1 - reserved bit
567 * @param oem0 - clear OEM 0 data
568 * @param oem1 - clear OEM 1 data
569 * @param oem2 - clear OEM 2 data
570
571 * @return IPMI completion code on success
572 */
573ipmi::RspType<> ipmiAppClearMessageFlags(bool receiveMessage,
574 bool eventMsgBufFull, bool reserved2,
575 bool watchdogTimeout, bool reserved1,
576 bool oem0, bool oem1, bool oem2)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700577{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000578 if (reserved1 || reserved2)
579 {
580 return ipmi::responseInvalidFieldRequest();
581 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700582
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000583 if (receiveMessage)
584 {
585 bridging.clearResponseQueue();
586 }
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000587
588 if (eventMessageBufferFlag != true && eventMsgBufFull == true)
589 {
590 eventMessageBufferFlag = true;
591 }
592
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000593 try
594 {
595 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
596 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface,
597 wdtInterruptFlagProp, false);
598 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700599 catch (const sdbusplus::exception::SdBusError& e)
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000600 {
601 phosphor::logging::log<phosphor::logging::level::ERR>(
602 "ipmiAppClearMessageFlags: can't Clear/Set "
603 "PreTimeoutInterruptOccurFlag");
604 return ipmi::responseUnspecifiedError();
605 }
606
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000607 return ipmi::responseSuccess();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700608}
609
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000610using systemEventType = std::tuple<
611 uint16_t, // Generator ID
612 uint32_t, // Timestamp
613 uint8_t, // Sensor Type
614 uint8_t, // EvM Rev
615 uint8_t, // Sensor Number
616 uint7_t, // Event Type
617 bool, // Event Direction
618 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data
619using oemTsEventType = std::tuple<
620 uint32_t, // Timestamp
621 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data
622using oemEventType =
623 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data
624
625/** @brief implements of Read event message buffer command
626 *
627 * @returns IPMI completion code plus response data
628 * - recordID - SEL Record ID
629 * - recordType - Record Type
630 * - generatorID - Generator ID
631 * - timeStamp - Timestamp
632 * - sensorType - Sensor Type
633 * - eventMsgFormatRev - Event Message format version
634 * - sensorNumber - Sensor Number
635 * - eventType - Event Type
636 * - eventDir - Event Direction
637 * - eventData - Event Data field
638 */
639ipmi::RspType<uint16_t, // Record ID
640 uint8_t, // Record Type
641 std::variant<systemEventType, oemTsEventType,
642 oemEventType>> // Record Content
643 ipmiAppReadEventMessageBuffer()
644{
645 uint16_t recordId =
646 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55
647 uint16_t generatorId =
648 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41
649 constexpr uint8_t recordType = 0xC0;
650 constexpr uint8_t eventMsgFormatRev = 0x3A;
651 constexpr uint8_t sensorNumber = 0xFF;
652
653 // TODO need to be implemented.
654 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{};
655 // All '0xFF' since unused.
656 eventData.fill(0xFF);
657
658 // Set the event message buffer flag
659 eventMessageBufferFlag = true;
660
661 return ipmi::responseSuccess(
662 recordId, recordType,
663 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber,
664 static_cast<uint7_t>(0), false, eventData});
665}
666
Vernon Mauerya3702c12019-05-22 13:20:59 -0700667static void register_bridging_functions() __attribute__((constructor));
668static void register_bridging_functions()
669{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000670 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
671 ipmi::app::cmdClearMessageFlags,
672 ipmi::Privilege::User, ipmiAppClearMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700673
Yong Lic3580e92019-08-15 14:36:47 +0800674 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
675 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User,
676 ipmiAppGetMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700677
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000678 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
679 ipmi::app::cmdGetMessage, ipmi::Privilege::User,
680 ipmiAppGetMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700681
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000682 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
683 ipmi::app::cmdSendMessage, ipmi::Privilege::User,
684 ipmiAppSendMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700685
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000686 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
687 ipmi::app::cmdReadEventMessageBuffer,
688 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer);
689
Vernon Mauerya3702c12019-05-22 13:20:59 -0700690 return;
691}