xref: /openbmc/phosphor-host-ipmid/user_channel/channelcommands.cpp (revision 2543bd51e2ac1cc7731ae7b0976a0d52d9a530c5)
1 /*
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 
17 #include "channel_layer.hpp"
18 
19 #include <ipmid/api.hpp>
20 #include <phosphor-logging/lg2.hpp>
21 
22 #include <regex>
23 
24 namespace ipmi
25 {
26 
27 constexpr Cc ccPayloadTypeNotSupported = 0x80;
28 
responsePayloadTypeNotSupported()29 static inline auto responsePayloadTypeNotSupported()
30 {
31     return response(ccPayloadTypeNotSupported);
32 }
33 
34 /** @brief implements the set channel access command
35  *  @ param ctx - context pointer
36  *  @ param channel - channel number
37  *  @ param reserved - skip 4 bits
38  *  @ param accessMode - access mode for IPMI messaging
39  *  @ param usrAuth - user level authentication (enable/disable)
40  *  @ param msgAuth - per message authentication (enable/disable)
41  *  @ param alertDisabled - PEF alerting (enable/disable)
42  *  @ param chanAccess - channel access
43  *  @ param channelPrivLimit - channel privilege limit
44  *  @ param reserved - skip 3 bits
45  *  @ param channelPrivMode - channel priviledge mode
46  *
47  *  @ returns IPMI completion code
48  **/
ipmiSetChannelAccess(Context::ptr ctx,uint4_t channel,uint4_t reserved1,uint3_t accessMode,bool usrAuth,bool msgAuth,bool alertDisabled,uint2_t chanAccess,uint4_t channelPrivLimit,uint2_t reserved2,uint2_t channelPrivMode)49 RspType<> ipmiSetChannelAccess(
50     Context::ptr ctx, uint4_t channel, uint4_t reserved1, uint3_t accessMode,
51     bool usrAuth, bool msgAuth, bool alertDisabled, uint2_t chanAccess,
52     uint4_t channelPrivLimit, uint2_t reserved2, uint2_t channelPrivMode)
53 {
54     if (reserved1 || reserved2 ||
55         !isValidPrivLimit(static_cast<uint8_t>(channelPrivLimit)))
56     {
57         lg2::debug("Set channel access - Invalid field in request");
58         return responseInvalidFieldRequest();
59     }
60 
61     const uint8_t chNum =
62         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
63     if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) ||
64         (!isValidChannel(chNum)))
65     {
66         lg2::debug("Set channel access - No support on channel: {CHANNEL}",
67                    "CHANNEL", chNum);
68         return responseActionNotSupportedForChannel();
69     }
70 
71     ChannelAccess chActData;
72     ChannelAccess chNVData;
73     uint8_t setActFlag = 0;
74     uint8_t setNVFlag = 0;
75     Cc compCode;
76 
77     // cannot static cast directly from uint2_t to enum; must go via int
78     uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess);
79     switch (static_cast<EChannelActionType>(channelAccessAction))
80     {
81         case doNotSet:
82             break;
83         case nvData:
84             chNVData.accessMode = static_cast<uint8_t>(accessMode);
85             chNVData.userAuthDisabled = usrAuth;
86             chNVData.perMsgAuthDisabled = msgAuth;
87             chNVData.alertingDisabled = alertDisabled;
88             setNVFlag |= (setAccessMode | setUserAuthEnabled |
89                           setMsgAuthEnabled | setAlertingEnabled);
90             break;
91 
92         case activeData:
93             chActData.accessMode = static_cast<uint8_t>(accessMode);
94             chActData.userAuthDisabled = usrAuth;
95             chActData.perMsgAuthDisabled = msgAuth;
96             chActData.alertingDisabled = alertDisabled;
97             setActFlag |= (setAccessMode | setUserAuthEnabled |
98                            setMsgAuthEnabled | setAlertingEnabled);
99             break;
100 
101         case reserved:
102         default:
103             lg2::debug("Set channel access - Invalid access set mode");
104             return responseAccessModeNotSupportedForChannel();
105     }
106 
107     // cannot static cast directly from uint2_t to enum; must go via int
108     uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode);
109     switch (static_cast<EChannelActionType>(channelPrivAction))
110     {
111         case doNotSet:
112             break;
113         case nvData:
114             chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit);
115             setNVFlag |= setPrivLimit;
116             break;
117         case activeData:
118             chActData.privLimit = static_cast<uint8_t>(channelPrivLimit);
119 
120             setActFlag |= setPrivLimit;
121             break;
122         case reserved:
123         default:
124             lg2::debug("Set channel access - Invalid access priv mode");
125             return responseAccessModeNotSupportedForChannel();
126     }
127 
128     if (setNVFlag != 0)
129     {
130         compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
131         if (compCode != ccSuccess)
132         {
133             lg2::debug("Set channel access - Failed to set access data");
134             return response(compCode);
135         }
136     }
137 
138     if (setActFlag != 0)
139     {
140         compCode = setChannelAccessData(chNum, chActData, setActFlag);
141         if (compCode != ccSuccess)
142         {
143             lg2::debug("Set channel access - Failed to set access data");
144             return response(compCode);
145         }
146     }
147 
148     return responseSuccess();
149 }
150 
151 /** @brief implements the get channel access command
152  *  @ param ctx - context pointer
153  *  @ param channel - channel number
154  *  @ param reserved1 - skip 4 bits
155  *  @ param reserved2 - skip 6 bits
156  *  @ param accessMode - get access mode
157  *
158  *  @returns ipmi completion code plus response data
159  *  - accessMode - get access mode
160  *  - usrAuthDisabled - user level authentication status
161  *  - msgAuthDisabled - message level authentication status
162  *  - alertDisabled - alerting status
163  *  - reserved - skip 2 bits
164  *  - privLimit - channel privilege limit
165  *  - reserved - skip 4 bits
166  * */
167 ipmi ::RspType<uint3_t, // access mode,
168                bool,    // user authentication status,
169                bool,    // message authentication status,
170                bool,    // alerting status,
171                uint2_t, // reserved,
172 
173                uint4_t, // channel privilege,
174                uint4_t  // reserved
175                >
ipmiGetChannelAccess(Context::ptr ctx,uint4_t channel,uint4_t reserved1,uint6_t reserved2,uint2_t accessSetMode)176     ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1,
177                          uint6_t reserved2, uint2_t accessSetMode)
178 {
179     if (reserved1 || reserved2)
180     {
181         lg2::debug("Get channel access - Invalid field in request");
182         return responseInvalidFieldRequest();
183     }
184 
185     if ((types::enum_cast<EChannelActionType>(accessSetMode) == doNotSet) ||
186         (types::enum_cast<EChannelActionType>(accessSetMode) == reserved))
187     {
188         lg2::debug("Get channel access - Invalid Access mode");
189         return responseInvalidFieldRequest();
190     }
191 
192     const uint8_t chNum =
193         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
194 
195     if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) ||
196         (!isValidChannel(chNum)))
197     {
198         lg2::debug("Get channel access - No support on channel: {CHANNEL}",
199                    "CHANNEL", chNum);
200         return responseActionNotSupportedForChannel();
201     }
202 
203     ChannelAccess chAccess = {};
204 
205     Cc compCode = ipmi::ccUnspecifiedError;
206 
207     if (types::enum_cast<EChannelActionType>(accessSetMode) == nvData)
208     {
209         compCode = getChannelAccessPersistData(chNum, chAccess);
210     }
211     else if (types::enum_cast<EChannelActionType>(accessSetMode) == activeData)
212     {
213         compCode = getChannelAccessData(chNum, chAccess);
214     }
215 
216     if (compCode != ccSuccess)
217     {
218         return response(compCode);
219     }
220 
221     constexpr uint2_t reservedOut1 = 0;
222     constexpr uint4_t reservedOut2 = 0;
223 
224     return responseSuccess(
225         types::enum_cast<uint3_t>(chAccess.accessMode),
226         chAccess.userAuthDisabled, chAccess.perMsgAuthDisabled,
227         chAccess.alertingDisabled, reservedOut1,
228         types::enum_cast<uint4_t>(chAccess.privLimit), reservedOut2);
229 }
230 
231 /** @brief implements the get channel info command
232  *  @ param ctx - context pointer
233  *  @ param channel - channel number
234  *  @ param reserved - skip 4 bits
235  *
236  *  @returns ipmi completion code plus response data
237  *  - chNum - the channel number for this request
238  *  - mediumType - see Table 6-3, Channel Medium Type Numbers
239  *  - protocolType - Table 6-2, Channel Protocol Type Numbers
240  *  - activeSessionCount - number of active sessions
241  *  - sessionType - channel support for sessions
242  *  - vendorId - vendor for this channel protocol (IPMI - 7154)
243  *  - auxChInfo - auxiliary info for channel
244  * */
245 RspType<uint4_t,  // chNum
246         uint4_t,  // reserved
247         uint7_t,  // mediumType
248         bool,     // reserved
249         uint5_t,  // protocolType
250         uint3_t,  // reserved
251         uint6_t,  // activeSessionCount
252         uint2_t,  // sessionType
253         uint24_t, // Vendor IANA
254         uint16_t  // aux info
255         >
ipmiGetChannelInfo(Context::ptr ctx,uint4_t channel,uint4_t reserved)256     ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved)
257 {
258     if (reserved)
259     {
260         lg2::debug("Get channel access - Invalid field in request");
261         return responseInvalidFieldRequest();
262     }
263 
264     uint8_t chNum =
265         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
266     if (!isValidChannel(chNum))
267     {
268         lg2::debug("Get channel Info - No support on channel: {CHANNEL}",
269                    "CHANNEL", chNum);
270         return responseInvalidFieldRequest();
271     }
272 
273     ChannelInfo chInfo;
274     Cc compCode = getChannelInfo(chNum, chInfo);
275     if (compCode != ccSuccess)
276     {
277         lg2::error("Failed to get channel info, channel: {CHANNEL}, "
278                    "errno: {ERRNO}",
279                    "CHANNEL", chNum, "ERRNO", compCode);
280         return response(compCode);
281     }
282 
283     constexpr uint4_t reserved1 = 0;
284     constexpr bool reserved2 = false;
285     constexpr uint3_t reserved3 = 0;
286     uint8_t mediumType = chInfo.mediumType;
287     uint8_t protocolType = chInfo.protocolType;
288     uint2_t sessionType = chInfo.sessionSupported;
289     uint6_t activeSessionCount = getChannelActiveSessions(chNum);
290     // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
291     constexpr uint24_t vendorId = 7154;
292     constexpr uint16_t auxChInfo = 0;
293 
294     return responseSuccess(chNum, reserved1, mediumType, reserved2,
295                            protocolType, reserved3, activeSessionCount,
296                            sessionType, vendorId, auxChInfo);
297 }
298 
299 namespace
300 {
standardPayloadBit(PayloadType p)301 constexpr uint16_t standardPayloadBit(PayloadType p)
302 {
303     return (1 << static_cast<size_t>(p));
304 }
305 
sessionPayloadBit(PayloadType p)306 constexpr uint16_t sessionPayloadBit(PayloadType p)
307 {
308     constexpr size_t sessionShift =
309         static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST);
310     return ((1 << static_cast<size_t>(p)) >> sessionShift);
311 }
312 } // namespace
313 
314 /** @brief implements get channel payload support command
315  *  @ param ctx - ipmi context pointer
316  *  @ param chNum - channel number
317  *  @ param reserved - skip 4 bits
318  *
319  *  @ returns IPMI completion code plus response data
320  *  - stdPayloadType - bitmask of supported standard payload types
321  *  - sessSetupPayloadType - bitmask of supported session setup payload types
322  *  - OEMPayloadType - bitmask of supported OEM payload types
323  *  - reserved - 2 bytes of 0
324  **/
325 RspType<uint16_t, // stdPayloadType
326         uint16_t, // sessSetupPayloadType
327         uint16_t, // OEMPayloadType
328         uint16_t  // reserved
329         >
ipmiGetChannelPayloadSupport(Context::ptr ctx,uint4_t channel,uint4_t reserved)330     ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel,
331                                  uint4_t reserved)
332 {
333     uint8_t chNum =
334         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
335 
336     if (!doesDeviceExist(chNum) || !isValidChannel(chNum) || reserved)
337     {
338         lg2::debug("Get channel payload - Invalid field in request");
339         return responseInvalidFieldRequest();
340     }
341 
342     // Session support is available in active LAN channels.
343     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
344     {
345         lg2::debug("Get channel payload - No support on channel");
346         return responseActionNotSupportedForChannel();
347     }
348     constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) |
349                                         standardPayloadBit(PayloadType::SOL);
350     constexpr uint16_t sessSetupPayloadType =
351         sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) |
352         sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) |
353         sessionPayloadBit(PayloadType::RAKP1) |
354         sessionPayloadBit(PayloadType::RAKP2) |
355         sessionPayloadBit(PayloadType::RAKP3) |
356         sessionPayloadBit(PayloadType::RAKP4);
357     constexpr uint16_t OEMPayloadType = 0;
358     constexpr uint16_t rspRsvd = 0;
359     return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType,
360                            rspRsvd);
361 }
362 
363 /** @brief implements the get channel payload version command
364  *  @param ctx - IPMI context pointer (for channel)
365  *  @param chNum - channel number to get info about
366  *  @param reserved - skip 4 bits
367  *  @param payloadTypeNum - to get payload type info
368 
369  *  @returns IPMI completion code plus response data
370  *   - formatVersion - BCD encoded format version info
371  */
372 
373 RspType<uint8_t> // formatVersion
ipmiGetChannelPayloadVersion(Context::ptr ctx,uint4_t chNum,uint4_t reserved,uint8_t payloadTypeNum)374     ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum,
375                                  uint4_t reserved, uint8_t payloadTypeNum)
376 {
377     uint8_t channel =
378         convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
379 
380     if (reserved || !isValidChannel(channel))
381     {
382         lg2::debug("Get channel payload version - Invalid field in request");
383         return responseInvalidFieldRequest();
384     }
385 
386     if (getChannelSessionSupport(channel) == EChannelSessSupported::none)
387     {
388         lg2::debug("Get channel payload version - No support on channel");
389         return responsePayloadTypeNotSupported();
390     }
391 
392     if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum)))
393     {
394         lg2::error("Get channel payload version - Payload type unavailable");
395 
396         return responsePayloadTypeNotSupported();
397     }
398 
399     // BCD encoded version representation - 1.0
400     constexpr uint8_t formatVersion = 0x10;
401 
402     return responseSuccess(formatVersion);
403 }
404 
405 void registerChannelFunctions() __attribute__((constructor));
registerChannelFunctions()406 void registerChannelFunctions()
407 {
408     ipmiChannelInit();
409 
410     registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess,
411                     Privilege::Admin, ipmiSetChannelAccess);
412 
413     registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess,
414                     Privilege::User, ipmiGetChannelAccess);
415 
416     registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand,
417                     Privilege::User, ipmiGetChannelInfo);
418 
419     registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport,
420                     Privilege::User, ipmiGetChannelPayloadSupport);
421 
422     registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion,
423                     Privilege::User, ipmiGetChannelPayloadVersion);
424 }
425 
426 } // namespace ipmi
427