blob: 0db54b657fc03917b5b0e78536e9b8048e68f30e [file] [log] [blame]
AppaRao Puli071f3f22018-05-24 16:45:30 +05301/*
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_mgmt.hpp"
18
19#include "apphandler.hpp"
20
21#include <sys/stat.h>
22#include <unistd.h>
23
24#include <boost/interprocess/sync/scoped_lock.hpp>
25#include <cerrno>
26#include <experimental/filesystem>
27#include <fstream>
28#include <phosphor-logging/log.hpp>
29#include <unordered_map>
30
31namespace ipmi
32{
33
34using namespace phosphor::logging;
35
36static constexpr const char* channelAccessDefaultFilename =
37 "/usr/share/ipmi-providers/channel_access.json";
38static constexpr const char* channelConfigDefaultFilename =
39 "/usr/share/ipmi-providers/channel_config.json";
40static constexpr const char* channelNvDataFilename =
41 "/var/lib/ipmi/channel_access_nv.json";
42static constexpr const char* channelVolatileDataFilename =
43 "/run/ipmi/channel_access_volatile.json";
44
45// STRING DEFINES: Should sync with key's in JSON
46static constexpr const char* nameString = "name";
47static constexpr const char* isValidString = "is_valid";
48static constexpr const char* activeSessionsString = "active_sessions";
49static constexpr const char* channelInfoString = "channel_info";
50static constexpr const char* mediumTypeString = "medium_type";
51static constexpr const char* protocolTypeString = "protocol_type";
52static constexpr const char* sessionSupportedString = "session_supported";
53static constexpr const char* isIpmiString = "is_ipmi";
54static constexpr const char* authTypeSupportedString = "auth_type_supported";
55static constexpr const char* accessModeString = "access_mode";
56static constexpr const char* userAuthDisabledString = "user_auth_disabled";
57static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
58static constexpr const char* alertingDisabledString = "alerting_disabled";
59static constexpr const char* privLimitString = "priv_limit";
60static constexpr const char* authTypeEnabledString = "auth_type_enabled";
61
62// Default values
63static constexpr const char* defaultChannelName = "RESERVED";
64static constexpr const uint8_t defaultMediumType =
65 static_cast<uint8_t>(EChannelMediumType::reserved);
66static constexpr const uint8_t defaultProtocolType =
67 static_cast<uint8_t>(EChannelProtocolType::reserved);
68static constexpr const uint8_t defaultSessionSupported =
69 static_cast<uint8_t>(EChannelSessSupported::none);
70static constexpr const uint8_t defaultAuthType =
71 static_cast<uint8_t>(EAuthType::none);
72static constexpr const bool defaultIsIpmiState = false;
73
74// String mappings use in JSON config file
75static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
76 {"reserved", EChannelMediumType::reserved},
77 {"ipmb", EChannelMediumType::ipmb},
78 {"icmb-v1.0", EChannelMediumType::icmbV10},
79 {"icmb-v0.9", EChannelMediumType::icmbV09},
80 {"lan-802.3", EChannelMediumType::lan8032},
81 {"serial", EChannelMediumType::serial},
82 {"other-lan", EChannelMediumType::otherLan},
83 {"pci-smbus", EChannelMediumType::pciSmbus},
84 {"smbus-v1.0", EChannelMediumType::smbusV11},
85 {"smbus-v2.0", EChannelMediumType::smbusV20},
86 {"usb-1x", EChannelMediumType::usbV1x},
87 {"usb-2x", EChannelMediumType::usbV2x},
88 {"system-interface", EChannelMediumType::systemInterface},
89 {"oem", EChannelMediumType::oem},
90 {"unknown", EChannelMediumType::unknown}};
91
92static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
93 {"na", EChannelProtocolType::na},
94 {"ipmb-1.0", EChannelProtocolType::ipmbV10},
95 {"icmb-2.0", EChannelProtocolType::icmbV11},
96 {"reserved", EChannelProtocolType::reserved},
97 {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
98 {"kcs", EChannelProtocolType::kcs},
99 {"smic", EChannelProtocolType::smic},
100 {"bt-10", EChannelProtocolType::bt10},
101 {"bt-15", EChannelProtocolType::bt15},
102 {"tmode", EChannelProtocolType::tMode},
103 {"oem", EChannelProtocolType::oem}};
104
105static std::array<std::string, 4> accessModeList = {
106 "disabled", "pre-boot", "always_available", "shared"};
107
108static std::array<std::string, 4> sessionSupportList = {
109 "session-less", "single-session", "multi-session", "session-based"};
110
111static std::array<std::string, PRIVILEGE_OEM + 1> privList = {
112 "priv-reserved", "priv-callback", "priv-user",
113 "priv-operator", "priv-admin", "priv-oem"};
114
115ChannelConfig& getChannelConfigObject()
116{
117 static ChannelConfig channelConfig;
118 return channelConfig;
119}
120
121ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
122{
123 std::ofstream mutexCleanUpFile;
124 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
125 std::ofstream::out | std::ofstream::app);
126 if (!mutexCleanUpFile.good())
127 {
128 log<level::DEBUG>("Unable to open mutex cleanup file");
129 return;
130 }
131 mutexCleanUpFile.close();
132 mutexCleanupLock =
133 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
134 if (mutexCleanupLock.try_lock())
135 {
136 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
137 channelMutex =
138 std::make_unique<boost::interprocess::named_recursive_mutex>(
139 boost::interprocess::open_or_create, ipmiChannelMutex);
140 mutexCleanupLock.lock_sharable();
141 }
142 else
143 {
144 mutexCleanupLock.lock_sharable();
145 channelMutex =
146 std::make_unique<boost::interprocess::named_recursive_mutex>(
147 boost::interprocess::open_or_create, ipmiChannelMutex);
148 }
149
150 initChannelPersistData();
151}
152
153bool ChannelConfig::isValidChannel(const uint8_t& chNum)
154{
155 if (chNum > maxIpmiChannels)
156 {
157 log<level::DEBUG>("Invalid channel ID - Out of range");
158 return false;
159 }
160
161 if (channelData[chNum].isChValid == false)
162 {
163 log<level::DEBUG>("Channel is not valid");
164 return false;
165 }
166
167 return true;
168}
169
170EChannelSessSupported
171 ChannelConfig::getChannelSessionSupport(const uint8_t& chNum)
172{
173 EChannelSessSupported chSessSupport =
174 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
175 return chSessSupport;
176}
177
178bool ChannelConfig::isValidAuthType(const uint8_t& chNum,
179 const EAuthType& authType)
180{
181 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
182 {
183 log<level::DEBUG>("Invalid authentication type");
184 return false;
185 }
186
187 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
188 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
189 {
190 log<level::DEBUG>("Authentication type is not supported.");
191 return false;
192 }
193
194 return true;
195}
196
197int ChannelConfig::getChannelActiveSessions(const uint8_t& chNum)
198{
199 // TODO: TEMPORARY FIX
200 // Channels active session count is managed separatly
201 // by monitoring channel session which includes LAN and
202 // RAKP layer changes. This will be updated, once the
203 // authentication part is implemented.
204 return channelData[chNum].activeSessCount;
205}
206
207ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t& chNum,
208 ChannelInfo& chInfo)
209{
210 if (!isValidChannel(chNum))
211 {
212 log<level::DEBUG>("Invalid channel");
213 return IPMI_CC_INVALID_FIELD_REQUEST;
214 }
215
216 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
217 sizeof(channelData[chNum].chInfo),
218 reinterpret_cast<uint8_t*>(&chInfo));
219
220 return IPMI_CC_OK;
221}
222
223ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t& chNum,
224 ChannelAccess& chAccessData)
225{
226 if (!isValidChannel(chNum))
227 {
228 log<level::DEBUG>("Invalid channel");
229 return IPMI_CC_INVALID_FIELD_REQUEST;
230 }
231
232 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
233 {
234 log<level::DEBUG>("Session-less channel doesn't have access data.");
235 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
236 }
237
238 if (checkAndReloadVolatileData() != 0)
239 {
240 return IPMI_CC_UNSPECIFIED_ERROR;
241 }
242
243 std::copy_n(
244 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
245 sizeof(channelData[chNum].chAccess.chVolatileData),
246 reinterpret_cast<uint8_t*>(&chAccessData));
247
248 return IPMI_CC_OK;
249}
250
251ipmi_ret_t
252 ChannelConfig::setChannelAccessData(const uint8_t& chNum,
253 const ChannelAccess& chAccessData,
254 const uint8_t& setFlag)
255{
256 if (!isValidChannel(chNum))
257 {
258 log<level::DEBUG>("Invalid channel");
259 return IPMI_CC_INVALID_FIELD_REQUEST;
260 }
261
262 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
263 {
264 log<level::DEBUG>("Session-less channel doesn't have access data.");
265 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
266 }
267
268 if ((setFlag & setAccessMode) &&
269 (!isValidAccessMode(chAccessData.accessMode)))
270 {
271 log<level::DEBUG>("Invalid access mode specified");
272 return IPMI_CC_INVALID_FIELD_REQUEST;
273 }
274
275 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
276 channelLock{*channelMutex};
277
278 if (checkAndReloadVolatileData() != 0)
279 {
280 return IPMI_CC_UNSPECIFIED_ERROR;
281 }
282
283 if (setFlag & setAccessMode)
284 {
285 channelData[chNum].chAccess.chVolatileData.accessMode =
286 chAccessData.accessMode;
287 }
288 if (setFlag & setUserAuthEnabled)
289 {
290 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
291 chAccessData.userAuthDisabled;
292 }
293 if (setFlag & setMsgAuthEnabled)
294 {
295 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
296 chAccessData.perMsgAuthDisabled;
297 }
298 if (setFlag & setAlertingEnabled)
299 {
300 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
301 chAccessData.alertingDisabled;
302 }
303 if (setFlag & setPrivLimit)
304 {
305 channelData[chNum].chAccess.chVolatileData.privLimit =
306 chAccessData.privLimit;
307 }
308
309 // Write Volatile data to file
310 if (writeChannelVolatileData() != 0)
311 {
312 log<level::DEBUG>("Failed to update the channel volatile data");
313 return IPMI_CC_UNSPECIFIED_ERROR;
314 }
315 return IPMI_CC_OK;
316}
317
318ipmi_ret_t
319 ChannelConfig::getChannelAccessPersistData(const uint8_t& chNum,
320 ChannelAccess& chAccessData)
321{
322 if (!isValidChannel(chNum))
323 {
324 log<level::DEBUG>("Invalid channel");
325 return IPMI_CC_INVALID_FIELD_REQUEST;
326 }
327
328 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
329 {
330 log<level::DEBUG>("Session-less channel doesn't have access data.");
331 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
332 }
333
334 if (checkAndReloadNVData() != 0)
335 {
336 return IPMI_CC_UNSPECIFIED_ERROR;
337 }
338
339 std::copy_n(reinterpret_cast<uint8_t*>(
340 &channelData[chNum].chAccess.chNonVolatileData),
341 sizeof(channelData[chNum].chAccess.chNonVolatileData),
342 reinterpret_cast<uint8_t*>(&chAccessData));
343
344 return IPMI_CC_OK;
345}
346
347ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
348 const uint8_t& chNum, const ChannelAccess& chAccessData,
349 const uint8_t& setFlag)
350{
351 if (!isValidChannel(chNum))
352 {
353 log<level::DEBUG>("Invalid channel");
354 return IPMI_CC_INVALID_FIELD_REQUEST;
355 }
356
357 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
358 {
359 log<level::DEBUG>("Session-less channel doesn't have access data.");
360 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
361 }
362
363 if ((setFlag & setAccessMode) &&
364 (!isValidAccessMode(chAccessData.accessMode)))
365 {
366 log<level::DEBUG>("Invalid access mode specified");
367 return IPMI_CC_INVALID_FIELD_REQUEST;
368 }
369
370 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
371 channelLock{*channelMutex};
372
373 if (checkAndReloadNVData() != 0)
374 {
375 return IPMI_CC_UNSPECIFIED_ERROR;
376 }
377
378 if (setFlag & setAccessMode)
379 {
380 channelData[chNum].chAccess.chNonVolatileData.accessMode =
381 chAccessData.accessMode;
382 }
383 if (setFlag & setUserAuthEnabled)
384 {
385 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
386 chAccessData.userAuthDisabled;
387 }
388 if (setFlag & setMsgAuthEnabled)
389 {
390 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
391 chAccessData.perMsgAuthDisabled;
392 }
393 if (setFlag & setAlertingEnabled)
394 {
395 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
396 chAccessData.alertingDisabled;
397 }
398 if (setFlag & setPrivLimit)
399 {
400 channelData[chNum].chAccess.chNonVolatileData.privLimit =
401 chAccessData.privLimit;
402 }
403
404 // Write persistent data to file
405 if (writeChannelPersistData() != 0)
406 {
407 log<level::DEBUG>("Failed to update the presist data file");
408 return IPMI_CC_UNSPECIFIED_ERROR;
409 }
410 return IPMI_CC_OK;
411}
412
413ipmi_ret_t
414 ChannelConfig::getChannelAuthTypeSupported(const uint8_t& chNum,
415 uint8_t& authTypeSupported)
416{
417 if (!isValidChannel(chNum))
418 {
419 log<level::DEBUG>("Invalid channel");
420 return IPMI_CC_INVALID_FIELD_REQUEST;
421 }
422
423 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
424 return IPMI_CC_OK;
425}
426
427ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t& chNum,
428 const uint8_t& priv,
429 EAuthType& authType)
430{
431 if (!isValidChannel(chNum))
432 {
433 log<level::DEBUG>("Invalid channel");
434 return IPMI_CC_INVALID_FIELD_REQUEST;
435 }
436
437 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
438 {
439 log<level::DEBUG>("Sessionless channel doesn't have access data.");
440 return IPMI_CC_INVALID_FIELD_REQUEST;
441 }
442
443 if (!isValidPrivLimit(priv))
444 {
445 log<level::DEBUG>("Invalid privilege specified.");
446 return IPMI_CC_INVALID_FIELD_REQUEST;
447 }
448
449 // TODO: Hardcoded for now. Need to implement.
450 authType = EAuthType::none;
451
452 return IPMI_CC_OK;
453}
454
455std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
456{
457 struct stat fileStat;
458 if (stat(fileName.c_str(), &fileStat) != 0)
459 {
460 log<level::DEBUG>("Error in getting last updated time stamp");
461 return -EIO;
462 }
463 return fileStat.st_mtime;
464}
465
466EChannelAccessMode
467 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
468{
469 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
470 if (iter == accessModeList.end())
471 {
472 log<level::ERR>("Invalid access mode.",
473 entry("MODE_STR=%s", mode.c_str()));
474 throw std::invalid_argument("Invalid access mode.");
475 }
476
477 return static_cast<EChannelAccessMode>(
478 std::distance(accessModeList.begin(), iter));
479}
480
481std::string ChannelConfig::convertToAccessModeString(const uint8_t& value)
482{
483 if (accessModeList.size() <= value)
484 {
485 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
486 throw std::invalid_argument("Invalid access mode.");
487 }
488
489 return accessModeList.at(value);
490}
491
492CommandPrivilege
493 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
494{
495 auto iter = std::find(privList.begin(), privList.end(), value);
496 if (iter == privList.end())
497 {
498 log<level::ERR>("Invalid privilege.",
499 entry("PRIV_STR=%s", value.c_str()));
500 throw std::invalid_argument("Invalid privilege.");
501 }
502
503 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
504}
505
506std::string ChannelConfig::convertToPrivLimitString(const uint8_t& value)
507{
508 if (privList.size() <= value)
509 {
510 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
511 throw std::invalid_argument("Invalid privilege.");
512 }
513
514 return privList.at(value);
515}
516
517EChannelSessSupported
518 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
519{
520 auto iter =
521 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
522 if (iter == sessionSupportList.end())
523 {
524 log<level::ERR>("Invalid session supported.",
525 entry("SESS_STR=%s", value.c_str()));
526 throw std::invalid_argument("Invalid session supported.");
527 }
528
529 return static_cast<EChannelSessSupported>(
530 std::distance(sessionSupportList.begin(), iter));
531}
532
533EChannelMediumType
534 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
535{
536 std::unordered_map<std::string, EChannelMediumType>::iterator it =
537 mediumTypeMap.find(value);
538 if (it == mediumTypeMap.end())
539 {
540 log<level::ERR>("Invalid medium type.",
541 entry("MEDIUM_STR=%s", value.c_str()));
542 throw std::invalid_argument("Invalid medium type.");
543 }
544
545 return static_cast<EChannelMediumType>(it->second);
546}
547
548EChannelProtocolType
549 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
550{
551 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
552 protocolTypeMap.find(value);
553 if (it == protocolTypeMap.end())
554 {
555 log<level::ERR>("Invalid protocol type.",
556 entry("PROTO_STR=%s", value.c_str()));
557 throw std::invalid_argument("Invalid protocol type.");
558 }
559
560 return static_cast<EChannelProtocolType>(it->second);
561}
562
563Json ChannelConfig::readJsonFile(const std::string& configFile)
564{
565 std::ifstream jsonFile(configFile);
566 if (!jsonFile.good())
567 {
568 log<level::ERR>("JSON file not found");
569 return nullptr;
570 }
571
572 Json data = nullptr;
573 try
574 {
575 data = Json::parse(jsonFile, nullptr, false);
576 }
577 catch (Json::parse_error& e)
578 {
579 log<level::DEBUG>("Corrupted channel config.",
580 entry("MSG: %s", e.what()));
581 throw std::runtime_error("Corrupted channel config file");
582 }
583
584 return data;
585}
586
587int ChannelConfig::writeJsonFile(const std::string& configFile,
588 const Json& jsonData)
589{
590 std::ofstream jsonFile(configFile);
591 if (!jsonFile.good())
592 {
593 log<level::ERR>("JSON file not found");
594 return -EIO;
595 }
596
597 // Write JSON to file
598 jsonFile << jsonData;
599
600 jsonFile.flush();
601 return 0;
602}
603
604void ChannelConfig::setDefaultChannelConfig(const uint8_t& chNum,
605 const std::string& chName)
606{
607 channelData[chNum].chName = chName;
608 channelData[chNum].chID = chNum;
609 channelData[chNum].isChValid = false;
610 channelData[chNum].activeSessCount = 0;
611
612 channelData[chNum].chInfo.mediumType = defaultMediumType;
613 channelData[chNum].chInfo.protocolType = defaultProtocolType;
614 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
615 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
616 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
617}
618
619int ChannelConfig::loadChannelConfig()
620{
621 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
622 channelLock{*channelMutex};
623
624 Json data = readJsonFile(channelConfigDefaultFilename);
625 if (data == nullptr)
626 {
627 log<level::DEBUG>("Error in opening IPMI Channel data file");
628 return -EIO;
629 }
630
631 try
632 {
633 // Fill in global structure
634 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
635 {
636 std::fill(reinterpret_cast<uint8_t*>(&channelData[chNum]),
637 reinterpret_cast<uint8_t*>(&channelData[chNum]) +
638 sizeof(ChannelData),
639 0);
640 std::string chKey = std::to_string(chNum);
641 Json jsonChData = data[chKey].get<Json>();
642 if (jsonChData.is_null())
643 {
644 log<level::WARNING>(
645 "Channel not configured so loading default.",
646 entry("CHANNEL_NUM:%d", chNum));
647 // If user didn't want to configure specific channel (say
648 // reserved channel), then load that index with default values.
649 std::string chName(defaultChannelName);
650 setDefaultChannelConfig(chNum, chName);
651 }
652 else
653 {
654 std::string chName = jsonChData[nameString].get<std::string>();
655 channelData[chNum].chName = chName;
656 channelData[chNum].chID = chNum;
657 channelData[chNum].isChValid =
658 jsonChData[isValidString].get<bool>();
659 channelData[chNum].activeSessCount =
660 jsonChData.value(activeSessionsString, 0);
661 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
662 if (jsonChInfo.is_null())
663 {
664 log<level::ERR>("Invalid/corrupted channel config file");
665 return -EBADMSG;
666 }
667 else
668 {
669 std::string medTypeStr =
670 jsonChInfo[mediumTypeString].get<std::string>();
671 channelData[chNum].chInfo.mediumType = static_cast<uint8_t>(
672 convertToMediumTypeIndex(medTypeStr));
673 std::string protoTypeStr =
674 jsonChInfo[protocolTypeString].get<std::string>();
675 channelData[chNum].chInfo.protocolType =
676 static_cast<uint8_t>(
677 convertToProtocolTypeIndex(protoTypeStr));
678 std::string sessStr =
679 jsonChInfo[sessionSupportedString].get<std::string>();
680 channelData[chNum].chInfo.sessionSupported =
681 static_cast<uint8_t>(
682 convertToSessionSupportIndex(sessStr));
683 channelData[chNum].chInfo.isIpmi =
684 jsonChInfo[isIpmiString].get<bool>();
685 channelData[chNum].chInfo.authTypeSupported =
686 defaultAuthType;
687 }
688 }
689 }
690 }
691 catch (const Json::exception& e)
692 {
693 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
694 return -EBADMSG;
695 }
696 catch (const std::invalid_argument& e)
697 {
698 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
699 return -EBADMSG;
700 }
701
702 return 0;
703}
704
705int ChannelConfig::readChannelVolatileData()
706{
707 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
708 channelLock{*channelMutex};
709
710 Json data = readJsonFile(channelVolatileDataFilename);
711 if (data == nullptr)
712 {
713 log<level::DEBUG>("Error in opening IPMI Channel data file");
714 return -EIO;
715 }
716
717 try
718 {
719 // Fill in global structure
720 for (auto it = data.begin(); it != data.end(); ++it)
721 {
722 std::string chKey = it.key();
723 uint8_t chNum = std::stoi(chKey, nullptr, 10);
724 if ((chNum < 0) || (chNum > maxIpmiChannels))
725 {
726 log<level::DEBUG>(
727 "Invalid channel access entry in config file");
728 throw std::out_of_range("Out of range - channel number");
729 }
730 Json jsonChData = it.value();
731 if (!jsonChData.is_null())
732 {
733 std::string accModeStr =
734 jsonChData[accessModeString].get<std::string>();
735 channelData[chNum].chAccess.chVolatileData.accessMode =
736 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
737 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
738 jsonChData[userAuthDisabledString].get<bool>();
739 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
740 jsonChData[perMsgAuthDisabledString].get<bool>();
741 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
742 jsonChData[alertingDisabledString].get<bool>();
743 std::string privStr =
744 jsonChData[privLimitString].get<std::string>();
745 channelData[chNum].chAccess.chVolatileData.privLimit =
746 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
747 }
748 else
749 {
750 log<level::ERR>(
751 "Invalid/corrupted volatile channel access file",
752 entry("FILE: %s", channelVolatileDataFilename));
753 throw std::runtime_error(
754 "Corrupted volatile channel access file");
755 }
756 }
757 }
758 catch (const Json::exception& e)
759 {
760 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
761 throw std::runtime_error("Corrupted volatile channel access file");
762 }
763 catch (const std::invalid_argument& e)
764 {
765 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
766 throw std::runtime_error("Corrupted volatile channel access file");
767 }
768
769 // Update the timestamp
770 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
771 return 0;
772}
773
774int ChannelConfig::readChannelPersistData()
775{
776 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
777 channelLock{*channelMutex};
778
779 Json data = readJsonFile(channelNvDataFilename);
780 if (data == nullptr)
781 {
782 log<level::DEBUG>("Error in opening IPMI Channel data file");
783 return -EIO;
784 }
785
786 try
787 {
788 // Fill in global structure
789 for (auto it = data.begin(); it != data.end(); ++it)
790 {
791 std::string chKey = it.key();
792 uint8_t chNum = std::stoi(chKey, nullptr, 10);
793 if ((chNum < 0) || (chNum > maxIpmiChannels))
794 {
795 log<level::DEBUG>(
796 "Invalid channel access entry in config file");
797 throw std::out_of_range("Out of range - channel number");
798 }
799 Json jsonChData = it.value();
800 if (!jsonChData.is_null())
801 {
802 std::string accModeStr =
803 jsonChData[accessModeString].get<std::string>();
804 channelData[chNum].chAccess.chNonVolatileData.accessMode =
805 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
806 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
807 jsonChData[userAuthDisabledString].get<bool>();
808 channelData[chNum]
809 .chAccess.chNonVolatileData.perMsgAuthDisabled =
810 jsonChData[perMsgAuthDisabledString].get<bool>();
811 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
812 jsonChData[alertingDisabledString].get<bool>();
813 std::string privStr =
814 jsonChData[privLimitString].get<std::string>();
815 channelData[chNum].chAccess.chNonVolatileData.privLimit =
816 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
817 }
818 else
819 {
820 log<level::ERR>("Invalid/corrupted nv channel access file",
821 entry("FILE:%s", channelNvDataFilename));
822 throw std::runtime_error("Corrupted nv channel access file");
823 }
824 }
825 }
826 catch (const Json::exception& e)
827 {
828 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
829 throw std::runtime_error("Corrupted nv channel access file");
830 }
831 catch (const std::invalid_argument& e)
832 {
833 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
834 throw std::runtime_error("Corrupted nv channel access file");
835 }
836
837 // Update the timestamp
838 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
839 return 0;
840}
841
842int ChannelConfig::writeChannelVolatileData()
843{
844 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
845 channelLock{*channelMutex};
846 Json outData;
847
848 try
849 {
850 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
851 {
852 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
853 {
854 Json jsonObj;
855 std::string chKey = std::to_string(chNum);
856 std::string accModeStr = convertToAccessModeString(
857 channelData[chNum].chAccess.chVolatileData.accessMode);
858 jsonObj[accessModeString] = accModeStr;
859 jsonObj[userAuthDisabledString] =
860 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
861 jsonObj[perMsgAuthDisabledString] =
862 channelData[chNum]
863 .chAccess.chVolatileData.perMsgAuthDisabled;
864 jsonObj[alertingDisabledString] =
865 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
866 std::string privStr = convertToPrivLimitString(
867 channelData[chNum].chAccess.chVolatileData.privLimit);
868 jsonObj[privLimitString] = privStr;
869
870 outData[chKey] = jsonObj;
871 }
872 }
873 }
874 catch (const std::invalid_argument& e)
875 {
876 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
877 return -EINVAL;
878 }
879
880 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
881 {
882 log<level::DEBUG>("Error in write JSON data to file");
883 return -EIO;
884 }
885
886 // Update the timestamp
887 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
888 return 0;
889}
890
891int ChannelConfig::writeChannelPersistData()
892{
893 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
894 channelLock{*channelMutex};
895 Json outData;
896
897 try
898 {
899 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
900 {
901 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
902 {
903 Json jsonObj;
904 std::string chKey = std::to_string(chNum);
905 std::string accModeStr = convertToAccessModeString(
906 channelData[chNum].chAccess.chNonVolatileData.accessMode);
907 jsonObj[accessModeString] = accModeStr;
908 jsonObj[userAuthDisabledString] =
909 channelData[chNum]
910 .chAccess.chNonVolatileData.userAuthDisabled;
911 jsonObj[perMsgAuthDisabledString] =
912 channelData[chNum]
913 .chAccess.chNonVolatileData.perMsgAuthDisabled;
914 jsonObj[alertingDisabledString] =
915 channelData[chNum]
916 .chAccess.chNonVolatileData.alertingDisabled;
917 std::string privStr = convertToPrivLimitString(
918 channelData[chNum].chAccess.chNonVolatileData.privLimit);
919 jsonObj[privLimitString] = privStr;
920
921 outData[chKey] = jsonObj;
922 }
923 }
924 }
925 catch (const std::invalid_argument& e)
926 {
927 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
928 return -EINVAL;
929 }
930
931 if (writeJsonFile(channelNvDataFilename, outData) != 0)
932 {
933 log<level::DEBUG>("Error in write JSON data to file");
934 return -EIO;
935 }
936
937 // Update the timestamp
938 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
939 return 0;
940}
941
942int ChannelConfig::checkAndReloadNVData()
943{
944 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
945 int ret = 0;
946 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
947 {
948 try
949 {
950 ret = readChannelPersistData();
951 }
952 catch (const std::exception& e)
953 {
954 log<level::ERR>("Exception caught in readChannelPersistData.",
955 entry("MSG=%s", e.what()));
956 ret = -EIO;
957 }
958 }
959 return ret;
960}
961
962int ChannelConfig::checkAndReloadVolatileData()
963{
964 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
965 int ret = 0;
966 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
967 {
968 try
969 {
970 ret = readChannelVolatileData();
971 }
972 catch (const std::exception& e)
973 {
974 log<level::ERR>("Exception caught in readChannelVolatileData.",
975 entry("MSG=%s", e.what()));
976 ret = -EIO;
977 }
978 }
979 return ret;
980}
981
982void ChannelConfig::initChannelPersistData()
983{
984 /* Always read the channel config */
985 if (loadChannelConfig() != 0)
986 {
987 log<level::ERR>("Failed to read channel config file");
988 throw std::ios_base::failure("Failed to load channel configuration");
989 }
990
991 /* Populate the channel persist data */
992 if (readChannelPersistData() != 0)
993 {
994 // Copy default NV data to RW location
995 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
996 channelNvDataFilename);
997
998 // Load the channel access NV data
999 if (readChannelPersistData() != 0)
1000 {
1001 log<level::ERR>("Failed to read channel access NV data");
1002 throw std::ios_base::failure(
1003 "Failed to read channel access NV configuration");
1004 }
1005 }
1006
1007 // First check the volatile data file
1008 // If not present, load the default values
1009 if (readChannelVolatileData() != 0)
1010 {
1011 // Copy default volatile data to temporary location
1012 // NV file(channelNvDataFilename) must have created by now.
1013 std::experimental::filesystem::copy_file(channelNvDataFilename,
1014 channelVolatileDataFilename);
1015
1016 // Load the channel access volatile data
1017 if (readChannelVolatileData() != 0)
1018 {
1019 log<level::ERR>("Failed to read channel access volatile data");
1020 throw std::ios_base::failure(
1021 "Failed to read channel access volatile configuration");
1022 }
1023 }
1024 return;
1025}
1026
1027} // namespace ipmi