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_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 <exception>
27 #include <experimental/filesystem>
28 #include <fstream>
29 #include <phosphor-logging/log.hpp>
30 #include <sdbusplus/bus/match.hpp>
31 #include <sdbusplus/server/object.hpp>
32 #include <unordered_map>
33 
34 namespace ipmi
35 {
36 
37 using namespace phosphor::logging;
38 
39 static constexpr const char* channelAccessDefaultFilename =
40     "/usr/share/ipmi-providers/channel_access.json";
41 static constexpr const char* channelConfigDefaultFilename =
42     "/usr/share/ipmi-providers/channel_config.json";
43 static constexpr const char* channelNvDataFilename =
44     "/var/lib/ipmi/channel_access_nv.json";
45 static constexpr const char* channelVolatileDataFilename =
46     "/run/ipmi/channel_access_volatile.json";
47 
48 // TODO: Get the service name dynamically..
49 static constexpr const char* networkIntfServiceName =
50     "xyz.openbmc_project.Network";
51 static constexpr const char* networkIntfObjectBasePath =
52     "/xyz/openbmc_project/network";
53 static constexpr const char* networkChConfigIntfName =
54     "xyz.openbmc_project.Channel.ChannelAccess";
55 static constexpr const char* privilegePropertyString = "MaxPrivilege";
56 static constexpr const char* dBusPropertiesInterface =
57     "org.freedesktop.DBus.Properties";
58 static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
59 
60 // STRING DEFINES: Should sync with key's in JSON
61 static constexpr const char* nameString = "name";
62 static constexpr const char* isValidString = "is_valid";
63 static constexpr const char* activeSessionsString = "active_sessions";
64 static constexpr const char* maxTransferSizeString = "max_transfer_size";
65 static constexpr const char* channelInfoString = "channel_info";
66 static constexpr const char* mediumTypeString = "medium_type";
67 static constexpr const char* protocolTypeString = "protocol_type";
68 static constexpr const char* sessionSupportedString = "session_supported";
69 static constexpr const char* isIpmiString = "is_ipmi";
70 static constexpr const char* authTypeSupportedString = "auth_type_supported";
71 static constexpr const char* accessModeString = "access_mode";
72 static constexpr const char* userAuthDisabledString = "user_auth_disabled";
73 static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
74 static constexpr const char* alertingDisabledString = "alerting_disabled";
75 static constexpr const char* privLimitString = "priv_limit";
76 static constexpr const char* authTypeEnabledString = "auth_type_enabled";
77 
78 // Default values
79 static constexpr const char* defaultChannelName = "RESERVED";
80 static constexpr const uint8_t defaultMediumType =
81     static_cast<uint8_t>(EChannelMediumType::reserved);
82 static constexpr const uint8_t defaultProtocolType =
83     static_cast<uint8_t>(EChannelProtocolType::reserved);
84 static constexpr const uint8_t defaultSessionSupported =
85     static_cast<uint8_t>(EChannelSessSupported::none);
86 static constexpr const uint8_t defaultAuthType =
87     static_cast<uint8_t>(EAuthType::none);
88 static constexpr const bool defaultIsIpmiState = false;
89 static constexpr size_t smallChannelSize = 64;
90 
91 std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal
92     __attribute__((init_priority(101)));
93 
94 // String mappings use in JSON config file
95 static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
96     {"reserved", EChannelMediumType::reserved},
97     {"ipmb", EChannelMediumType::ipmb},
98     {"icmb-v1.0", EChannelMediumType::icmbV10},
99     {"icmb-v0.9", EChannelMediumType::icmbV09},
100     {"lan-802.3", EChannelMediumType::lan8032},
101     {"serial", EChannelMediumType::serial},
102     {"other-lan", EChannelMediumType::otherLan},
103     {"pci-smbus", EChannelMediumType::pciSmbus},
104     {"smbus-v1.0", EChannelMediumType::smbusV11},
105     {"smbus-v2.0", EChannelMediumType::smbusV20},
106     {"usb-1x", EChannelMediumType::usbV1x},
107     {"usb-2x", EChannelMediumType::usbV2x},
108     {"system-interface", EChannelMediumType::systemInterface},
109     {"oem", EChannelMediumType::oem},
110     {"unknown", EChannelMediumType::unknown}};
111 
112 static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = {
113     {interfaceKCS, "SMS"},
114     {interfaceLAN1, "eth0"},
115     {interfaceUnknown, "unknown"}};
116 
117 static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
118     {"na", EChannelProtocolType::na},
119     {"ipmb-1.0", EChannelProtocolType::ipmbV10},
120     {"icmb-2.0", EChannelProtocolType::icmbV11},
121     {"reserved", EChannelProtocolType::reserved},
122     {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
123     {"kcs", EChannelProtocolType::kcs},
124     {"smic", EChannelProtocolType::smic},
125     {"bt-10", EChannelProtocolType::bt10},
126     {"bt-15", EChannelProtocolType::bt15},
127     {"tmode", EChannelProtocolType::tMode},
128     {"oem", EChannelProtocolType::oem}};
129 
130 static std::array<std::string, 4> accessModeList = {
131     "disabled", "pre-boot", "always_available", "shared"};
132 
133 static std::array<std::string, 4> sessionSupportList = {
134     "session-less", "single-session", "multi-session", "session-based"};
135 
136 static std::array<std::string, PRIVILEGE_OEM + 1> privList = {
137     "priv-reserved", "priv-callback", "priv-user",
138     "priv-operator", "priv-admin",    "priv-oem"};
139 
140 std::string ChannelConfig::getChannelName(const uint8_t chNum)
141 {
142     if (!isValidChannel(chNum))
143     {
144         log<level::ERR>("Invalid channel number.",
145                         entry("CHANNEL_ID=%d", chNum));
146         throw std::invalid_argument("Invalid channel number");
147     }
148 
149     return channelData[chNum].chName;
150 }
151 
152 int ChannelConfig::convertToChannelNumberFromChannelName(
153     const std::string& chName)
154 {
155     for (const auto& it : channelData)
156     {
157         if (it.chName == chName)
158         {
159             return it.chID;
160         }
161     }
162     log<level::ERR>("Invalid channel name.",
163                     entry("CHANNEL=%s", chName.c_str()));
164     throw std::invalid_argument("Invalid channel name");
165 
166     return -1;
167 }
168 
169 std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
170 {
171 
172     constexpr size_t length = strlen(networkIntfObjectBasePath);
173     if (((length + 1) >= path.size()) ||
174         path.compare(0, length, networkIntfObjectBasePath))
175     {
176         log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str()));
177         throw std::invalid_argument("Invalid object path");
178     }
179     std::string chName(path, length + 1);
180     return chName;
181 }
182 
183 void ChannelConfig::processChAccessPropChange(
184     const std::string& path, const DbusChObjProperties& chProperties)
185 {
186     // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
187     std::string chName;
188     try
189     {
190         chName = getChannelNameFromPath(path);
191     }
192     catch (const std::invalid_argument& e)
193     {
194         log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
195         return;
196     }
197 
198     // Get the MaxPrivilege property value from the signal
199     std::string intfPrivStr;
200     std::string propName;
201     for (const auto& prop : chProperties)
202     {
203         if (prop.first == privilegePropertyString)
204         {
205             propName = privilegePropertyString;
206             intfPrivStr = std::get<std::string>(prop.second);
207             break;
208         }
209     }
210 
211     if (propName != privilegePropertyString)
212     {
213         log<level::ERR>("Unknown signal caught.");
214         return;
215     }
216 
217     if (intfPrivStr.empty())
218     {
219         log<level::ERR>("Invalid privilege string.",
220                         entry("INTF=%s", chName.c_str()));
221         return;
222     }
223 
224     uint8_t intfPriv = 0;
225     int chNum;
226     try
227     {
228         intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
229         chNum = convertToChannelNumberFromChannelName(chName);
230     }
231     catch (const std::invalid_argument& e)
232     {
233         log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
234         return;
235     }
236 
237     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
238         channelLock{*channelMutex};
239     // skip updating the values, if this property change originated from IPMI.
240     if (signalFlag & (1 << chNum))
241     {
242         signalFlag &= ~(1 << chNum);
243         log<level::DEBUG>("Request originated from IPMI so ignoring signal");
244         return;
245     }
246 
247     // Update both volatile & Non-volatile, if there is mismatch.
248     // as property change other than IPMI, has to update both volatile &
249     // non-volatile data.
250     checkAndReloadVolatileData();
251     checkAndReloadNVData();
252     if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
253     {
254         // Update NV data
255         channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
256         if (writeChannelPersistData() != 0)
257         {
258             log<level::ERR>("Failed to update the persist data file");
259             return;
260         }
261 
262         // Update Volatile data
263         if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
264         {
265             channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
266             if (writeChannelVolatileData() != 0)
267             {
268                 log<level::ERR>("Failed to update the volatile data file");
269                 return;
270             }
271         }
272     }
273 
274     return;
275 }
276 
277 ChannelConfig& getChannelConfigObject()
278 {
279     static ChannelConfig channelConfig;
280     return channelConfig;
281 }
282 
283 ChannelConfig::~ChannelConfig()
284 {
285     if (signalHndlrObjectState)
286     {
287         chPropertiesSignal.reset();
288         sigHndlrLock.unlock();
289     }
290 }
291 
292 ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
293 {
294     std::ofstream mutexCleanUpFile;
295     mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
296                           std::ofstream::out | std::ofstream::app);
297     if (!mutexCleanUpFile.good())
298     {
299         log<level::DEBUG>("Unable to open mutex cleanup file");
300         return;
301     }
302     mutexCleanUpFile.close();
303     mutexCleanupLock =
304         boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
305     if (mutexCleanupLock.try_lock())
306     {
307         boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
308         channelMutex =
309             std::make_unique<boost::interprocess::named_recursive_mutex>(
310                 boost::interprocess::open_or_create, ipmiChannelMutex);
311         mutexCleanupLock.lock_sharable();
312     }
313     else
314     {
315         mutexCleanupLock.lock_sharable();
316         channelMutex =
317             std::make_unique<boost::interprocess::named_recursive_mutex>(
318                 boost::interprocess::open_or_create, ipmiChannelMutex);
319     }
320 
321     initChannelPersistData();
322 
323     sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
324     // Register it for single object and single process either netipimd /
325     // host-ipmid
326     if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
327     {
328         log<level::DEBUG>("Registering channel signal handler.");
329         chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
330             bus,
331             sdbusplus::bus::match::rules::path_namespace(
332                 networkIntfObjectBasePath) +
333                 sdbusplus::bus::match::rules::type::signal() +
334                 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
335                 sdbusplus::bus::match::rules::interface(
336                     dBusPropertiesInterface) +
337                 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
338             [&](sdbusplus::message::message& msg) {
339                 DbusChObjProperties props;
340                 std::string iface;
341                 std::string path = msg.get_path();
342                 msg.read(iface, props);
343                 processChAccessPropChange(path, props);
344             });
345         signalHndlrObjectState = true;
346     }
347 }
348 
349 bool ChannelConfig::isValidChannel(const uint8_t chNum)
350 {
351     if (chNum > maxIpmiChannels)
352     {
353         log<level::DEBUG>("Invalid channel ID - Out of range");
354         return false;
355     }
356 
357     if (channelData[chNum].isChValid == false)
358     {
359         log<level::DEBUG>("Channel is not valid");
360     }
361 
362     return channelData[chNum].isChValid;
363 }
364 
365 EChannelSessSupported
366     ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
367 {
368     EChannelSessSupported chSessSupport =
369         (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
370     return chSessSupport;
371 }
372 
373 bool ChannelConfig::isValidAuthType(const uint8_t chNum,
374                                     const EAuthType& authType)
375 {
376     if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
377     {
378         log<level::DEBUG>("Invalid authentication type");
379         return false;
380     }
381 
382     uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
383     if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
384     {
385         log<level::DEBUG>("Authentication type is not supported.");
386         return false;
387     }
388 
389     return true;
390 }
391 
392 int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
393 {
394     // TODO: TEMPORARY FIX
395     // Channels active session count is managed separately
396     // by monitoring channel session which includes LAN and
397     // RAKP layer changes. This will be updated, once the
398     // authentication part is implemented.
399     return channelData[chNum].activeSessCount;
400 }
401 
402 size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
403 {
404     return channelData[chNum].maxTransferSize;
405 }
406 
407 Cc ChannelConfig::getChannelInfo(const uint8_t chNum, ChannelInfo& chInfo)
408 {
409     if (!isValidChannel(chNum))
410     {
411         log<level::DEBUG>("Invalid channel");
412         return ccInvalidFieldRequest;
413     }
414 
415     std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
416                 sizeof(channelData[chNum].chInfo),
417                 reinterpret_cast<uint8_t*>(&chInfo));
418     return ccSuccess;
419 }
420 
421 Cc ChannelConfig::getChannelAccessData(const uint8_t chNum,
422                                        ChannelAccess& chAccessData)
423 {
424     if (!isValidChannel(chNum))
425     {
426         log<level::DEBUG>("Invalid channel");
427         return ccInvalidFieldRequest;
428     }
429 
430     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
431     {
432         log<level::DEBUG>("Session-less channel doesn't have access data.");
433         return ccActionNotSupportedForChannel;
434     }
435 
436     if (checkAndReloadVolatileData() != 0)
437     {
438         return ccUnspecifiedError;
439     }
440 
441     std::copy_n(
442         reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
443         sizeof(channelData[chNum].chAccess.chVolatileData),
444         reinterpret_cast<uint8_t*>(&chAccessData));
445 
446     return ccSuccess;
447 }
448 
449 Cc ChannelConfig::setChannelAccessData(const uint8_t chNum,
450                                        const ChannelAccess& chAccessData,
451                                        const uint8_t setFlag)
452 {
453     if (!isValidChannel(chNum))
454     {
455         log<level::DEBUG>("Invalid channel");
456         return ccInvalidFieldRequest;
457     }
458 
459     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
460     {
461         log<level::DEBUG>("Session-less channel doesn't have access data.");
462         return ccActionNotSupportedForChannel;
463     }
464 
465     if (((setFlag & setAccessMode) &&
466          (!isValidAccessMode(chAccessData.accessMode))) ||
467         ((setFlag & setPrivLimit) &&
468          (!isValidPrivLimit(chAccessData.privLimit))))
469     {
470         log<level::DEBUG>("Invalid access mode / privilege limit specified");
471         return ccInvalidFieldRequest;
472     }
473 
474     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
475         channelLock{*channelMutex};
476 
477     if (checkAndReloadVolatileData() != 0)
478     {
479         return ccUnspecifiedError;
480     }
481 
482     if (setFlag & setAccessMode)
483     {
484         channelData[chNum].chAccess.chVolatileData.accessMode =
485             chAccessData.accessMode;
486     }
487     if (setFlag & setUserAuthEnabled)
488     {
489         channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
490             chAccessData.userAuthDisabled;
491     }
492     if (setFlag & setMsgAuthEnabled)
493     {
494         channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
495             chAccessData.perMsgAuthDisabled;
496     }
497     if (setFlag & setAlertingEnabled)
498     {
499         channelData[chNum].chAccess.chVolatileData.alertingDisabled =
500             chAccessData.alertingDisabled;
501     }
502     if (setFlag & setPrivLimit)
503     {
504         channelData[chNum].chAccess.chVolatileData.privLimit =
505             chAccessData.privLimit;
506     }
507 
508     // Write Volatile data to file
509     if (writeChannelVolatileData() != 0)
510     {
511         log<level::DEBUG>("Failed to update the channel volatile data");
512         return ccUnspecifiedError;
513     }
514     return ccSuccess;
515 }
516 
517 Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
518                                               ChannelAccess& chAccessData)
519 {
520     if (!isValidChannel(chNum))
521     {
522         log<level::DEBUG>("Invalid channel");
523         return ccInvalidFieldRequest;
524     }
525 
526     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
527     {
528         log<level::DEBUG>("Session-less channel doesn't have access data.");
529         return ccActionNotSupportedForChannel;
530     }
531 
532     if (checkAndReloadNVData() != 0)
533     {
534         return ccUnspecifiedError;
535     }
536 
537     std::copy_n(reinterpret_cast<uint8_t*>(
538                     &channelData[chNum].chAccess.chNonVolatileData),
539                 sizeof(channelData[chNum].chAccess.chNonVolatileData),
540                 reinterpret_cast<uint8_t*>(&chAccessData));
541 
542     return ccSuccess;
543 }
544 
545 Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum,
546                                               const ChannelAccess& chAccessData,
547                                               const uint8_t setFlag)
548 {
549     if (!isValidChannel(chNum))
550     {
551         log<level::DEBUG>("Invalid channel");
552         return ccInvalidFieldRequest;
553     }
554 
555     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
556     {
557         log<level::DEBUG>("Session-less channel doesn't have access data.");
558         return ccActionNotSupportedForChannel;
559     }
560 
561     if (((setFlag & setAccessMode) &&
562          (!isValidAccessMode(chAccessData.accessMode))) ||
563         ((setFlag & setPrivLimit) &&
564          (!isValidPrivLimit(chAccessData.privLimit))))
565     {
566         log<level::DEBUG>("Invalid access mode / privilege limit specified");
567         return ccInvalidFieldRequest;
568     }
569 
570     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
571         channelLock{*channelMutex};
572 
573     if (checkAndReloadNVData() != 0)
574     {
575         return ccUnspecifiedError;
576     }
577 
578     if (setFlag & setAccessMode)
579     {
580         channelData[chNum].chAccess.chNonVolatileData.accessMode =
581             chAccessData.accessMode;
582     }
583     if (setFlag & setUserAuthEnabled)
584     {
585         channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
586             chAccessData.userAuthDisabled;
587     }
588     if (setFlag & setMsgAuthEnabled)
589     {
590         channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
591             chAccessData.perMsgAuthDisabled;
592     }
593     if (setFlag & setAlertingEnabled)
594     {
595         channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
596             chAccessData.alertingDisabled;
597     }
598     if (setFlag & setPrivLimit)
599     {
600         // Send Update to network channel config interfaces over dbus
601         std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
602         std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
603                                      "/" + channelData[chNum].chName;
604         try
605         {
606             if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
607                                      networkChConfigIntfName,
608                                      privilegePropertyString, privStr))
609             {
610                 log<level::DEBUG>(
611                     "Network interface does not exist",
612                     entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
613                 return ccUnspecifiedError;
614             }
615         }
616         catch (const sdbusplus::exception::SdBusError& e)
617         {
618             log<level::ERR>("Exception: Network interface does not exist");
619             return ccInvalidFieldRequest;
620         }
621         signalFlag |= (1 << chNum);
622         channelData[chNum].chAccess.chNonVolatileData.privLimit =
623             chAccessData.privLimit;
624     }
625 
626     // Write persistent data to file
627     if (writeChannelPersistData() != 0)
628     {
629         log<level::DEBUG>("Failed to update the presist data file");
630         return ccUnspecifiedError;
631     }
632     return ccSuccess;
633 }
634 
635 Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
636                                               uint8_t& authTypeSupported)
637 {
638     if (!isValidChannel(chNum))
639     {
640         log<level::DEBUG>("Invalid channel");
641         return ccInvalidFieldRequest;
642     }
643 
644     authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
645     return ccSuccess;
646 }
647 
648 Cc ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
649                                             const uint8_t priv,
650                                             EAuthType& authType)
651 {
652     if (!isValidChannel(chNum))
653     {
654         log<level::DEBUG>("Invalid channel");
655         return ccInvalidFieldRequest;
656     }
657 
658     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
659     {
660         log<level::DEBUG>("Sessionless channel doesn't have access data.");
661         return ccInvalidFieldRequest;
662     }
663 
664     if (!isValidPrivLimit(priv))
665     {
666         log<level::DEBUG>("Invalid privilege specified.");
667         return ccInvalidFieldRequest;
668     }
669 
670     // TODO: Hardcoded for now. Need to implement.
671     authType = EAuthType::none;
672 
673     return ccSuccess;
674 }
675 
676 std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
677 {
678     struct stat fileStat;
679     if (stat(fileName.c_str(), &fileStat) != 0)
680     {
681         log<level::DEBUG>("Error in getting last updated time stamp");
682         return -EIO;
683     }
684     return fileStat.st_mtime;
685 }
686 
687 EChannelAccessMode
688     ChannelConfig::convertToAccessModeIndex(const std::string& mode)
689 {
690     auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
691     if (iter == accessModeList.end())
692     {
693         log<level::ERR>("Invalid access mode.",
694                         entry("MODE_STR=%s", mode.c_str()));
695         throw std::invalid_argument("Invalid access mode.");
696     }
697 
698     return static_cast<EChannelAccessMode>(
699         std::distance(accessModeList.begin(), iter));
700 }
701 
702 std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
703 {
704     if (accessModeList.size() <= value)
705     {
706         log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
707         throw std::invalid_argument("Invalid access mode.");
708     }
709 
710     return accessModeList.at(value);
711 }
712 
713 CommandPrivilege
714     ChannelConfig::convertToPrivLimitIndex(const std::string& value)
715 {
716     auto iter = std::find(privList.begin(), privList.end(), value);
717     if (iter == privList.end())
718     {
719         log<level::ERR>("Invalid privilege.",
720                         entry("PRIV_STR=%s", value.c_str()));
721         throw std::invalid_argument("Invalid privilege.");
722     }
723 
724     return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
725 }
726 
727 std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
728 {
729     if (privList.size() <= value)
730     {
731         log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
732         throw std::invalid_argument("Invalid privilege.");
733     }
734 
735     return privList.at(value);
736 }
737 
738 EChannelSessSupported
739     ChannelConfig::convertToSessionSupportIndex(const std::string& value)
740 {
741     auto iter =
742         std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
743     if (iter == sessionSupportList.end())
744     {
745         log<level::ERR>("Invalid session supported.",
746                         entry("SESS_STR=%s", value.c_str()));
747         throw std::invalid_argument("Invalid session supported.");
748     }
749 
750     return static_cast<EChannelSessSupported>(
751         std::distance(sessionSupportList.begin(), iter));
752 }
753 
754 EChannelMediumType
755     ChannelConfig::convertToMediumTypeIndex(const std::string& value)
756 {
757     std::unordered_map<std::string, EChannelMediumType>::iterator it =
758         mediumTypeMap.find(value);
759     if (it == mediumTypeMap.end())
760     {
761         log<level::ERR>("Invalid medium type.",
762                         entry("MEDIUM_STR=%s", value.c_str()));
763         throw std::invalid_argument("Invalid medium type.");
764     }
765 
766     return static_cast<EChannelMediumType>(it->second);
767 }
768 
769 EChannelProtocolType
770     ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
771 {
772     std::unordered_map<std::string, EChannelProtocolType>::iterator it =
773         protocolTypeMap.find(value);
774     if (it == protocolTypeMap.end())
775     {
776         log<level::ERR>("Invalid protocol type.",
777                         entry("PROTO_STR=%s", value.c_str()));
778         throw std::invalid_argument("Invalid protocol type.");
779     }
780 
781     return static_cast<EChannelProtocolType>(it->second);
782 }
783 
784 Json ChannelConfig::readJsonFile(const std::string& configFile)
785 {
786     std::ifstream jsonFile(configFile);
787     if (!jsonFile.good())
788     {
789         log<level::INFO>("JSON file not found",
790                          entry("FILE_NAME=%s", configFile.c_str()));
791         return nullptr;
792     }
793 
794     Json data = nullptr;
795     try
796     {
797         data = Json::parse(jsonFile, nullptr, false);
798     }
799     catch (Json::parse_error& e)
800     {
801         log<level::DEBUG>("Corrupted channel config.",
802                           entry("MSG=%s", e.what()));
803         throw std::runtime_error("Corrupted channel config file");
804     }
805 
806     return data;
807 }
808 
809 int ChannelConfig::writeJsonFile(const std::string& configFile,
810                                  const Json& jsonData)
811 {
812     const std::string tmpFile = configFile + "_tmp";
813     int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
814                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
815     if (fd < 0)
816     {
817         log<level::ERR>("Error in creating json file",
818                         entry("FILE_NAME = %s", tmpFile.c_str()));
819         return -EIO;
820     }
821     const auto& writeData = jsonData.dump();
822     if (write(fd, writeData.c_str(), writeData.size()) !=
823         static_cast<ssize_t>(writeData.size()))
824     {
825         close(fd);
826         log<level::ERR>("Error in writing configuration file",
827                         entry("FILE_NAME = %s", tmpFile.c_str()));
828         return -EIO;
829     }
830     close(fd);
831 
832     if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
833     {
834         log<level::ERR>("Error in renaming temporary data file",
835                         entry("FILE_NAME = %s", tmpFile.c_str()));
836         return -EIO;
837     }
838 
839     return 0;
840 }
841 
842 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
843                                             const std::string& chName)
844 {
845     channelData[chNum].chName = chName;
846     channelData[chNum].chID = chNum;
847     channelData[chNum].isChValid = false;
848     channelData[chNum].activeSessCount = 0;
849 
850     channelData[chNum].chInfo.mediumType = defaultMediumType;
851     channelData[chNum].chInfo.protocolType = defaultProtocolType;
852     channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
853     channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
854     channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
855 }
856 
857 int ChannelConfig::loadChannelConfig()
858 {
859     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
860         channelLock{*channelMutex};
861 
862     Json data = readJsonFile(channelConfigDefaultFilename);
863     if (data.empty())
864     {
865         log<level::DEBUG>("Error in opening IPMI Channel data file");
866         return -EIO;
867     }
868 
869     channelData.fill(ChannelProperties{});
870 
871     for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
872     {
873         try
874         {
875             std::string chKey = std::to_string(chNum);
876             Json jsonChData = data[chKey].get<Json>();
877             if (jsonChData.is_null())
878             {
879                 log<level::WARNING>(
880                     "Channel not configured so loading default.",
881                     entry("CHANNEL_NUM=%d", chNum));
882                 // If user didn't want to configure specific channel (say
883                 // reserved channel), then load that index with default values.
884                 setDefaultChannelConfig(chNum, defaultChannelName);
885                 continue;
886             }
887             Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
888             if (jsonChInfo.is_null())
889             {
890                 log<level::ERR>("Invalid/corrupted channel config file");
891                 return -EBADMSG;
892             }
893 
894             ChannelProperties& chData = channelData[chNum];
895             chData.chName = jsonChData[nameString].get<std::string>();
896             chData.chID = chNum;
897             chData.isChValid = jsonChData[isValidString].get<bool>();
898             chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
899             chData.maxTransferSize =
900                 jsonChData.value(maxTransferSizeString, smallChannelSize);
901             std::string medTypeStr =
902                 jsonChInfo[mediumTypeString].get<std::string>();
903             chData.chInfo.mediumType =
904                 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
905             std::string protoTypeStr =
906                 jsonChInfo[protocolTypeString].get<std::string>();
907             chData.chInfo.protocolType =
908                 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
909             std::string sessStr =
910                 jsonChInfo[sessionSupportedString].get<std::string>();
911             chData.chInfo.sessionSupported =
912                 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
913             chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
914             chData.chInfo.authTypeSupported = defaultAuthType;
915         }
916         catch (const Json::exception& e)
917         {
918             log<level::DEBUG>("Json Exception caught.",
919                               entry("MSG=%s", e.what()));
920             return -EBADMSG;
921         }
922         catch (const std::invalid_argument& e)
923         {
924             log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
925             return -EBADMSG;
926         }
927     }
928 
929     return 0;
930 }
931 
932 int ChannelConfig::readChannelVolatileData()
933 {
934     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
935         channelLock{*channelMutex};
936 
937     Json data = readJsonFile(channelVolatileDataFilename);
938     if (data == nullptr)
939     {
940         log<level::DEBUG>("Error in opening IPMI Channel data file");
941         return -EIO;
942     }
943     try
944     {
945         // Fill in global structure
946         for (auto it = data.begin(); it != data.end(); ++it)
947         {
948             std::string chKey = it.key();
949             uint8_t chNum = std::stoi(chKey, nullptr, 10);
950             if ((chNum < 0) || (chNum > maxIpmiChannels))
951             {
952                 log<level::DEBUG>(
953                     "Invalid channel access entry in config file");
954                 throw std::out_of_range("Out of range - channel number");
955             }
956             Json jsonChData = it.value();
957             if (!jsonChData.is_null())
958             {
959                 std::string accModeStr =
960                     jsonChData[accessModeString].get<std::string>();
961                 channelData[chNum].chAccess.chVolatileData.accessMode =
962                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
963                 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
964                     jsonChData[userAuthDisabledString].get<bool>();
965                 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
966                     jsonChData[perMsgAuthDisabledString].get<bool>();
967                 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
968                     jsonChData[alertingDisabledString].get<bool>();
969                 std::string privStr =
970                     jsonChData[privLimitString].get<std::string>();
971                 channelData[chNum].chAccess.chVolatileData.privLimit =
972                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
973             }
974             else
975             {
976                 log<level::ERR>(
977                     "Invalid/corrupted volatile channel access file",
978                     entry("FILE=%s", channelVolatileDataFilename));
979                 throw std::runtime_error(
980                     "Corrupted volatile channel access file");
981             }
982         }
983     }
984     catch (const Json::exception& e)
985     {
986         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
987         throw std::runtime_error("Corrupted volatile channel access file");
988     }
989     catch (const std::invalid_argument& e)
990     {
991         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
992         throw std::runtime_error("Corrupted volatile channel access file");
993     }
994 
995     // Update the timestamp
996     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
997     return 0;
998 }
999 
1000 int ChannelConfig::readChannelPersistData()
1001 {
1002     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1003         channelLock{*channelMutex};
1004 
1005     Json data = readJsonFile(channelNvDataFilename);
1006     if (data == nullptr)
1007     {
1008         log<level::DEBUG>("Error in opening IPMI Channel data file");
1009         return -EIO;
1010     }
1011     try
1012     {
1013         // Fill in global structure
1014         for (auto it = data.begin(); it != data.end(); ++it)
1015         {
1016             std::string chKey = it.key();
1017             uint8_t chNum = std::stoi(chKey, nullptr, 10);
1018             if ((chNum < 0) || (chNum > maxIpmiChannels))
1019             {
1020                 log<level::DEBUG>(
1021                     "Invalid channel access entry in config file");
1022                 throw std::out_of_range("Out of range - channel number");
1023             }
1024             Json jsonChData = it.value();
1025             if (!jsonChData.is_null())
1026             {
1027                 std::string accModeStr =
1028                     jsonChData[accessModeString].get<std::string>();
1029                 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1030                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1031                 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1032                     jsonChData[userAuthDisabledString].get<bool>();
1033                 channelData[chNum]
1034                     .chAccess.chNonVolatileData.perMsgAuthDisabled =
1035                     jsonChData[perMsgAuthDisabledString].get<bool>();
1036                 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1037                     jsonChData[alertingDisabledString].get<bool>();
1038                 std::string privStr =
1039                     jsonChData[privLimitString].get<std::string>();
1040                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1041                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1042             }
1043             else
1044             {
1045                 log<level::ERR>("Invalid/corrupted nv channel access file",
1046                                 entry("FILE=%s", channelNvDataFilename));
1047                 throw std::runtime_error("Corrupted nv channel access file");
1048             }
1049         }
1050     }
1051     catch (const Json::exception& e)
1052     {
1053         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
1054         throw std::runtime_error("Corrupted nv channel access file");
1055     }
1056     catch (const std::invalid_argument& e)
1057     {
1058         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1059         throw std::runtime_error("Corrupted nv channel access file");
1060     }
1061 
1062     // Update the timestamp
1063     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1064     return 0;
1065 }
1066 
1067 int ChannelConfig::writeChannelVolatileData()
1068 {
1069     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1070         channelLock{*channelMutex};
1071     Json outData;
1072 
1073     try
1074     {
1075         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1076         {
1077             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1078             {
1079                 Json jsonObj;
1080                 std::string chKey = std::to_string(chNum);
1081                 std::string accModeStr = convertToAccessModeString(
1082                     channelData[chNum].chAccess.chVolatileData.accessMode);
1083                 jsonObj[accessModeString] = accModeStr;
1084                 jsonObj[userAuthDisabledString] =
1085                     channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1086                 jsonObj[perMsgAuthDisabledString] =
1087                     channelData[chNum]
1088                         .chAccess.chVolatileData.perMsgAuthDisabled;
1089                 jsonObj[alertingDisabledString] =
1090                     channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1091                 std::string privStr = convertToPrivLimitString(
1092                     channelData[chNum].chAccess.chVolatileData.privLimit);
1093                 jsonObj[privLimitString] = privStr;
1094 
1095                 outData[chKey] = jsonObj;
1096             }
1097         }
1098     }
1099     catch (const std::invalid_argument& e)
1100     {
1101         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1102         return -EINVAL;
1103     }
1104 
1105     if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1106     {
1107         log<level::DEBUG>("Error in write JSON data to file");
1108         return -EIO;
1109     }
1110 
1111     // Update the timestamp
1112     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1113     return 0;
1114 }
1115 
1116 int ChannelConfig::writeChannelPersistData()
1117 {
1118     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1119         channelLock{*channelMutex};
1120     Json outData;
1121 
1122     try
1123     {
1124         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1125         {
1126             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1127             {
1128                 Json jsonObj;
1129                 std::string chKey = std::to_string(chNum);
1130                 std::string accModeStr = convertToAccessModeString(
1131                     channelData[chNum].chAccess.chNonVolatileData.accessMode);
1132                 jsonObj[accessModeString] = accModeStr;
1133                 jsonObj[userAuthDisabledString] =
1134                     channelData[chNum]
1135                         .chAccess.chNonVolatileData.userAuthDisabled;
1136                 jsonObj[perMsgAuthDisabledString] =
1137                     channelData[chNum]
1138                         .chAccess.chNonVolatileData.perMsgAuthDisabled;
1139                 jsonObj[alertingDisabledString] =
1140                     channelData[chNum]
1141                         .chAccess.chNonVolatileData.alertingDisabled;
1142                 std::string privStr = convertToPrivLimitString(
1143                     channelData[chNum].chAccess.chNonVolatileData.privLimit);
1144                 jsonObj[privLimitString] = privStr;
1145 
1146                 outData[chKey] = jsonObj;
1147             }
1148         }
1149     }
1150     catch (const std::invalid_argument& e)
1151     {
1152         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1153         return -EINVAL;
1154     }
1155 
1156     if (writeJsonFile(channelNvDataFilename, outData) != 0)
1157     {
1158         log<level::DEBUG>("Error in write JSON data to file");
1159         return -EIO;
1160     }
1161 
1162     // Update the timestamp
1163     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1164     return 0;
1165 }
1166 
1167 int ChannelConfig::checkAndReloadNVData()
1168 {
1169     std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1170     int ret = 0;
1171     if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1172     {
1173         try
1174         {
1175             ret = readChannelPersistData();
1176         }
1177         catch (const std::exception& e)
1178         {
1179             log<level::ERR>("Exception caught in readChannelPersistData.",
1180                             entry("MSG=%s", e.what()));
1181             ret = -EIO;
1182         }
1183     }
1184     return ret;
1185 }
1186 
1187 int ChannelConfig::checkAndReloadVolatileData()
1188 {
1189     std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1190     int ret = 0;
1191     if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1192     {
1193         try
1194         {
1195             ret = readChannelVolatileData();
1196         }
1197         catch (const std::exception& e)
1198         {
1199             log<level::ERR>("Exception caught in readChannelVolatileData.",
1200                             entry("MSG=%s", e.what()));
1201             ret = -EIO;
1202         }
1203     }
1204     return ret;
1205 }
1206 
1207 int ChannelConfig::setDbusProperty(const std::string& service,
1208                                    const std::string& objPath,
1209                                    const std::string& interface,
1210                                    const std::string& property,
1211                                    const DbusVariant& value)
1212 {
1213     try
1214     {
1215         auto method =
1216             bus.new_method_call(service.c_str(), objPath.c_str(),
1217                                 "org.freedesktop.DBus.Properties", "Set");
1218 
1219         method.append(interface, property, value);
1220 
1221         auto reply = bus.call(method);
1222     }
1223     catch (const sdbusplus::exception::SdBusError& e)
1224     {
1225         log<level::DEBUG>("set-property failed",
1226                           entry("SERVICE=%s", service.c_str()),
1227                           entry("OBJPATH=%s", objPath.c_str()),
1228                           entry("INTERFACE=%s", interface.c_str()),
1229                           entry("PROP=%s", property.c_str()));
1230         return -EIO;
1231     }
1232 
1233     return 0;
1234 }
1235 
1236 int ChannelConfig::getDbusProperty(const std::string& service,
1237                                    const std::string& objPath,
1238                                    const std::string& interface,
1239                                    const std::string& property,
1240                                    DbusVariant& value)
1241 {
1242     try
1243     {
1244         auto method =
1245             bus.new_method_call(service.c_str(), objPath.c_str(),
1246                                 "org.freedesktop.DBus.Properties", "Get");
1247 
1248         method.append(interface, property);
1249 
1250         auto reply = bus.call(method);
1251         reply.read(value);
1252     }
1253     catch (const sdbusplus::exception::SdBusError& e)
1254     {
1255         log<level::DEBUG>("get-property failed",
1256                           entry("SERVICE=%s", service.c_str()),
1257                           entry("OBJPATH=%s", objPath.c_str()),
1258                           entry("INTERFACE=%s", interface.c_str()),
1259                           entry("PROP=%s", property.c_str()));
1260         return -EIO;
1261     }
1262     return 0;
1263 }
1264 
1265 int ChannelConfig::syncNetworkChannelConfig()
1266 {
1267     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1268         channelLock{*channelMutex};
1269     bool isUpdated = false;
1270     for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1271     {
1272         if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1273         {
1274             std::string intfPrivStr;
1275             try
1276             {
1277                 std::string networkIntfObj =
1278                     std::string(networkIntfObjectBasePath) + "/" +
1279                     channelData[chNum].chName;
1280                 DbusVariant variant;
1281                 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
1282                                          networkChConfigIntfName,
1283                                          privilegePropertyString, variant))
1284                 {
1285                     log<level::DEBUG>("Network interface does not exist",
1286                                       entry("INTERFACE=%s",
1287                                             channelData[chNum].chName.c_str()));
1288                     continue;
1289                 }
1290                 intfPrivStr = std::get<std::string>(variant);
1291             }
1292             catch (const std::bad_variant_access& e)
1293             {
1294                 log<level::DEBUG>(
1295                     "exception: Network interface does not exist");
1296                 continue;
1297             }
1298             catch (const sdbusplus::exception::SdBusError& e)
1299             {
1300                 log<level::DEBUG>(
1301                     "exception: Network interface does not exist");
1302                 continue;
1303             }
1304 
1305             uint8_t intfPriv =
1306                 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1307             if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1308                 intfPriv)
1309             {
1310                 isUpdated = true;
1311                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1312                     intfPriv;
1313                 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1314             }
1315         }
1316     }
1317 
1318     if (isUpdated)
1319     {
1320         // Write persistent data to file
1321         if (writeChannelPersistData() != 0)
1322         {
1323             log<level::DEBUG>("Failed to update the persistent data file");
1324             return -EIO;
1325         }
1326         // Write Volatile data to file
1327         if (writeChannelVolatileData() != 0)
1328         {
1329             log<level::DEBUG>("Failed to update the channel volatile data");
1330             return -EIO;
1331         }
1332     }
1333 
1334     return 0;
1335 }
1336 
1337 void ChannelConfig::initChannelPersistData()
1338 {
1339     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1340         channelLock{*channelMutex};
1341 
1342     /* Always read the channel config */
1343     if (loadChannelConfig() != 0)
1344     {
1345         log<level::ERR>("Failed to read channel config file");
1346         throw std::ios_base::failure("Failed to load channel configuration");
1347     }
1348 
1349     /* Populate the channel persist data */
1350     if (readChannelPersistData() != 0)
1351     {
1352         // Copy default NV data to RW location
1353         std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1354                                                  channelNvDataFilename);
1355 
1356         // Load the channel access NV data
1357         if (readChannelPersistData() != 0)
1358         {
1359             log<level::ERR>("Failed to read channel access NV data");
1360             throw std::ios_base::failure(
1361                 "Failed to read channel access NV configuration");
1362         }
1363     }
1364 
1365     // First check the volatile data file
1366     // If not present, load the default values
1367     if (readChannelVolatileData() != 0)
1368     {
1369         // Copy default volatile data to temporary location
1370         // NV file(channelNvDataFilename) must have created by now.
1371         std::experimental::filesystem::copy_file(channelNvDataFilename,
1372                                                  channelVolatileDataFilename);
1373 
1374         // Load the channel access volatile data
1375         if (readChannelVolatileData() != 0)
1376         {
1377             log<level::ERR>("Failed to read channel access volatile data");
1378             throw std::ios_base::failure(
1379                 "Failed to read channel access volatile configuration");
1380         }
1381     }
1382 
1383     // Synchronize the channel config(priv) with network channel
1384     // configuration(priv) over dbus
1385     if (syncNetworkChannelConfig() != 0)
1386     {
1387         log<level::ERR>(
1388             "Failed to synchronize data with network channel config over dbus");
1389         throw std::ios_base::failure(
1390             "Failed to synchronize data with network channel config over dbus");
1391     }
1392 
1393     log<level::DEBUG>("Successfully completed channel data initialization.");
1394     return;
1395 }
1396 
1397 } // namespace ipmi
1398