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