xref: /openbmc/ipmbbridge/ipmbbridged.hpp (revision 314862d949a715f579507d77720798def0a70ac0)
1 /* Copyright 2018 Intel
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software
10  *  distributed under the License is distributed on an "AS IS" BASIS,
11  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  *  See the License for the specific language governing permissions and
13  *  limitations under the License.
14  */
15 
16 #include "ipmbdefines.hpp"
17 
18 #include <boost/container/flat_set.hpp>
19 #include <optional>
20 #include <sdbusplus/asio/object_server.hpp>
21 #include <sdbusplus/message.hpp>
22 #include <vector>
23 
24 #ifndef IPMBBRIDGED_HPP
25 #define IPMBBRIDGED_HPP
26 
27 /**
28  * @brief Ipmb return status codes (sendRequest API call)
29  */
30 enum class ipmbResponseStatus
31 {
32     success = 0,
33     error = 1,
34     invalid_param = 2,
35     busy = 3,
36     timeout = 4,
37 };
38 
39 /**
40  * @brief Ipmb outstanding requests defines
41  */
42 constexpr int ipmbMaxOutstandingRequestsCount = 64;
43 constexpr int ipmbNumberOfTries = 6;
44 constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
45 
46 /**
47  * @brief Ipmb I2C communication
48  */
49 constexpr uint8_t ipmbI2cNumberOfRetries = 2;
50 
51 /**
52  * @brief Ipmb defines
53  */
54 constexpr size_t ipmbMaxDataSize = 256;
55 constexpr size_t ipmbConnectionHeaderLength = 3;
56 constexpr size_t ipmbResponseDataHeaderLength = 4;
57 constexpr size_t ipmbRequestDataHeaderLength = 3;
58 constexpr size_t ipmbAddressSize = 1;
59 constexpr size_t ipmbChecksumSize = 1;
60 constexpr size_t ipmbChecksum2StartOffset = 3;
61 constexpr size_t ipmbMinFrameLength = 7;
62 constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength +
63                                       ipmbResponseDataHeaderLength +
64                                       ipmbChecksumSize + ipmbMaxDataSize;
65 
66 /**
67  * @brief Ipmb misc
68  */
69 constexpr uint8_t ipmbNetFnResponseMask = 0x01;
70 constexpr uint8_t ipmbLunMask = 0x03;
71 constexpr uint8_t ipmbSeqMask = 0x3F;
72 constexpr uint8_t ipmbRsLun = 0x0;
73 
74 /**
75  * @brief Ipmb setters
76  */
77 constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
78 {
79     return ((netFn << 2) | (lun & ipmbLunMask));
80 }
81 
82 constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
83 {
84     return ((seq << 2) | (lun & ipmbLunMask));
85 }
86 
87 constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
88 {
89     return address >> 1;
90 }
91 
92 constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
93 {
94     return netFn |= 1;
95 }
96 
97 /**
98  * @brief Ipmb getters
99  */
100 constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
101 {
102     return netFnLun >> 2;
103 }
104 
105 constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
106 {
107     return netFnLun & ipmbLunMask;
108 }
109 
110 constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
111 {
112     return seqNumLun >> 2;
113 }
114 
115 constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
116 {
117     return seqNumLun & ipmbLunMask;
118 }
119 
120 /**
121  * @brief Ipmb checkers
122  */
123 constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
124 {
125     return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
126            ipmbNetFnResponseMask;
127 }
128 
129 /**
130  * @brief Ipmb request state
131  */
132 enum class ipmbRequestState
133 {
134     invalid,
135     valid,
136     matched,
137 };
138 
139 /**
140  * @brief Channel types
141  */
142 enum class ipmbChannelType
143 {
144     ipmb = 0,
145     me = 1
146 };
147 
148 // TODO w/a to differentiate channel origin of incoming IPMI response:
149 // extracting channel number from 2 oldest bits of seq
150 constexpr ipmbChannelType getChannelFromSeq(const uint8_t &seq)
151 {
152     return static_cast<ipmbChannelType>((seq & 0xC0) >> 6);
153 }
154 
155 /**
156  * @brief IpmbResponse declaration
157  */
158 struct IpmbResponse
159 {
160     uint8_t address;
161     uint8_t netFn;
162     uint8_t rqLun;
163     uint8_t rsSA;
164     uint8_t seq;
165     uint8_t rsLun;
166     uint8_t cmd;
167     uint8_t completionCode;
168     std::vector<uint8_t> data;
169 
170     IpmbResponse();
171 
172     IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
173                  uint8_t seq, uint8_t rsLun, uint8_t cmd,
174                  uint8_t completionCode, std::vector<uint8_t> &inputData);
175 
176     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
177 
178     int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
179 };
180 
181 /**
182  * @brief IpmbRequest declaration
183  */
184 struct IpmbRequest
185 {
186     uint8_t address;
187     uint8_t netFn;
188     uint8_t rsLun;
189     uint8_t rqSA;
190     uint8_t seq;
191     uint8_t rqLun;
192     uint8_t cmd;
193     std::vector<uint8_t> data;
194 
195     size_t dataLength;
196     ipmbRequestState state;
197     std::optional<boost::asio::steady_timer> timer;
198     std::unique_ptr<IpmbResponse> matchedResponse;
199 
200     // creates empty request with empty timer object
201     IpmbRequest();
202 
203     IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
204                 uint8_t seq, uint8_t rqLun, uint8_t cmd,
205                 std::vector<uint8_t> &inputData);
206 
207     IpmbRequest(const IpmbRequest &) = delete;
208     IpmbRequest &operator=(IpmbRequest const &) = delete;
209 
210     void incomingMessageHandler();
211 
212     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
213         returnMatchedResponse();
214 
215     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
216         returnStatusResponse(int status);
217 
218     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
219 
220     int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
221 
222     // TODO w/a to differentiate channel origin of incoming IPMI response:
223     // saving channel number at two oldest unused bits of seq
224     void addChannelToSeq(const ipmbChannelType &channelType);
225 };
226 
227 /**
228  * @brief Command filtering class declaration
229  *
230  * This feature provides simple mechanism for filtering out commands - which are
231  * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
232  */
233 class IpmbCommandFilter
234 {
235   public:
236     // function checking if netFn & cmd combination exist in blocked command
237     // list
238     bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
239     // function adding netfFn & cmd combination to the blocked command list
240     void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
241 
242   private:
243     boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
244 };
245 
246 /**
247  * @brief Command filtering defines
248  */
249 
250 constexpr uint8_t ipmbIpmiInvalidCommand = 0xC1;
251 
252 constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
253 {
254     return reqNetFn & ~ipmbNetFnResponseMask;
255 }
256 
257 /**
258  * @brief IpmbChannel class declaration
259  */
260 class IpmbChannel
261 {
262   public:
263     IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
264                 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
265                 std::shared_ptr<IpmbCommandFilter> commandFilter);
266 
267     IpmbChannel(const IpmbChannel &) = delete;
268     IpmbChannel &operator=(IpmbChannel const &) = delete;
269 
270     int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
271 
272     bool seqNumGet(uint8_t &seq);
273 
274     ipmbChannelType getChannelType();
275 
276     uint8_t getBmcSlaveAddress();
277 
278     uint8_t getRqSlaveAddress();
279 
280     void addFilter(const uint8_t respNetFn, const uint8_t cmd);
281 
282     void processI2cEvent();
283 
284     void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
285                           size_t retriesAttempted);
286 
287     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
288         requestAdd(boost::asio::yield_context &yield,
289                    std::shared_ptr<IpmbRequest> requestToSend);
290 
291   private:
292     boost::asio::ip::tcp::socket i2cSlaveSocket;
293     boost::asio::posix::stream_descriptor i2cMasterSocket;
294 
295     int ipmbi2cMasterFd;
296     int ipmbi2cSlaveFd;
297 
298     uint8_t ipmbBmcSlaveAddress;
299     uint8_t ipmbRqSlaveAddress;
300 
301     ipmbChannelType type;
302 
303     std::shared_ptr<IpmbCommandFilter> commandFilter;
304 
305     // array storing outstanding requests
306     std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
307         outstandingRequests;
308 
309     void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
310                               std::shared_ptr<std::vector<uint8_t>> buffer);
311 
312     void responseMatch(std::unique_ptr<IpmbResponse> &response);
313 
314     void makeRequestInvalid(IpmbRequest &request);
315 
316     void makeRequestValid(std::shared_ptr<IpmbRequest> request);
317 };
318 
319 #endif
320