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