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 ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
156                                 ipmi_request_t request,
157                                 ipmi_response_t response,
158                                 ipmi_data_len_t data_len,
159                                 ipmi_context_t context)
160 {
161     const SetChannelAccessReq* req = static_cast<SetChannelAccessReq*>(request);
162     size_t reqLength = *data_len;
163 
164     *data_len = 0;
165 
166     if (reqLength != sizeof(*req))
167     {
168         log<level::DEBUG>("Set channel access - Invalid Length");
169         return IPMI_CC_REQ_DATA_LEN_INVALID;
170     }
171 
172     uint8_t chNum = convertCurrentChannelNum(req->chNum);
173     if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
174     {
175         log<level::DEBUG>("Set channel access - Invalid field in request");
176         return IPMI_CC_INVALID_FIELD_REQUEST;
177     }
178 
179     if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
180     {
181         log<level::DEBUG>("Set channel access - No support on channel");
182         return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
183     }
184 
185     ChannelAccess chActData;
186     ChannelAccess chNVData;
187     uint8_t setActFlag = 0;
188     uint8_t setNVFlag = 0;
189     ipmi_ret_t compCode = IPMI_CC_OK;
190 
191     switch (req->accessSetMode)
192     {
193         case doNotSet:
194             // Do nothing
195             break;
196         case nvData:
197             chNVData.accessMode = req->accessMode;
198             chNVData.userAuthDisabled = req->usrAuthDisabled;
199             chNVData.perMsgAuthDisabled = req->msgAuthDisabled;
200             chNVData.alertingDisabled = req->alertDisabled;
201             setNVFlag |= (setAccessMode | setUserAuthEnabled |
202                           setMsgAuthEnabled | setAlertingEnabled);
203             break;
204         case activeData:
205             chActData.accessMode = req->accessMode;
206             chActData.userAuthDisabled = req->usrAuthDisabled;
207             chActData.perMsgAuthDisabled = req->msgAuthDisabled;
208             chActData.alertingDisabled = req->alertDisabled;
209             setActFlag |= (setAccessMode | setUserAuthEnabled |
210                            setMsgAuthEnabled | setAlertingEnabled);
211             break;
212         case reserved:
213         default:
214             log<level::DEBUG>("Set channel access - Invalid access set mode");
215             return IPMI_CC_INVALID_FIELD_REQUEST;
216     }
217 
218     switch (req->privSetMode)
219     {
220         case doNotSet:
221             // Do nothing
222             break;
223         case nvData:
224             chNVData.privLimit = req->privLimit;
225             setNVFlag |= setPrivLimit;
226             break;
227         case activeData:
228             chActData.privLimit = req->privLimit;
229             setActFlag |= setPrivLimit;
230             break;
231         case reserved:
232         default:
233             log<level::DEBUG>("Set channel access - Invalid access priv mode");
234             return IPMI_CC_INVALID_FIELD_REQUEST;
235     }
236 
237     if (setNVFlag != 0)
238     {
239         compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
240         if (compCode != IPMI_CC_OK)
241         {
242             log<level::DEBUG>("Set channel access - Failed to set access data");
243             return compCode;
244         }
245     }
246 
247     if (setActFlag != 0)
248     {
249         compCode = setChannelAccessData(chNum, chActData, setActFlag);
250         if (compCode != IPMI_CC_OK)
251         {
252             log<level::DEBUG>("Set channel access - Failed to set access data");
253             return compCode;
254         }
255     }
256 
257     return IPMI_CC_OK;
258 }
259 
260 ipmi_ret_t ipmiGetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
261                                 ipmi_request_t request,
262                                 ipmi_response_t response,
263                                 ipmi_data_len_t data_len,
264                                 ipmi_context_t context)
265 {
266     const GetChannelAccessReq* req = static_cast<GetChannelAccessReq*>(request);
267     size_t reqLength = *data_len;
268 
269     *data_len = 0;
270 
271     if (reqLength != sizeof(*req))
272     {
273         log<level::DEBUG>("Get channel access - Invalid Length");
274         return IPMI_CC_REQ_DATA_LEN_INVALID;
275     }
276 
277     uint8_t chNum = convertCurrentChannelNum(req->chNum);
278     if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
279     {
280         log<level::DEBUG>("Get channel access - Invalid field in request");
281         return IPMI_CC_INVALID_FIELD_REQUEST;
282     }
283 
284     if ((req->accessSetMode == doNotSet) || (req->accessSetMode == reserved))
285     {
286         log<level::DEBUG>("Get channel access - Invalid Access mode");
287         return IPMI_CC_INVALID_FIELD_REQUEST;
288     }
289 
290     if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
291     {
292         log<level::DEBUG>("Get channel access - No support on channel");
293         return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
294     }
295 
296     GetChannelAccessResp* resp = static_cast<GetChannelAccessResp*>(response);
297 
298     std::fill(reinterpret_cast<uint8_t*>(resp),
299               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
300 
301     ChannelAccess chAccess;
302     ipmi_ret_t compCode = IPMI_CC_OK;
303 
304     if (req->accessSetMode == nvData)
305     {
306         compCode = getChannelAccessPersistData(chNum, chAccess);
307     }
308     else if (req->accessSetMode == activeData)
309     {
310         compCode = getChannelAccessData(chNum, chAccess);
311     }
312 
313     if (compCode != IPMI_CC_OK)
314     {
315         return compCode;
316     }
317 
318     resp->accessMode = chAccess.accessMode;
319     resp->usrAuthDisabled = chAccess.userAuthDisabled;
320     resp->msgAuthDisabled = chAccess.perMsgAuthDisabled;
321     resp->alertDisabled = chAccess.alertingDisabled;
322     resp->privLimit = chAccess.privLimit;
323 
324     *data_len = sizeof(*resp);
325     return IPMI_CC_OK;
326 }
327 
328 ipmi_ret_t ipmiGetChannelInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
329                               ipmi_request_t request, ipmi_response_t response,
330                               ipmi_data_len_t data_len, ipmi_context_t context)
331 {
332     const GetChannelInfoReq* req = static_cast<GetChannelInfoReq*>(request);
333     size_t reqLength = *data_len;
334 
335     *data_len = 0;
336 
337     if (reqLength != sizeof(*req))
338     {
339         log<level::DEBUG>("Get channel info - Invalid Length");
340         return IPMI_CC_REQ_DATA_LEN_INVALID;
341     }
342 
343     uint8_t chNum = convertCurrentChannelNum(req->chNum);
344     if (!isValidChannel(chNum) || req->reserved_1 != 0)
345     {
346         log<level::DEBUG>("Get channel info - Invalid field in request");
347         return IPMI_CC_INVALID_FIELD_REQUEST;
348     }
349 
350     // Check the existance of device for session-less channels.
351     if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) &&
352         (!(doesDeviceExist(chNum))))
353     {
354         log<level::DEBUG>("Get channel info - Device not exist");
355         return IPMI_CC_PARM_OUT_OF_RANGE;
356     }
357 
358     GetChannelInfoResp* resp = static_cast<GetChannelInfoResp*>(response);
359 
360     std::fill(reinterpret_cast<uint8_t*>(resp),
361               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
362 
363     ChannelInfo chInfo;
364     ipmi_ret_t compCode = getChannelInfo(chNum, chInfo);
365     if (compCode != IPMI_CC_OK)
366     {
367         return compCode;
368     }
369 
370     resp->chNum = chNum;
371     resp->mediumType = chInfo.mediumType;
372     resp->msgProtType = chInfo.protocolType;
373     resp->actSessCount = getChannelActiveSessions(chNum);
374     resp->sessType = chInfo.sessionSupported;
375 
376     // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
377     resp->vendorId[0] = 0xF2;
378     resp->vendorId[1] = 0x1B;
379     resp->vendorId[2] = 0x00;
380 
381     // Auxiliary Channel info  - byte 1:2
382     // TODO: For System Interface(0xF) and OEM channel types, this needs
383     // to be changed acoordingly.
384     // All other channel types, its reverved
385     resp->auxChInfo[0] = 0x00;
386     resp->auxChInfo[1] = 0x00;
387 
388     *data_len = sizeof(*resp);
389 
390     return IPMI_CC_OK;
391 }
392 
393 void registerChannelFunctions() __attribute__((constructor));
394 void registerChannelFunctions()
395 {
396     ipmiChannelInit();
397 
398     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHANNEL_ACCESS, NULL,
399                            ipmiSetChannelAccess, PRIVILEGE_ADMIN);
400 
401     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
402                            ipmiGetChannelAccess, PRIVILEGE_USER);
403 
404     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_INFO, NULL,
405                            ipmiGetChannelInfo, PRIVILEGE_USER);
406     return;
407 }
408 
409 } // namespace ipmi
410