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 "channelcommands.hpp"
18 
19 #include "apphandler.hpp"
20 #include "channel_layer.hpp"
21 
22 #include <phosphor-logging/log.hpp>
23 #include <regex>
24 
25 using namespace phosphor::logging;
26 
27 namespace ipmi
28 {
29 
30 /** @struct SetChannelAccessReq
31  *
32  *  Structure for set channel access request command (refer spec sec 22.22)
33  */
34 struct SetChannelAccessReq
35 {
36 #if BYTE_ORDER == LITTLE_ENDIAN
37     uint8_t chNum : 4;
38     uint8_t reserved_1 : 4;
39     uint8_t accessMode : 3;
40     uint8_t usrAuthDisabled : 1;
41     uint8_t msgAuthDisabled : 1;
42     uint8_t alertDisabled : 1;
43     uint8_t accessSetMode : 2;
44     uint8_t privLimit : 4;
45     uint8_t reserved_2 : 2;
46     uint8_t privSetMode : 2;
47 #endif
48 #if BYTE_ORDER == BIG_ENDIAN
49     uint8_t reserved_1 : 4;
50     uint8_t chNum : 4;
51     uint8_t accessSetMode : 2;
52     uint8_t alertDisabled : 1;
53     uint8_t msgAuthDisabled : 1;
54     uint8_t usrAuthDisabled : 1;
55     uint8_t accessMode : 3;
56     uint8_t privSetMode : 2;
57     uint8_t reserved_2 : 2;
58     uint8_t privLimit : 4;
59 #endif
60 
61 } __attribute__((packed));
62 
63 /** @struct GetChannelAccessReq
64  *
65  *  Structure for get channel access request command (refer spec sec 22.23)
66  */
67 struct GetChannelAccessReq
68 {
69 #if BYTE_ORDER == LITTLE_ENDIAN
70     uint8_t chNum : 4;
71     uint8_t reserved_1 : 4;
72     uint8_t reserved_2 : 6;
73     uint8_t accessSetMode : 2;
74 #endif
75 #if BYTE_ORDER == BIG_ENDIAN
76     uint8_t reserved_1 : 4;
77     uint8_t chNum : 4;
78     uint8_t accessSetMode : 2;
79     uint8_t reserved_2 : 6;
80 #endif
81 } __attribute__((packed));
82 
83 /** @struct GetChannelAccessResp
84  *
85  *  Structure for get channel access response command (refer spec sec 22.23)
86  */
87 struct GetChannelAccessResp
88 {
89 #if BYTE_ORDER == LITTLE_ENDIAN
90     uint8_t accessMode : 3;
91     uint8_t usrAuthDisabled : 1;
92     uint8_t msgAuthDisabled : 1;
93     uint8_t alertDisabled : 1;
94     uint8_t reserved_1 : 2;
95     uint8_t privLimit : 4;
96     uint8_t reserved_2 : 4;
97 #endif
98 #if BYTE_ORDER == BIG_ENDIAN
99     uint8_t reserved_1 : 2;
100     uint8_t alertDisabled : 1;
101     uint8_t msgAuthDisabled : 1;
102     uint8_t usrAuthDisabled : 1;
103     uint8_t accessMode : 3;
104     uint8_t reserved_2 : 4;
105     uint8_t privLimit : 4;
106 #endif
107 } __attribute__((packed));
108 
109 /** @struct GetChannelInfoReq
110  *
111  *  Structure for get channel info request command (refer spec sec 22.24)
112  */
113 struct GetChannelInfoReq
114 {
115 #if BYTE_ORDER == LITTLE_ENDIAN
116     uint8_t chNum : 4;
117     uint8_t reserved_1 : 4;
118 #endif
119 #if BYTE_ORDER == BIG_ENDIAN
120     uint8_t reserved_1 : 4;
121     uint8_t chNum : 4;
122 #endif
123 } __attribute__((packed));
124 
125 /** @struct GetChannelInfoResp
126  *
127  *  Structure for get channel info response command (refer spec sec 22.24)
128  */
129 struct GetChannelInfoResp
130 {
131 #if BYTE_ORDER == LITTLE_ENDIAN
132     uint8_t chNum : 4;
133     uint8_t reserved_1 : 4;
134     uint8_t mediumType : 7;
135     uint8_t reserved_2 : 1;
136     uint8_t msgProtType : 5;
137     uint8_t reserved_3 : 3;
138     uint8_t actSessCount : 6;
139     uint8_t sessType : 2;
140 #endif
141 #if BYTE_ORDER == BIG_ENDIAN
142     uint8_t reserved_1 : 4;
143     uint8_t chNum : 4;
144     uint8_t reserved_2 : 1;
145     uint8_t mediumType : 7;
146     uint8_t reserved_3 : 3;
147     uint8_t msgProtType : 5;
148     uint8_t sessType : 2;
149     uint8_t actSessCount : 6;
150 #endif
151     uint8_t vendorId[3];
152     uint8_t auxChInfo[2];
153 } __attribute__((packed));
154 
155 /** @struct GetChannelPayloadSupportReq
156  *
157  *  Structure for get channel payload support command request (refer spec
158  *  sec 24.8)
159  */
160 struct GetChannelPayloadSupportReq
161 {
162 #if BYTE_ORDER == LITTLE_ENDIAN
163     uint8_t chNum : 4;
164     uint8_t reserved : 4;
165 #endif
166 #if BYTE_ORDER == BIG_ENDIAN
167     uint8_t reserved : 4;
168     uint8_t chNum : 4;
169 #endif
170 } __attribute__((packed));
171 
172 /** @struct GetChannelPayloadSupportResp
173  *
174  *  Structure for get channel payload support command response (refer spec
175  *  sec 24.8)
176  */
177 struct GetChannelPayloadSupportResp
178 {
179     uint8_t stdPayloadType[2];
180     uint8_t sessSetupPayloadType[2];
181     uint8_t OEMPayloadType[2];
182     uint8_t reserved[2];
183 } __attribute__((packed));
184 
185 ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
186                                 ipmi_request_t request,
187                                 ipmi_response_t response,
188                                 ipmi_data_len_t data_len,
189                                 ipmi_context_t context)
190 {
191     const SetChannelAccessReq* req = static_cast<SetChannelAccessReq*>(request);
192     size_t reqLength = *data_len;
193 
194     *data_len = 0;
195 
196     if (reqLength != sizeof(*req))
197     {
198         log<level::DEBUG>("Set channel access - Invalid Length");
199         return IPMI_CC_REQ_DATA_LEN_INVALID;
200     }
201 
202     uint8_t chNum = convertCurrentChannelNum(req->chNum);
203     if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
204     {
205         log<level::DEBUG>("Set channel access - Invalid field in request");
206         return IPMI_CC_INVALID_FIELD_REQUEST;
207     }
208 
209     if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
210     {
211         log<level::DEBUG>("Set channel access - No support on channel");
212         return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
213     }
214 
215     ChannelAccess chActData;
216     ChannelAccess chNVData;
217     uint8_t setActFlag = 0;
218     uint8_t setNVFlag = 0;
219     ipmi_ret_t compCode = IPMI_CC_OK;
220 
221     switch (req->accessSetMode)
222     {
223         case doNotSet:
224             // Do nothing
225             break;
226         case nvData:
227             chNVData.accessMode = req->accessMode;
228             chNVData.userAuthDisabled = req->usrAuthDisabled;
229             chNVData.perMsgAuthDisabled = req->msgAuthDisabled;
230             chNVData.alertingDisabled = req->alertDisabled;
231             setNVFlag |= (setAccessMode | setUserAuthEnabled |
232                           setMsgAuthEnabled | setAlertingEnabled);
233             break;
234         case activeData:
235             chActData.accessMode = req->accessMode;
236             chActData.userAuthDisabled = req->usrAuthDisabled;
237             chActData.perMsgAuthDisabled = req->msgAuthDisabled;
238             chActData.alertingDisabled = req->alertDisabled;
239             setActFlag |= (setAccessMode | setUserAuthEnabled |
240                            setMsgAuthEnabled | setAlertingEnabled);
241             break;
242         case reserved:
243         default:
244             log<level::DEBUG>("Set channel access - Invalid access set mode");
245             return IPMI_CC_INVALID_FIELD_REQUEST;
246     }
247 
248     switch (req->privSetMode)
249     {
250         case doNotSet:
251             // Do nothing
252             break;
253         case nvData:
254             chNVData.privLimit = req->privLimit;
255             setNVFlag |= setPrivLimit;
256             break;
257         case activeData:
258             chActData.privLimit = req->privLimit;
259             setActFlag |= setPrivLimit;
260             break;
261         case reserved:
262         default:
263             log<level::DEBUG>("Set channel access - Invalid access priv mode");
264             return IPMI_CC_INVALID_FIELD_REQUEST;
265     }
266 
267     if (setNVFlag != 0)
268     {
269         compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
270         if (compCode != IPMI_CC_OK)
271         {
272             log<level::DEBUG>("Set channel access - Failed to set access data");
273             return compCode;
274         }
275     }
276 
277     if (setActFlag != 0)
278     {
279         compCode = setChannelAccessData(chNum, chActData, setActFlag);
280         if (compCode != IPMI_CC_OK)
281         {
282             log<level::DEBUG>("Set channel access - Failed to set access data");
283             return compCode;
284         }
285     }
286 
287     return IPMI_CC_OK;
288 }
289 
290 ipmi_ret_t ipmiGetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
291                                 ipmi_request_t request,
292                                 ipmi_response_t response,
293                                 ipmi_data_len_t data_len,
294                                 ipmi_context_t context)
295 {
296     const GetChannelAccessReq* req = static_cast<GetChannelAccessReq*>(request);
297     size_t reqLength = *data_len;
298 
299     *data_len = 0;
300 
301     if (reqLength != sizeof(*req))
302     {
303         log<level::DEBUG>("Get channel access - Invalid Length");
304         return IPMI_CC_REQ_DATA_LEN_INVALID;
305     }
306 
307     uint8_t chNum = convertCurrentChannelNum(req->chNum);
308     if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
309     {
310         log<level::DEBUG>("Get channel access - Invalid field in request");
311         return IPMI_CC_INVALID_FIELD_REQUEST;
312     }
313 
314     if ((req->accessSetMode == doNotSet) || (req->accessSetMode == reserved))
315     {
316         log<level::DEBUG>("Get channel access - Invalid Access mode");
317         return IPMI_CC_INVALID_FIELD_REQUEST;
318     }
319 
320     if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
321     {
322         log<level::DEBUG>("Get channel access - No support on channel");
323         return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
324     }
325 
326     GetChannelAccessResp* resp = static_cast<GetChannelAccessResp*>(response);
327 
328     std::fill(reinterpret_cast<uint8_t*>(resp),
329               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
330 
331     ChannelAccess chAccess;
332     ipmi_ret_t compCode = IPMI_CC_OK;
333 
334     if (req->accessSetMode == nvData)
335     {
336         compCode = getChannelAccessPersistData(chNum, chAccess);
337     }
338     else if (req->accessSetMode == activeData)
339     {
340         compCode = getChannelAccessData(chNum, chAccess);
341     }
342 
343     if (compCode != IPMI_CC_OK)
344     {
345         return compCode;
346     }
347 
348     resp->accessMode = chAccess.accessMode;
349     resp->usrAuthDisabled = chAccess.userAuthDisabled;
350     resp->msgAuthDisabled = chAccess.perMsgAuthDisabled;
351     resp->alertDisabled = chAccess.alertingDisabled;
352     resp->privLimit = chAccess.privLimit;
353 
354     *data_len = sizeof(*resp);
355     return IPMI_CC_OK;
356 }
357 
358 ipmi_ret_t ipmiGetChannelInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
359                               ipmi_request_t request, ipmi_response_t response,
360                               ipmi_data_len_t data_len, ipmi_context_t context)
361 {
362     const GetChannelInfoReq* req = static_cast<GetChannelInfoReq*>(request);
363     size_t reqLength = *data_len;
364 
365     *data_len = 0;
366 
367     if (reqLength != sizeof(*req))
368     {
369         log<level::DEBUG>("Get channel info - Invalid Length");
370         return IPMI_CC_REQ_DATA_LEN_INVALID;
371     }
372 
373     uint8_t chNum = convertCurrentChannelNum(req->chNum);
374     if (!isValidChannel(chNum) || req->reserved_1 != 0)
375     {
376         log<level::DEBUG>("Get channel info - Invalid field in request");
377         return IPMI_CC_INVALID_FIELD_REQUEST;
378     }
379 
380     // Check the existance of device for session-less channels.
381     if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) &&
382         (!(doesDeviceExist(chNum))))
383     {
384         log<level::DEBUG>("Get channel info - Device not exist");
385         return IPMI_CC_PARM_OUT_OF_RANGE;
386     }
387 
388     GetChannelInfoResp* resp = static_cast<GetChannelInfoResp*>(response);
389 
390     std::fill(reinterpret_cast<uint8_t*>(resp),
391               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
392 
393     ChannelInfo chInfo;
394     ipmi_ret_t compCode = getChannelInfo(chNum, chInfo);
395     if (compCode != IPMI_CC_OK)
396     {
397         return compCode;
398     }
399 
400     resp->chNum = chNum;
401     resp->mediumType = chInfo.mediumType;
402     resp->msgProtType = chInfo.protocolType;
403     resp->actSessCount = getChannelActiveSessions(chNum);
404     resp->sessType = chInfo.sessionSupported;
405 
406     // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
407     resp->vendorId[0] = 0xF2;
408     resp->vendorId[1] = 0x1B;
409     resp->vendorId[2] = 0x00;
410 
411     // Auxiliary Channel info  - byte 1:2
412     // TODO: For System Interface(0xF) and OEM channel types, this needs
413     // to be changed acoordingly.
414     // All other channel types, its reverved
415     resp->auxChInfo[0] = 0x00;
416     resp->auxChInfo[1] = 0x00;
417 
418     *data_len = sizeof(*resp);
419 
420     return IPMI_CC_OK;
421 }
422 
423 ipmi_ret_t ipmiGetChannelPayloadSupport(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
424                                         ipmi_request_t request,
425                                         ipmi_response_t response,
426                                         ipmi_data_len_t data_len,
427                                         ipmi_context_t context)
428 {
429     const auto req = static_cast<GetChannelPayloadSupportReq*>(request);
430     size_t reqLength = *data_len;
431 
432     *data_len = 0;
433 
434     if (reqLength != sizeof(*req))
435     {
436         log<level::DEBUG>("Get channel payload - Invalid Length");
437         return IPMI_CC_REQ_DATA_LEN_INVALID;
438     }
439 
440     uint8_t chNum = convertCurrentChannelNum(req->chNum);
441     if (!isValidChannel(chNum) || req->reserved != 0)
442     {
443         log<level::DEBUG>("Get channel payload - Invalid field in request");
444         return IPMI_CC_INVALID_FIELD_REQUEST;
445     }
446 
447     // Not supported on sessionless channels.
448     if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
449     {
450         log<level::DEBUG>("Get channel payload - Sessionless Channel");
451         return IPMI_CC_INVALID_FIELD_REQUEST;
452     }
453 
454     // Session support is available in active LAN channels.
455     if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) &&
456         (!(doesDeviceExist(chNum))))
457     {
458         log<level::DEBUG>("Get channel payload - Device not exist");
459         return IPMI_CC_INVALID_FIELD_REQUEST;
460     }
461 
462     auto resp = static_cast<GetChannelPayloadSupportResp*>(response);
463 
464     std::fill(reinterpret_cast<uint8_t*>(resp),
465               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
466 
467     // TODO: Hard coding for now.
468     // Mapping PayloadTypes to 'GetChannelPayloadSupportResp' fields:
469     // --------------------------------------------------------------
470     // Mask all except least 3 significant bits to get a value in the range of
471     // 0-7. This value maps to the bit position of given payload type in 'resp'
472     // fields.
473 
474     static constexpr uint8_t payloadByteMask = 0x07;
475     static constexpr uint8_t stdPayloadTypeIPMI =
476         1 << (static_cast<uint8_t>(PayloadType::IPMI) & payloadByteMask);
477     static constexpr uint8_t stdPayloadTypeSOL =
478         1 << (static_cast<uint8_t>(PayloadType::SOL) & payloadByteMask);
479 
480     static constexpr uint8_t sessPayloadTypeOpenReq =
481         1 << (static_cast<uint8_t>(PayloadType::OPEN_SESSION_REQUEST) &
482               payloadByteMask);
483     static constexpr uint8_t sessPayloadTypeRAKP1 =
484         1 << (static_cast<uint8_t>(PayloadType::RAKP1) & payloadByteMask);
485     static constexpr uint8_t sessPayloadTypeRAKP3 =
486         1 << (static_cast<uint8_t>(PayloadType::RAKP3) & payloadByteMask);
487 
488     resp->stdPayloadType[0] = stdPayloadTypeIPMI | stdPayloadTypeSOL;
489     // RMCP+ Open Session request, RAKP Message1 and RAKP Message3.
490     resp->sessSetupPayloadType[0] =
491         sessPayloadTypeOpenReq | sessPayloadTypeRAKP1 | sessPayloadTypeRAKP3;
492 
493     *data_len = sizeof(*resp);
494 
495     return IPMI_CC_OK;
496 }
497 
498 void registerChannelFunctions() __attribute__((constructor));
499 void registerChannelFunctions()
500 {
501     ipmiChannelInit();
502 
503     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHANNEL_ACCESS, NULL,
504                            ipmiSetChannelAccess, PRIVILEGE_ADMIN);
505 
506     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
507                            ipmiGetChannelAccess, PRIVILEGE_USER);
508 
509     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_INFO, NULL,
510                            ipmiGetChannelInfo, PRIVILEGE_USER);
511 
512     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT,
513                            NULL, ipmiGetChannelPayloadSupport, PRIVILEGE_USER);
514 
515     return;
516 }
517 
518 } // namespace ipmi
519