1 /**
2  * Copyright 2017 Google Inc.
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 
17 #include "manualcmds.hpp"
18 
19 #include "control.hpp"
20 #include "dbus_mode.hpp"
21 #include "manual_messages.hpp"
22 
23 #include <ipmid/api.h>
24 
25 #include <sdbusplus/bus.hpp>
26 #include <sdbusplus/message.hpp>
27 
28 #include <map>
29 #include <memory>
30 #include <string>
31 #include <tuple>
32 #include <variant>
33 
34 namespace pid_control
35 {
36 namespace ipmi
37 {
38 
39 static constexpr auto manualProperty = "Manual";
40 static constexpr auto failsafeProperty = "FailSafe";
41 
42 ipmi_ret_t ZoneControlIpmiHandler::getFailsafeModeState(const uint8_t* reqBuf,
43                                                         uint8_t* replyBuf,
44                                                         size_t* dataLen)
45 {
46     bool current;
47 
48     if (*dataLen < sizeof(struct FanCtrlRequest))
49     {
50         return IPMI_CC_INVALID;
51     }
52 
53     const auto request =
54         reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
55 
56     ipmi_ret_t rc = _control->getFanCtrlProperty(request->zone, &current,
57                                                  failsafeProperty);
58     if (rc)
59     {
60         return rc;
61     }
62 
63     *replyBuf = (uint8_t)current;
64     *dataLen = sizeof(uint8_t);
65     return IPMI_CC_OK;
66 }
67 
68 /*
69  * <method name="GetAll">
70  *   <arg name="interface" direction="in" type="s"/>
71  *   <arg name="properties" direction="out" type="a{sv}"/>
72  * </method>
73  */
74 ipmi_ret_t ZoneControlIpmiHandler::getManualModeState(const uint8_t* reqBuf,
75                                                       uint8_t* replyBuf,
76                                                       size_t* dataLen)
77 {
78     bool current;
79 
80     if (*dataLen < sizeof(struct FanCtrlRequest))
81     {
82         return IPMI_CC_INVALID;
83     }
84 
85     const auto request =
86         reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
87 
88     ipmi_ret_t rc = _control->getFanCtrlProperty(request->zone, &current,
89                                                  manualProperty);
90     if (rc)
91     {
92         return rc;
93     }
94 
95     *replyBuf = (uint8_t)current;
96     *dataLen = sizeof(uint8_t);
97     return IPMI_CC_OK;
98 }
99 
100 /*
101  * <method name="Set">
102  *   <arg name="interface" direction="in" type="s"/>
103  *   <arg name="property" direction="in" type="s"/>
104  *   <arg name="value" direction="in" type="v"/>
105  * </method>
106  */
107 ipmi_ret_t ZoneControlIpmiHandler::setManualModeState(
108     const uint8_t* reqBuf, [[maybe_unused]] uint8_t* replyBuf,
109     const size_t* dataLen)
110 {
111     if (*dataLen < sizeof(struct FanCtrlRequestSet))
112     {
113         return IPMI_CC_INVALID;
114     }
115 
116     const auto request =
117         reinterpret_cast<const struct FanCtrlRequestSet*>(&reqBuf[0]);
118 
119     /* 0 is false, 1 is true */
120     ipmi_ret_t rc = _control->setFanCtrlProperty(
121         request->zone, static_cast<bool>(request->value), manualProperty);
122     return rc;
123 }
124 
125 /* Three command packages: get, set true, set false */
126 ipmi_ret_t manualModeControl(ZoneControlIpmiHandler* handler,
127                              [[maybe_unused]] ipmi_cmd_t cmd,
128                              const uint8_t* reqBuf, uint8_t* replyCmdBuf,
129                              size_t* dataLen)
130 {
131     // FanCtrlRequest is the smaller of the requests, so it's at a minimum.
132     if (*dataLen < sizeof(struct FanCtrlRequest))
133     {
134         return IPMI_CC_INVALID;
135     }
136 
137     const auto request =
138         reinterpret_cast<const struct FanCtrlRequest*>(&reqBuf[0]);
139 
140     ipmi_ret_t rc = IPMI_CC_OK;
141 
142     switch (request->command)
143     {
144         case getControlState:
145             return handler->getManualModeState(reqBuf, replyCmdBuf, dataLen);
146         case setControlState:
147             return handler->setManualModeState(reqBuf, replyCmdBuf, dataLen);
148         case getFailsafeState:
149             return handler->getFailsafeModeState(reqBuf, replyCmdBuf, dataLen);
150         default:
151             rc = IPMI_CC_INVALID;
152     }
153 
154     return rc;
155 }
156 
157 } // namespace ipmi
158 } // namespace pid_control
159