xref: /openbmc/ipmbbridge/ipmbbridged.hpp (revision a642a9480d348bb6677f4badb635ebf881f3bcd0)
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 /**
149  * @brief Channel configuration structure
150  */
151 struct IpmbChannelConfig
152 {
153     ipmbChannelType type;
154     const char *ipmbI2cSlave;
155     const char *ipmbI2cMaster;
156     uint8_t ipmbBmcSlaveAddress;
157     uint8_t ipmbRqSlaveAddress;
158 };
159 
160 // TODO w/a to differentiate channel origin of incoming IPMI response:
161 // extracting channel number from 2 oldest bits of seq
162 constexpr ipmbChannelType getChannelFromSeq(const uint8_t &seq)
163 {
164     return static_cast<ipmbChannelType>((seq & 0xC0) >> 6);
165 }
166 
167 /**
168  * @brief IpmbResponse declaration
169  */
170 struct IpmbResponse
171 {
172     uint8_t address;
173     uint8_t netFn;
174     uint8_t rqLun;
175     uint8_t rsSA;
176     uint8_t seq;
177     uint8_t rsLun;
178     uint8_t cmd;
179     uint8_t completionCode;
180     std::vector<uint8_t> data;
181 
182     IpmbResponse();
183 
184     IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
185                  uint8_t seq, uint8_t rsLun, uint8_t cmd,
186                  uint8_t completionCode, std::vector<uint8_t> &inputData);
187 
188     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
189 
190     int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
191 };
192 
193 /**
194  * @brief IpmbRequest declaration
195  */
196 struct IpmbRequest
197 {
198     uint8_t address;
199     uint8_t netFn;
200     uint8_t rsLun;
201     uint8_t rqSA;
202     uint8_t seq;
203     uint8_t rqLun;
204     uint8_t cmd;
205     std::vector<uint8_t> data;
206 
207     size_t dataLength;
208     ipmbRequestState state;
209     std::optional<boost::asio::steady_timer> timer;
210     std::unique_ptr<IpmbResponse> matchedResponse;
211 
212     // creates empty request with empty timer object
213     IpmbRequest();
214 
215     IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
216                 uint8_t seq, uint8_t rqLun, uint8_t cmd,
217                 std::vector<uint8_t> &inputData);
218 
219     IpmbRequest(const IpmbRequest &) = delete;
220     IpmbRequest &operator=(IpmbRequest const &) = delete;
221 
222     void incomingMessageHandler();
223 
224     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
225         returnMatchedResponse();
226 
227     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
228         returnStatusResponse(int status);
229 
230     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
231 
232     int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
233 
234     // TODO w/a to differentiate channel origin of incoming IPMI response:
235     // saving channel number at two oldest unused bits of seq
236     void addChannelToSeq(const ipmbChannelType &channelType);
237 };
238 
239 /**
240  * @brief Command filtering class declaration
241  *
242  * This feature provides simple mechanism for filtering out commands - which are
243  * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
244  */
245 class IpmbCommandFilter
246 {
247   public:
248     // function checking if netFn & cmd combination exist in blocked command
249     // list
250     bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
251     // function adding netfFn & cmd combination to the blocked command list
252     void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
253 
254   private:
255     boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
256 };
257 
258 /**
259  * @brief Command filtering defines
260  */
261 
262 constexpr uint8_t ipmbIpmiInvalidCommand = 0xC1;
263 
264 constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
265 {
266     return reqNetFn & ~ipmbNetFnResponseMask;
267 }
268 
269 /**
270  * @brief IpmbChannel class declaration
271  */
272 class IpmbChannel
273 {
274   public:
275     IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
276                 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
277                 std::shared_ptr<IpmbCommandFilter> commandFilter);
278 
279     IpmbChannel(const IpmbChannel &) = delete;
280     IpmbChannel &operator=(IpmbChannel const &) = delete;
281 
282     int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
283 
284     bool seqNumGet(uint8_t &seq);
285 
286     ipmbChannelType getChannelType();
287 
288     uint8_t getBmcSlaveAddress();
289 
290     uint8_t getRqSlaveAddress();
291 
292     void addFilter(const uint8_t respNetFn, const uint8_t cmd);
293 
294     void processI2cEvent();
295 
296     void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
297                           size_t retriesAttempted);
298 
299     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
300         requestAdd(boost::asio::yield_context &yield,
301                    std::shared_ptr<IpmbRequest> requestToSend);
302 
303   private:
304     boost::asio::ip::tcp::socket i2cSlaveSocket;
305     boost::asio::posix::stream_descriptor i2cMasterSocket;
306 
307     int ipmbi2cMasterFd;
308     int ipmbi2cSlaveFd;
309 
310     uint8_t ipmbBmcSlaveAddress;
311     uint8_t ipmbRqSlaveAddress;
312 
313     ipmbChannelType type;
314 
315     std::shared_ptr<IpmbCommandFilter> commandFilter;
316 
317     // array storing outstanding requests
318     std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
319         outstandingRequests;
320 
321     void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
322                               std::shared_ptr<std::vector<uint8_t>> buffer);
323 
324     void responseMatch(std::unique_ptr<IpmbResponse> &response);
325 
326     void makeRequestInvalid(IpmbRequest &request);
327 
328     void makeRequestValid(std::shared_ptr<IpmbRequest> request);
329 };
330 
331 #endif
332