xref: /openbmc/intel-ipmi-oem/src/chassiscommands.cpp (revision de03ada04dd973c33eaf08b9354eb2f8ba146e54)
1 /*
2 // Copyright (c) 2019 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 #include "xyz/openbmc_project/Common/error.hpp"
17 
18 #include <ipmid/api.hpp>
19 #include <ipmid/utils.hpp>
20 #include <nlohmann/json.hpp>
21 #include <phosphor-logging/elog-errors.hpp>
22 #include <phosphor-logging/log.hpp>
23 #include <sdbusplus/timer.hpp>
24 #include <xyz/openbmc_project/Chassis/Intrusion/client.hpp>
25 #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
26 
27 #include <fstream>
28 #include <iostream>
29 #include <regex>
30 #include <stdexcept>
31 #include <string_view>
32 
33 using namespace phosphor::logging;
34 
35 namespace ipmi::chassis
36 {
37 static constexpr const char* buttonIntf = "xyz.openbmc_project.Chassis.Buttons";
38 
39 const static constexpr char* idButtonPath =
40     "/xyz/openbmc_project/chassis/buttons/id";
41 static constexpr const char* powerButtonPath =
42     "/xyz/openbmc_project/chassis/buttons/power";
43 static constexpr const char* resetButtonPath =
44     "/xyz/openbmc_project/chassis/buttons/reset";
45 static constexpr const char* interruptButtonPath =
46     "/xyz/openbmc_project/chassis/buttons/nmi";
47 
48 const static constexpr char* idButtonProp = "ButtonPressed";
49 
50 const static constexpr char* ledService =
51     "xyz.openbmc_project.LED.GroupManager";
52 const static constexpr char* ledIDOnObj =
53     "/xyz/openbmc_project/led/groups/enclosure_identify";
54 const static constexpr char* ledIDBlinkObj =
55     "/xyz/openbmc_project/led/groups/enclosure_identify_blink";
56 const static constexpr char* ledInterface = "xyz.openbmc_project.Led.Group";
57 const static constexpr char* ledProp = "Asserted";
58 enum class ChassisIDState
59 {
60     off = 0,
61     temporary = 1,
62     indefinite = 2,
63 };
64 static ChassisIDState chassisIDState = ChassisIDState::off;
65 
66 constexpr size_t defaultIdentifyTimeOut = 15;
67 
68 std::unique_ptr<sdbusplus::Timer> identifyTimer
69     __attribute__((init_priority(101)));
70 std::unique_ptr<sdbusplus::bus::match_t> matchPtr
71     __attribute__((init_priority(101)));
72 
73 static void registerChassisFunctions() __attribute__((constructor));
74 
75 static ipmi::ServiceCache LEDService(ledInterface, ledIDBlinkObj);
76 
enclosureIdentifyLed(const char * objName,bool isIdLedOn)77 void enclosureIdentifyLed(const char* objName, bool isIdLedOn)
78 {
79     auto bus = getSdBus();
80 
81     try
82     {
83         std::string service = LEDService.getService(*bus);
84         setDbusProperty(*bus, service, objName, ledInterface, ledProp,
85                         isIdLedOn);
86     }
87     catch (const std::exception& e)
88     {
89         log<level::ERR>("enclosureIdentifyLed: can't set property",
90                         entry("ERR=%s", e.what()));
91     }
92 }
93 
getIDState(const char * objName,bool & state)94 bool getIDState(const char* objName, bool& state)
95 {
96     auto bus = getSdBus();
97 
98     try
99     {
100         std::string service = LEDService.getService(*bus);
101         ipmi::Value enabled =
102             getDbusProperty(*bus, service, objName, ledInterface, ledProp);
103         state = std::get<bool>(enabled);
104     }
105     catch (const sdbusplus::exception_t& e)
106     {
107         log<level::ERR>("Fail to get property", entry("PATH=%s", objName),
108                         entry("ERROR=%s", e.what()));
109         return false;
110     }
111     return true;
112 }
113 
enclosureIdentifyLedBlinkOff()114 void enclosureIdentifyLedBlinkOff()
115 {
116     chassisIDState = ChassisIDState::off;
117     enclosureIdentifyLed(ledIDBlinkObj, false);
118 }
119 
idButtonPropChanged(sdbusplus::message_t & msg)120 void idButtonPropChanged(sdbusplus::message_t& msg)
121 {
122     bool asserted = false;
123     bool buttonPressed = false;
124 
125     std::map<std::string, ipmi::Value> props;
126     std::vector<std::string> inval;
127     std::string iface;
128     msg.read(iface, props, inval);
129 
130     for (const auto& t : props)
131     {
132         auto key = t.first;
133         auto value = t.second;
134 
135         if (key == idButtonProp)
136         {
137             buttonPressed = std::get<bool>(value);
138         }
139         break;
140     }
141 
142     if (buttonPressed)
143     {
144         if (identifyTimer->isRunning())
145         {
146             log<level::INFO>("ID timer is running");
147         }
148 
149         // make sure timer is stopped
150         identifyTimer->stop();
151 
152         if (!getIDState(ledIDBlinkObj, asserted))
153         {
154             return;
155         }
156 
157         if (asserted)
158         {
159             // LED is blinking, turn off the LED
160             chassisIDState = ChassisIDState::off;
161             enclosureIdentifyLed(ledIDBlinkObj, false);
162             enclosureIdentifyLed(ledIDOnObj, false);
163         }
164         else
165         {
166             // toggle the IED on/off
167             if (!getIDState(ledIDOnObj, asserted))
168             {
169                 return;
170             }
171             enclosureIdentifyLed(ledIDOnObj, !asserted);
172         }
173     }
174 }
175 
createIdentifyTimer()176 void createIdentifyTimer()
177 {
178     if (!identifyTimer)
179     {
180         identifyTimer =
181             std::make_unique<sdbusplus::Timer>(enclosureIdentifyLedBlinkOff);
182     }
183 }
184 
ipmiChassisIdentify(std::optional<uint8_t> interval,std::optional<uint8_t> force)185 ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval,
186                                     std::optional<uint8_t> force)
187 {
188     uint8_t identifyInterval = interval.value_or(defaultIdentifyTimeOut);
189     bool forceIdentify = force.value_or(0) & 0x01;
190 
191     enclosureIdentifyLed(ledIDOnObj, false);
192     identifyTimer->stop();
193 
194     if (identifyInterval || forceIdentify)
195     {
196         enclosureIdentifyLed(ledIDBlinkObj, true);
197         if (forceIdentify)
198         {
199             chassisIDState = ChassisIDState::indefinite;
200             return ipmi::responseSuccess();
201         }
202         chassisIDState = ChassisIDState::temporary;
203         // start the timer
204         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
205             std::chrono::seconds(identifyInterval));
206         identifyTimer->start(time);
207     }
208     else
209     {
210         chassisIDState = ChassisIDState::off;
211         enclosureIdentifyLed(ledIDBlinkObj, false);
212     }
213     return ipmi::responseSuccess();
214 }
215 
216 namespace power_policy
217 {
218 /* helper function for Get Chassis Status Command
219  */
getPowerRestorePolicy()220 std::optional<uint2_t> getPowerRestorePolicy()
221 {
222     constexpr const char* powerRestorePath =
223         "/xyz/openbmc_project/control/host0/power_restore_policy";
224     constexpr const char* powerRestoreIntf =
225         "xyz.openbmc_project.Control.Power.RestorePolicy";
226     uint2_t restorePolicy = 0;
227     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
228 
229     try
230     {
231         auto service =
232             ipmi::getService(*busp, powerRestoreIntf, powerRestorePath);
233 
234         ipmi::Value result =
235             ipmi::getDbusProperty(*busp, service, powerRestorePath,
236                                   powerRestoreIntf, "PowerRestorePolicy");
237         auto powerRestore = sdbusplus::xyz::openbmc_project::Control::Power::
238             server::RestorePolicy::convertPolicyFromString(
239                 std::get<std::string>(result));
240 
241         using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
242         switch (powerRestore)
243         {
244             case RestorePolicy::Policy::AlwaysOff:
245                 restorePolicy = 0x00;
246                 break;
247             case RestorePolicy::Policy::Restore:
248                 restorePolicy = 0x01;
249                 break;
250             case RestorePolicy::Policy::AlwaysOn:
251                 restorePolicy = 0x02;
252                 break;
253             default:
254                 break;
255         }
256     }
257     catch (const std::exception& e)
258     {
259         log<level::ERR>("Failed to fetch PowerRestorePolicy property",
260                         entry("ERROR=%s", e.what()),
261                         entry("PATH=%s", powerRestorePath),
262                         entry("INTERFACE=%s", powerRestoreIntf));
263         return std::nullopt;
264     }
265     return std::make_optional(restorePolicy);
266 }
267 
268 /*
269  * getPowerStatus
270  * helper function for Get Chassis Status Command
271  * return - optional value for pgood (no value on error)
272  */
getPowerStatus()273 std::optional<bool> getPowerStatus()
274 {
275     bool powerGood = false;
276     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
277     try
278     {
279         constexpr const char* chassisStatePath =
280             "/xyz/openbmc_project/state/chassis0";
281         constexpr const char* chassisStateIntf =
282             "xyz.openbmc_project.State.Chassis";
283         auto service =
284             ipmi::getService(*busp, chassisStateIntf, chassisStatePath);
285 
286         ipmi::Value variant =
287             ipmi::getDbusProperty(*busp, service, chassisStatePath,
288                                   chassisStateIntf, "CurrentPowerState");
289         std::string powerState = std::get<std::string>(variant);
290         if (powerState == "xyz.openbmc_project.State.Chassis.PowerState.On")
291         {
292             powerGood = true;
293         }
294     }
295     catch (const std::exception& e)
296     {
297         log<level::ERR>("Failed to fetch power state property",
298                         entry("ERROR=%s", e.what()));
299         return std::nullopt;
300     }
301     return std::make_optional(powerGood);
302 }
303 
304 /*
305  * getACFailStatus
306  * helper function for Get Chassis Status Command
307  * return - bool value for ACFail (false on error)
308  */
getACFailStatus()309 bool getACFailStatus()
310 {
311     constexpr const char* acBootObj =
312         "/xyz/openbmc_project/control/host0/ac_boot";
313     constexpr const char* acBootIntf = "xyz.openbmc_project.Common.ACBoot";
314     std::string acFail;
315     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
316     try
317     {
318         auto service = ipmi::getService(*bus, acBootIntf, acBootObj);
319 
320         ipmi::Value variant = ipmi::getDbusProperty(*bus, service, acBootObj,
321                                                     acBootIntf, "ACBoot");
322         acFail = std::get<std::string>(variant);
323     }
324     catch (const std::exception& e)
325     {
326         log<level::ERR>(
327             "Failed to fetch ACBoot property", entry("ERROR=%s", e.what()),
328             entry("PATH=%s", acBootObj), entry("INTERFACE=%s", acBootIntf));
329     }
330     return acFail == "True";
331 }
332 } // namespace power_policy
333 
getButtonEnabled(const std::string & buttonPath)334 static std::optional<bool> getButtonEnabled(const std::string& buttonPath)
335 {
336     bool buttonDisabled = false;
337     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
338     try
339     {
340         auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
341         ipmi::Value disabled = ipmi::getDbusProperty(
342             *busp, service, buttonPath, buttonIntf, "ButtonMasked");
343         buttonDisabled = std::get<bool>(disabled);
344     }
345     catch (const sdbusplus::exception_t& e)
346     {
347         log<level::ERR>("Fail to get button disabled property",
348                         entry("PATH=%s", buttonPath.c_str()),
349                         entry("ERROR=%s", e.what()));
350         return std::nullopt;
351     }
352     return std::make_optional(buttonDisabled);
353 }
354 
setButtonEnabled(const std::string & buttonPath,const bool disabled)355 static bool setButtonEnabled(const std::string& buttonPath, const bool disabled)
356 {
357     try
358     {
359         auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
360         ipmi::setDbusProperty(*getSdBus(), service, buttonPath, buttonIntf,
361                               "ButtonMasked", disabled);
362     }
363     catch (const std::exception& e)
364     {
365         log<level::ERR>("Failed to set button disabled",
366                         entry("EXCEPTION=%s, REQUEST=%x", e.what(), disabled));
367         return -1;
368     }
369 
370     return 0;
371 }
372 
getRestartCause(ipmi::Context::ptr & ctx,std::string & restartCause)373 static bool getRestartCause(ipmi::Context::ptr& ctx, std::string& restartCause)
374 {
375     constexpr const char* restartCausePath =
376         "/xyz/openbmc_project/control/host0/restart_cause";
377     constexpr const char* restartCauseIntf =
378         "xyz.openbmc_project.Control.Host.RestartCause";
379 
380     std::string service;
381     boost::system::error_code ec =
382         ipmi::getService(ctx, restartCauseIntf, restartCausePath, service);
383 
384     if (!ec)
385     {
386         ec = ipmi::getDbusProperty(ctx, service, restartCausePath,
387                                    restartCauseIntf, "RestartCause",
388                                    restartCause);
389     }
390     if (ec)
391     {
392         log<level::ERR>("Failed to fetch RestartCause property",
393                         entry("ERROR=%s", ec.message().c_str()),
394                         entry("PATH=%s", restartCausePath),
395                         entry("INTERFACE=%s", restartCauseIntf));
396         return false;
397     }
398     return true;
399 }
400 
checkIPMIRestartCause(ipmi::Context::ptr & ctx,bool & ipmiRestartCause)401 static bool checkIPMIRestartCause(ipmi::Context::ptr& ctx,
402                                   bool& ipmiRestartCause)
403 {
404     std::string restartCause;
405     if (!getRestartCause(ctx, restartCause))
406     {
407         return false;
408     }
409     ipmiRestartCause =
410         (restartCause ==
411          "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand");
412     return true;
413 }
414 
415 //----------------------------------------------------------------------
416 // Get Chassis Status commands
417 //----------------------------------------------------------------------
418 ipmi::RspType<bool,    // Power is on
419               bool,    // Power overload
420               bool,    // Interlock
421               bool,    // power fault
422               bool,    // power control fault
423               uint2_t, // power restore policy
424               bool,    // reserved
425 
426               bool,    // AC failed
427               bool,    // last power down caused by a Power overload
428               bool,    // last power down caused by a power interlock
429               bool,    // last power down caused by power fault
430               bool,    // last ‘Power is on’ state was entered via IPMI command
431               uint3_t, // reserved
432 
433               bool,    // Chassis intrusion active
434               bool,    // Front Panel Lockout active
435               bool,    // Drive Fault
436               bool,    // Cooling/fan fault detected
437               uint2_t, // Chassis Identify State
438               bool,    // Chassis Identify command and state info supported
439               bool,    // reserved
440 
441               bool,    // Power off button disabled
442               bool,    // Reset button disabled
443               bool,    // Diagnostic Interrupt button disabled
444               bool,    // Standby (sleep) button disabled
445               bool,    // Power off button disable allowed
446               bool,    // Reset button disable allowed
447               bool,    // Diagnostic Interrupt button disable allowed
448               bool     // Standby (sleep) button disable allowed
449               >
ipmiGetChassisStatus(ipmi::Context::ptr ctx)450     ipmiGetChassisStatus(ipmi::Context::ptr ctx)
451 {
452     std::optional<uint2_t> restorePolicy =
453         power_policy::getPowerRestorePolicy();
454     std::optional<bool> powerGood = power_policy::getPowerStatus();
455     if (!restorePolicy || !powerGood)
456     {
457         return ipmi::responseUnspecifiedError();
458     }
459 
460     //  Front Panel Button Capabilities and disable/enable status(Optional)
461     std::optional<bool> powerButtonReading = getButtonEnabled(powerButtonPath);
462     // allow disable if the interface is present
463     bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading);
464     // default return the button is enabled (not disabled)
465     bool powerButtonDisabled = false;
466     if (powerButtonDisableAllow)
467     {
468         // return the real value of the button status, if present
469         powerButtonDisabled = *powerButtonReading;
470     }
471 
472     std::optional<bool> resetButtonReading = getButtonEnabled(resetButtonPath);
473     // allow disable if the interface is present
474     bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading);
475     // default return the button is enabled (not disabled)
476     bool resetButtonDisabled = false;
477     if (resetButtonDisableAllow)
478     {
479         // return the real value of the button status, if present
480         resetButtonDisabled = *resetButtonReading;
481     }
482 
483     std::optional<bool> interruptButtonReading =
484         getButtonEnabled(interruptButtonPath);
485     // allow disable if the interface is present
486     bool interruptButtonDisableAllow =
487         static_cast<bool>(interruptButtonReading);
488     // default return the button is enabled (not disabled)
489     bool interruptButtonDisabled = false;
490     if (interruptButtonDisableAllow)
491     {
492         // return the real value of the button status, if present
493         interruptButtonDisabled = *interruptButtonReading;
494     }
495 
496     bool powerDownAcFailed = power_policy::getACFailStatus();
497 
498     bool powerStatusIPMI = false;
499     if (!checkIPMIRestartCause(ctx, powerStatusIPMI))
500     {
501         return ipmi::responseUnspecifiedError();
502     }
503 
504     using Intrusion =
505         sdbusplus::client::xyz::openbmc_project::chassis::Intrusion<>;
506 
507     std::vector<std::string> chassisIntrusionIntf = {
508         std::string(Intrusion::interface)};
509     ipmi::ObjectTree chassisIntrusionObjs;
510     bool chassisIntrusionActive = false;
511 
512     boost::system::error_code ec = ipmi::getSubTree(
513         ctx, chassisIntrusionIntf, std::string("/"), 0, chassisIntrusionObjs);
514 
515     if (ec)
516     {
517         log<level::ERR>("Failed to find Chassis Intrusion Interface on D-Bus",
518                         entry("ERROR=%s", ec.message().c_str()));
519     }
520 
521     chassisIntrusionActive = !chassisIntrusionObjs.empty();
522 
523     // This response has a lot of hard-coded, unsupported fields
524     // They are set to false or 0
525     constexpr bool powerOverload = false;
526     constexpr bool chassisInterlock = false;
527     constexpr bool powerFault = false;
528     constexpr bool powerControlFault = false;
529     constexpr bool powerDownOverload = false;
530     constexpr bool powerDownInterlock = false;
531     constexpr bool powerDownPowerFault = false;
532     constexpr bool frontPanelLockoutActive = false;
533     constexpr bool driveFault = false;
534     constexpr bool coolingFanFault = false;
535     // chassisIdentifySupport set because this command is implemented
536     constexpr bool chassisIdentifySupport = true;
537     uint2_t chassisIdentifyState = types::enum_cast<uint2_t>(chassisIDState);
538     constexpr bool sleepButtonDisabled = false;
539     constexpr bool sleepButtonDisableAllow = false;
540 
541     return ipmi::responseSuccess(
542         *powerGood, powerOverload, chassisInterlock, powerFault,
543         powerControlFault, *restorePolicy,
544         false, // reserved
545 
546         powerDownAcFailed, powerDownOverload, powerDownInterlock,
547         powerDownPowerFault, powerStatusIPMI,
548         uint3_t(0), // reserved
549 
550         chassisIntrusionActive, frontPanelLockoutActive, driveFault,
551         coolingFanFault, chassisIdentifyState, chassisIdentifySupport,
552         false, // reserved
553 
554         powerButtonDisabled, resetButtonDisabled, interruptButtonDisabled,
555         sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow,
556         interruptButtonDisableAllow, sleepButtonDisableAllow);
557 }
558 
getRestartCauseValue(const std::string & cause)559 static uint4_t getRestartCauseValue(const std::string& cause)
560 {
561     uint4_t restartCauseValue = 0;
562     if (cause == "xyz.openbmc_project.State.Host.RestartCause.Unknown")
563     {
564         restartCauseValue = 0x0;
565     }
566     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand")
567     {
568         restartCauseValue = 0x1;
569     }
570     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.ResetButton")
571     {
572         restartCauseValue = 0x2;
573     }
574     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PowerButton")
575     {
576         restartCauseValue = 0x3;
577     }
578     else if (cause ==
579              "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
580     {
581         restartCauseValue = 0x4;
582     }
583     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.OEM")
584     {
585         restartCauseValue = 0x5;
586     }
587     else if (cause ==
588              "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn")
589     {
590         restartCauseValue = 0x6;
591     }
592     else if (cause == "xyz.openbmc_project.State.Host.RestartCause."
593                       "PowerPolicyPreviousState")
594     {
595         restartCauseValue = 0x7;
596     }
597     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PEFReset")
598     {
599         restartCauseValue = 0x8;
600     }
601     else if (cause ==
602              "xyz.openbmc_project.State.Host.RestartCause.PEFPowerCycle")
603     {
604         restartCauseValue = 0x9;
605     }
606     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.SoftReset")
607     {
608         restartCauseValue = 0xa;
609     }
610     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.RTCWakeup")
611     {
612         restartCauseValue = 0xb;
613     }
614     return restartCauseValue;
615 }
616 
617 ipmi::RspType<uint4_t, // Restart Cause
618               uint4_t, // reserved
619               uint8_t  // channel number
620               >
ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)621     ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)
622 {
623     std::string restartCauseStr;
624     if (!getRestartCause(ctx, restartCauseStr))
625     {
626         return ipmi::responseUnspecifiedError();
627     }
628     constexpr uint4_t reserved = 0;
629     auto channel = static_cast<uint8_t>(ctx->channel);
630     return ipmi::responseSuccess(getRestartCauseValue(restartCauseStr),
631                                  reserved, channel);
632 }
633 
ipmiSetFrontPanelButtonEnables(bool disablePowerButton,bool disableResetButton,bool disableInterruptButton,bool disableSleepButton,uint4_t reserved)634 ipmi::RspType<> ipmiSetFrontPanelButtonEnables(
635     bool disablePowerButton, bool disableResetButton,
636     bool disableInterruptButton, [[maybe_unused]] bool disableSleepButton,
637     uint4_t reserved)
638 {
639     if (reserved)
640     {
641         return ipmi::responseInvalidFieldRequest();
642     }
643     bool error = false;
644 
645     error |= setButtonEnabled(powerButtonPath, disablePowerButton);
646     error |= setButtonEnabled(resetButtonPath, disableResetButton);
647     error |= setButtonEnabled(interruptButtonPath, disableInterruptButton);
648 
649     if (error)
650     {
651         return ipmi::responseUnspecifiedError();
652     }
653 
654     return ipmi::responseSuccess();
655 }
656 
registerChassisFunctions(void)657 static void registerChassisFunctions(void)
658 {
659     log<level::INFO>("Registering Chassis commands");
660 
661     createIdentifyTimer();
662 
663     if (matchPtr == nullptr)
664     {
665         using namespace sdbusplus::bus::match::rules;
666         auto bus = getSdBus();
667 
668         matchPtr = std::make_unique<sdbusplus::bus::match_t>(
669             *bus,
670             sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
671                                                             buttonIntf),
672             std::bind(idButtonPropChanged, std::placeholders::_1));
673     }
674 
675     // <Chassis Identify>
676     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
677                           ipmi::chassis::cmdChassisIdentify,
678                           ipmi::Privilege::Operator, ipmiChassisIdentify);
679     // <Get Chassis Status>
680     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
681                           ipmi::chassis::cmdGetChassisStatus,
682                           ipmi::Privilege::User, ipmiGetChassisStatus);
683     // <Get System Restart Cause>
684     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
685                           ipmi::chassis::cmdGetSystemRestartCause,
686                           ipmi::Privilege::User, ipmiGetSystemRestartCause);
687     // <Set Front Panel Enables>
688     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
689                           ipmi::chassis::cmdSetFrontPanelButtonEnables,
690                           ipmi::Privilege::Admin,
691                           ipmiSetFrontPanelButtonEnables);
692 }
693 
694 } // namespace ipmi::chassis
695