blob: 465659f07c7b7ef641346b770f820da01d64f8e1 [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
Patrick Williams1bcced02024-08-16 15:20:24 -0400101static inline bool
102 ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader, size_t length)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700103{
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
PavanKumarIntel919075d2023-10-30 16:41:19 +0000109static bool isFrameValid(const ipmbHeader* frame, size_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
Patrick Williams1bcced02024-08-16 15:20:24 -0400139 size_t dataLength =
140 bufferLength - (ipmbConnectionHeaderLength +
141 ipmbRequestDataHeaderLength + ipmbChecksumSize);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700142
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) :
Patrick Williams1bcced02024-08-16 15:20:24 -0400154 address(address), netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq),
155 rsLun(rsLun), cmd(cmd), completionCode(completionCode)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700156{
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
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500194void IpmbRequest::prepareRequest(sdbusplus::message_t& 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;
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800215 constexpr uint8_t cmdMeOemSlotI2cControllerWriteRead = 0x52;
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530216 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9;
217 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7;
218 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC;
219
220 switch (makeCmdKey(netFn, cmd))
221 {
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800222 // Restrict ME Controller write command
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530223 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):
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800232 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cControllerWriteRead):
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
Patrick Williams1bcced02024-08-16 15:20:24 -0400242ipmi::Cc Bridging::handleIpmbChannel(
243 ipmi::Context::ptr& ctx, const uint8_t tracking,
244 const std::vector<uint8_t>& msgData, 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
James Feistfcd2d3a2020-05-28 10:38:15 -0700262 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data());
Vernon Mauerya3702c12019-05-22 13:20:59 -0700263
264 // allow bridging to ME only
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800265 if (sendMsgReqData->Header.Req.address != ipmbMeTargetAddress)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700266 {
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
Patrick Williams1bcced02024-08-16 15:20:24 -0400324 auto respReceived =
325 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address,
326 ipmbRequest.seq, lun, cmd, cc, dataReceived);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700327
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 >
Vernon Mauerydcff1502022-09-28 11:12:46 -0700394 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,
James Feistfcd2d3a2020-05-28 10:38:15 -0700397 ipmi::message::Payload& msg)
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000398{
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);
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000418 std::vector<uint8_t> unpackMsg;
419
Vernon Mauerydcff1502022-09-28 11:12:46 -0700420 auto channelNo = static_cast<uint8_t>(channelNumber);
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000421 // Get the channel number
422 switch (channelNo)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700423 {
424 // we only handle ipmb for now
425 case targetChannelIpmb:
426 case targetChannelOtherLan:
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000427 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked())
428 {
429 return ipmi::responseReqDataLenInvalid();
430 }
431
432 returnVal = bridging.handleIpmbChannel(
Vernon Mauerydcff1502022-09-28 11:12:46 -0700433 ctx, static_cast<uint8_t>(tracking), unpackMsg, rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700434 break;
435 // fall through to default
436 case targetChannelIcmb10:
437 case targetChannelIcmb09:
438 case targetChannelLan:
439 case targetChannelSerialModem:
440 case targetChannelPciSmbus:
441 case targetChannelSmbus10:
442 case targetChannelSmbus20:
443 case targetChannelSystemInterface:
444 default:
445 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000446 "ipmiAppSendMessage, TargetChannel invalid");
447 return ipmi::responseParmOutOfRange();
448 }
449 if (returnVal != ipmi::ccSuccess)
450 {
451 return ipmi::response(returnVal);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700452 }
453
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000454 return ipmi::responseSuccess(rspData);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700455}
456
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000457/**
458 * @brief This command is used to Get data from the receive message queue.
459 * This command should be executed executed via system interface only.
460 *
461 * @return IPMI completion code plus response data on success.
462 * - channelNumber
463 * - messageData
464 **/
465
466ipmi::RspType<uint8_t, // channelNumber
467 std::vector<uint8_t> // messageData
468 >
Vernon Mauerydcff1502022-09-28 11:12:46 -0700469 ipmiAppGetMessage(ipmi::Context::ptr& ctx)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700470{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000471 ipmi::ChannelInfo chInfo;
472
473 try
474 {
475 getChannelInfo(ctx->channel, chInfo);
476 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500477 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000478 {
479 phosphor::logging::log<phosphor::logging::level::ERR>(
480 "ipmiAppGetMessage: Failed to get Channel Info",
481 phosphor::logging::entry("MSG: %s", e.description()));
482 return ipmi::responseUnspecifiedError();
483 }
484 if (chInfo.mediumType !=
485 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
486 {
487 phosphor::logging::log<phosphor::logging::level::ERR>(
488 "ipmiAppGetMessage: Error - supported only in System(SMS) "
489 "interface");
490 return ipmi::responseCommandNotAvailable();
491 }
492
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000493 uint8_t channelData = 0;
494 std::vector<uint8_t> res(ipmbMaxFrameLength);
495 size_t dataLength = 0;
496
497 if (!bridging.getResponseQueueSize())
Vernon Mauerya3702c12019-05-22 13:20:59 -0700498 {
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000499 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700500 phosphor::logging::log<phosphor::logging::level::INFO>(
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000501 "ipmiAppGetMessage, no data available");
502 return ipmi::response(ipmiGetMessageCmdDataNotAvailable);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700503 }
504
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000505 // channel number set.
506 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700507
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000508 // Priviledge level set.
509 channelData |= SYSTEM_INTERFACE & 0xF0;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700510
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000511 // Get the first message from queue
512 auto respQueueItem = bridging.getMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700513
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000514 // construct response data.
515 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700516
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000517 // Remove the message from queue
518 bridging.eraseMessageFromQueue();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700519
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000520 // resizing the rspData to its correct length
521 res.resize(dataLength);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700522
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000523 return ipmi::responseSuccess(channelData, res);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700524}
525
Yong Lic3580e92019-08-15 14:36:47 +0800526std::size_t Bridging::getResponseQueueSize()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700527{
Yong Lic3580e92019-08-15 14:36:47 +0800528 return responseQueue.size();
529}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700530
Yong Lic3580e92019-08-15 14:36:47 +0800531/**
532@brief This command is used to retrive present message available states.
533
534@return IPMI completion code plus Flags as response data on success.
535**/
Vernon Mauerydcff1502022-09-28 11:12:46 -0700536ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags(ipmi::Context::ptr& ctx)
Yong Lic3580e92019-08-15 14:36:47 +0800537{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000538 ipmi::ChannelInfo chInfo;
539
540 try
541 {
542 getChannelInfo(ctx->channel, chInfo);
543 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500544 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000545 {
546 phosphor::logging::log<phosphor::logging::level::ERR>(
547 "ipmiAppGetMessageFlags: Failed to get Channel Info",
548 phosphor::logging::entry("MSG: %s", e.description()));
549 return ipmi::responseUnspecifiedError();
550 }
551 if (chInfo.mediumType !=
552 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
553 {
554 phosphor::logging::log<phosphor::logging::level::ERR>(
555 "ipmiAppGetMessageFlags: Error - supported only in System(SMS) "
556 "interface");
557 return ipmi::responseCommandNotAvailable();
558 }
559
Yong Lic3580e92019-08-15 14:36:47 +0800560 std::bitset<8> getMsgFlagsRes;
561
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000562 // set event message buffer bit
563 if (!eventMessageBufferFlag)
564 {
565 getMsgFlagsRes.set(getMsgFlagEventMessageBit);
566 }
567 else
568 {
569 getMsgFlagsRes.reset(getMsgFlagEventMessageBit);
570 }
Yong Lic3580e92019-08-15 14:36:47 +0800571
572 // set message fields
573 if (bridging.getResponseQueueSize() > 0)
574 {
575 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit);
576 }
577 else
578 {
579 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit);
580 }
581
582 try
583 {
584 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
585 ipmi::Value variant = ipmi::getDbusProperty(
586 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp);
587 if (std::get<bool>(variant))
588 {
589 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit);
590 }
591 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500592 catch (const sdbusplus::exception_t& e)
Yong Lic3580e92019-08-15 14:36:47 +0800593 {
594 phosphor::logging::log<phosphor::logging::level::ERR>(
595 "ipmiAppGetMessageFlags, dbus call exception");
596 return ipmi::responseUnspecifiedError();
597 }
598
599 return ipmi::responseSuccess(getMsgFlagsRes);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700600}
601
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000602/** @brief This command is used to flush unread data from the receive
603 * message queue
604 * @param receiveMessage - clear receive message queue
605 * @param eventMsgBufFull - clear event message buffer full
606 * @param reserved2 - reserved bit
607 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
608 * @param reserved1 - reserved bit
609 * @param oem0 - clear OEM 0 data
610 * @param oem1 - clear OEM 1 data
611 * @param oem2 - clear OEM 2 data
612
613 * @return IPMI completion code on success
614 */
Patrick Williams1bcced02024-08-16 15:20:24 -0400615ipmi::RspType<> ipmiAppClearMessageFlags(
616 ipmi::Context::ptr& ctx, bool receiveMessage, bool eventMsgBufFull,
617 bool reserved2, bool watchdogTimeout, bool reserved1, bool /* oem0 */,
618 bool /* oem1 */, bool /* oem2 */)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700619{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000620 ipmi::ChannelInfo chInfo;
621
622 try
623 {
624 getChannelInfo(ctx->channel, chInfo);
625 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500626 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000627 {
628 phosphor::logging::log<phosphor::logging::level::ERR>(
629 "ipmiAppClearMessageFlags: Failed to get Channel Info",
630 phosphor::logging::entry("MSG: %s", e.description()));
631 return ipmi::responseUnspecifiedError();
632 }
633 if (chInfo.mediumType !=
634 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
635 {
636 phosphor::logging::log<phosphor::logging::level::ERR>(
637 "ipmiAppClearMessageFlags: Error - supported only in System(SMS) "
638 "interface");
639 return ipmi::responseCommandNotAvailable();
640 }
641
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000642 if (reserved1 || reserved2)
643 {
644 return ipmi::responseInvalidFieldRequest();
645 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700646
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000647 if (receiveMessage)
648 {
649 bridging.clearResponseQueue();
650 }
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000651
652 if (eventMessageBufferFlag != true && eventMsgBufFull == true)
653 {
654 eventMessageBufferFlag = true;
655 }
656
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000657 try
658 {
Jayaprakash Mutyala52771792022-05-30 14:51:01 +0000659 if (watchdogTimeout)
660 {
661 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
662 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface,
663 wdtInterruptFlagProp, false);
664 }
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000665 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500666 catch (const sdbusplus::exception_t& e)
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000667 {
668 phosphor::logging::log<phosphor::logging::level::ERR>(
669 "ipmiAppClearMessageFlags: can't Clear/Set "
670 "PreTimeoutInterruptOccurFlag");
671 return ipmi::responseUnspecifiedError();
672 }
673
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000674 return ipmi::responseSuccess();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700675}
676
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000677using systemEventType = std::tuple<
678 uint16_t, // Generator ID
679 uint32_t, // Timestamp
680 uint8_t, // Sensor Type
681 uint8_t, // EvM Rev
682 uint8_t, // Sensor Number
683 uint7_t, // Event Type
684 bool, // Event Direction
685 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data
686using oemTsEventType = std::tuple<
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500687 uint32_t, // Timestamp
688 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000689using oemEventType =
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500690 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000691
692/** @brief implements of Read event message buffer command
693 *
694 * @returns IPMI completion code plus response data
695 * - recordID - SEL Record ID
696 * - recordType - Record Type
697 * - generatorID - Generator ID
698 * - timeStamp - Timestamp
699 * - sensorType - Sensor Type
700 * - eventMsgFormatRev - Event Message format version
701 * - sensorNumber - Sensor Number
702 * - eventType - Event Type
703 * - eventDir - Event Direction
704 * - eventData - Event Data field
705 */
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500706ipmi::RspType<uint16_t, // Record ID
707 uint8_t, // Record Type
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000708 std::variant<systemEventType, oemTsEventType,
709 oemEventType>> // Record Content
Vernon Mauerydcff1502022-09-28 11:12:46 -0700710 ipmiAppReadEventMessageBuffer(ipmi::Context::ptr& ctx)
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000711{
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000712 ipmi::ChannelInfo chInfo;
713
714 try
715 {
716 getChannelInfo(ctx->channel, chInfo);
717 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500718 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyalacca21402020-07-16 12:14:10 +0000719 {
720 phosphor::logging::log<phosphor::logging::level::ERR>(
721 "ipmiAppReadEventMessageBuffer: Failed to get Channel Info",
722 phosphor::logging::entry("MSG: %s", e.description()));
723 return ipmi::responseUnspecifiedError();
724 }
725 if (chInfo.mediumType !=
726 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
727 {
728 phosphor::logging::log<phosphor::logging::level::ERR>(
729 "ipmiAppReadEventMessageBuffer: Error - supported only in "
730 "System(SMS) interface");
731 return ipmi::responseCommandNotAvailable();
732 }
733
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000734 uint16_t recordId =
735 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55
736 uint16_t generatorId =
737 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41
738 constexpr uint8_t recordType = 0xC0;
739 constexpr uint8_t eventMsgFormatRev = 0x3A;
740 constexpr uint8_t sensorNumber = 0xFF;
741
742 // TODO need to be implemented.
743 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{};
744 // All '0xFF' since unused.
745 eventData.fill(0xFF);
746
747 // Set the event message buffer flag
748 eventMessageBufferFlag = true;
749
750 return ipmi::responseSuccess(
751 recordId, recordType,
752 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber,
753 static_cast<uint7_t>(0), false, eventData});
754}
755
Vernon Mauerya3702c12019-05-22 13:20:59 -0700756static void register_bridging_functions() __attribute__((constructor));
757static void register_bridging_functions()
758{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000759 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
760 ipmi::app::cmdClearMessageFlags,
761 ipmi::Privilege::User, ipmiAppClearMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700762
Yong Lic3580e92019-08-15 14:36:47 +0800763 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
764 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User,
765 ipmiAppGetMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700766
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000767 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
768 ipmi::app::cmdGetMessage, ipmi::Privilege::User,
769 ipmiAppGetMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700770
Deepak Kumar Sahu24d2d562019-07-14 16:05:19 +0000771 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
772 ipmi::app::cmdSendMessage, ipmi::Privilege::User,
773 ipmiAppSendMessage);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700774
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000775 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
776 ipmi::app::cmdReadEventMessageBuffer,
777 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer);
778
Vernon Mauerya3702c12019-05-22 13:20:59 -0700779 return;
780}