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 const 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     {
468         log<level::DEBUG>("Invalid access mode specified");
469         return ccAccessModeNotSupportedForChannel;
470     }
471     if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
472     {
473         log<level::DEBUG>("Invalid privilege limit specified");
474         return ccInvalidFieldRequest;
475     }
476 
477     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
478         channelLock{*channelMutex};
479 
480     if (checkAndReloadVolatileData() != 0)
481     {
482         return ccUnspecifiedError;
483     }
484 
485     if (setFlag & setAccessMode)
486     {
487         channelData[chNum].chAccess.chVolatileData.accessMode =
488             chAccessData.accessMode;
489     }
490     if (setFlag & setUserAuthEnabled)
491     {
492         channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
493             chAccessData.userAuthDisabled;
494     }
495     if (setFlag & setMsgAuthEnabled)
496     {
497         channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
498             chAccessData.perMsgAuthDisabled;
499     }
500     if (setFlag & setAlertingEnabled)
501     {
502         channelData[chNum].chAccess.chVolatileData.alertingDisabled =
503             chAccessData.alertingDisabled;
504     }
505     if (setFlag & setPrivLimit)
506     {
507         channelData[chNum].chAccess.chVolatileData.privLimit =
508             chAccessData.privLimit;
509     }
510 
511     // Write Volatile data to file
512     if (writeChannelVolatileData() != 0)
513     {
514         log<level::DEBUG>("Failed to update the channel volatile data");
515         return ccUnspecifiedError;
516     }
517     return ccSuccess;
518 }
519 
520 Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
521                                               ChannelAccess& chAccessData)
522 {
523     if (!isValidChannel(chNum))
524     {
525         log<level::DEBUG>("Invalid channel");
526         return ccInvalidFieldRequest;
527     }
528 
529     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
530     {
531         log<level::DEBUG>("Session-less channel doesn't have access data.");
532         return ccActionNotSupportedForChannel;
533     }
534 
535     if (checkAndReloadNVData() != 0)
536     {
537         return ccUnspecifiedError;
538     }
539 
540     std::copy_n(reinterpret_cast<uint8_t*>(
541                     &channelData[chNum].chAccess.chNonVolatileData),
542                 sizeof(channelData[chNum].chAccess.chNonVolatileData),
543                 reinterpret_cast<uint8_t*>(&chAccessData));
544 
545     return ccSuccess;
546 }
547 
548 Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum,
549                                               const ChannelAccess& chAccessData,
550                                               const uint8_t setFlag)
551 {
552     if (!isValidChannel(chNum))
553     {
554         log<level::DEBUG>("Invalid channel");
555         return ccInvalidFieldRequest;
556     }
557 
558     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
559     {
560         log<level::DEBUG>("Session-less channel doesn't have access data.");
561         return ccActionNotSupportedForChannel;
562     }
563 
564     if ((setFlag & setAccessMode) &&
565         (!isValidAccessMode(chAccessData.accessMode)))
566     {
567         log<level::DEBUG>("Invalid access mode specified");
568         return ccAccessModeNotSupportedForChannel;
569     }
570     if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
571     {
572         log<level::DEBUG>("Invalid privilege limit specified");
573         return ccInvalidFieldRequest;
574     }
575 
576     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
577         channelLock{*channelMutex};
578 
579     if (checkAndReloadNVData() != 0)
580     {
581         return ccUnspecifiedError;
582     }
583 
584     if (setFlag & setAccessMode)
585     {
586         channelData[chNum].chAccess.chNonVolatileData.accessMode =
587             chAccessData.accessMode;
588     }
589     if (setFlag & setUserAuthEnabled)
590     {
591         channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
592             chAccessData.userAuthDisabled;
593     }
594     if (setFlag & setMsgAuthEnabled)
595     {
596         channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
597             chAccessData.perMsgAuthDisabled;
598     }
599     if (setFlag & setAlertingEnabled)
600     {
601         channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
602             chAccessData.alertingDisabled;
603     }
604     if (setFlag & setPrivLimit)
605     {
606         // Send Update to network channel config interfaces over dbus
607         std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
608         std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
609                                      "/" + channelData[chNum].chName;
610         try
611         {
612             if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
613                                      networkChConfigIntfName,
614                                      privilegePropertyString, privStr))
615             {
616                 log<level::DEBUG>(
617                     "Network interface does not exist",
618                     entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
619                 return ccUnspecifiedError;
620             }
621         }
622         catch (const sdbusplus::exception::SdBusError& e)
623         {
624             log<level::ERR>("Exception: Network interface does not exist");
625             return ccInvalidFieldRequest;
626         }
627         signalFlag |= (1 << chNum);
628         channelData[chNum].chAccess.chNonVolatileData.privLimit =
629             chAccessData.privLimit;
630     }
631 
632     // Write persistent data to file
633     if (writeChannelPersistData() != 0)
634     {
635         log<level::DEBUG>("Failed to update the presist data file");
636         return ccUnspecifiedError;
637     }
638     return ccSuccess;
639 }
640 
641 Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
642                                               uint8_t& authTypeSupported)
643 {
644     if (!isValidChannel(chNum))
645     {
646         log<level::DEBUG>("Invalid channel");
647         return ccInvalidFieldRequest;
648     }
649 
650     authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
651     return ccSuccess;
652 }
653 
654 Cc ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
655                                             const uint8_t priv,
656                                             EAuthType& authType)
657 {
658     if (!isValidChannel(chNum))
659     {
660         log<level::DEBUG>("Invalid channel");
661         return ccInvalidFieldRequest;
662     }
663 
664     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
665     {
666         log<level::DEBUG>("Sessionless channel doesn't have access data.");
667         return ccInvalidFieldRequest;
668     }
669 
670     if (!isValidPrivLimit(priv))
671     {
672         log<level::DEBUG>("Invalid privilege specified.");
673         return ccInvalidFieldRequest;
674     }
675 
676     // TODO: Hardcoded for now. Need to implement.
677     authType = EAuthType::none;
678 
679     return ccSuccess;
680 }
681 
682 std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
683 {
684     struct stat fileStat;
685     if (stat(fileName.c_str(), &fileStat) != 0)
686     {
687         log<level::DEBUG>("Error in getting last updated time stamp");
688         return -EIO;
689     }
690     return fileStat.st_mtime;
691 }
692 
693 EChannelAccessMode
694     ChannelConfig::convertToAccessModeIndex(const std::string& mode)
695 {
696     auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
697     if (iter == accessModeList.end())
698     {
699         log<level::ERR>("Invalid access mode.",
700                         entry("MODE_STR=%s", mode.c_str()));
701         throw std::invalid_argument("Invalid access mode.");
702     }
703 
704     return static_cast<EChannelAccessMode>(
705         std::distance(accessModeList.begin(), iter));
706 }
707 
708 std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
709 {
710     if (accessModeList.size() <= value)
711     {
712         log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
713         throw std::invalid_argument("Invalid access mode.");
714     }
715 
716     return accessModeList.at(value);
717 }
718 
719 CommandPrivilege
720     ChannelConfig::convertToPrivLimitIndex(const std::string& value)
721 {
722     auto iter = std::find(privList.begin(), privList.end(), value);
723     if (iter == privList.end())
724     {
725         log<level::ERR>("Invalid privilege.",
726                         entry("PRIV_STR=%s", value.c_str()));
727         throw std::invalid_argument("Invalid privilege.");
728     }
729 
730     return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
731 }
732 
733 std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
734 {
735     if (privList.size() <= value)
736     {
737         log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
738         throw std::invalid_argument("Invalid privilege.");
739     }
740 
741     return privList.at(value);
742 }
743 
744 EChannelSessSupported
745     ChannelConfig::convertToSessionSupportIndex(const std::string& value)
746 {
747     auto iter =
748         std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
749     if (iter == sessionSupportList.end())
750     {
751         log<level::ERR>("Invalid session supported.",
752                         entry("SESS_STR=%s", value.c_str()));
753         throw std::invalid_argument("Invalid session supported.");
754     }
755 
756     return static_cast<EChannelSessSupported>(
757         std::distance(sessionSupportList.begin(), iter));
758 }
759 
760 EChannelMediumType
761     ChannelConfig::convertToMediumTypeIndex(const std::string& value)
762 {
763     std::unordered_map<std::string, EChannelMediumType>::iterator it =
764         mediumTypeMap.find(value);
765     if (it == mediumTypeMap.end())
766     {
767         log<level::ERR>("Invalid medium type.",
768                         entry("MEDIUM_STR=%s", value.c_str()));
769         throw std::invalid_argument("Invalid medium type.");
770     }
771 
772     return static_cast<EChannelMediumType>(it->second);
773 }
774 
775 EChannelProtocolType
776     ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
777 {
778     std::unordered_map<std::string, EChannelProtocolType>::iterator it =
779         protocolTypeMap.find(value);
780     if (it == protocolTypeMap.end())
781     {
782         log<level::ERR>("Invalid protocol type.",
783                         entry("PROTO_STR=%s", value.c_str()));
784         throw std::invalid_argument("Invalid protocol type.");
785     }
786 
787     return static_cast<EChannelProtocolType>(it->second);
788 }
789 
790 Json ChannelConfig::readJsonFile(const std::string& configFile)
791 {
792     std::ifstream jsonFile(configFile);
793     if (!jsonFile.good())
794     {
795         log<level::INFO>("JSON file not found",
796                          entry("FILE_NAME=%s", configFile.c_str()));
797         return nullptr;
798     }
799 
800     Json data = nullptr;
801     try
802     {
803         data = Json::parse(jsonFile, nullptr, false);
804     }
805     catch (Json::parse_error& e)
806     {
807         log<level::DEBUG>("Corrupted channel config.",
808                           entry("MSG=%s", e.what()));
809         throw std::runtime_error("Corrupted channel config file");
810     }
811 
812     return data;
813 }
814 
815 int ChannelConfig::writeJsonFile(const std::string& configFile,
816                                  const Json& jsonData)
817 {
818     const std::string tmpFile = configFile + "_tmp";
819     int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
820                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
821     if (fd < 0)
822     {
823         log<level::ERR>("Error in creating json file",
824                         entry("FILE_NAME = %s", tmpFile.c_str()));
825         return -EIO;
826     }
827     const auto& writeData = jsonData.dump();
828     if (write(fd, writeData.c_str(), writeData.size()) !=
829         static_cast<ssize_t>(writeData.size()))
830     {
831         close(fd);
832         log<level::ERR>("Error in writing configuration file",
833                         entry("FILE_NAME = %s", tmpFile.c_str()));
834         return -EIO;
835     }
836     close(fd);
837 
838     if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
839     {
840         log<level::ERR>("Error in renaming temporary data file",
841                         entry("FILE_NAME = %s", tmpFile.c_str()));
842         return -EIO;
843     }
844 
845     return 0;
846 }
847 
848 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
849                                             const std::string& chName)
850 {
851     channelData[chNum].chName = chName;
852     channelData[chNum].chID = chNum;
853     channelData[chNum].isChValid = false;
854     channelData[chNum].activeSessCount = 0;
855 
856     channelData[chNum].chInfo.mediumType = defaultMediumType;
857     channelData[chNum].chInfo.protocolType = defaultProtocolType;
858     channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
859     channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
860     channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
861 }
862 
863 int ChannelConfig::loadChannelConfig()
864 {
865     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
866         channelLock{*channelMutex};
867 
868     Json data = readJsonFile(channelConfigDefaultFilename);
869     if (data.empty())
870     {
871         log<level::DEBUG>("Error in opening IPMI Channel data file");
872         return -EIO;
873     }
874 
875     channelData.fill(ChannelProperties{});
876 
877     for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
878     {
879         try
880         {
881             std::string chKey = std::to_string(chNum);
882             Json jsonChData = data[chKey].get<Json>();
883             if (jsonChData.is_null())
884             {
885                 log<level::WARNING>(
886                     "Channel not configured so loading default.",
887                     entry("CHANNEL_NUM=%d", chNum));
888                 // If user didn't want to configure specific channel (say
889                 // reserved channel), then load that index with default values.
890                 setDefaultChannelConfig(chNum, defaultChannelName);
891                 continue;
892             }
893             Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
894             if (jsonChInfo.is_null())
895             {
896                 log<level::ERR>("Invalid/corrupted channel config file");
897                 return -EBADMSG;
898             }
899 
900             ChannelProperties& chData = channelData[chNum];
901             chData.chName = jsonChData[nameString].get<std::string>();
902             chData.chID = chNum;
903             chData.isChValid = jsonChData[isValidString].get<bool>();
904             chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
905             chData.maxTransferSize =
906                 jsonChData.value(maxTransferSizeString, smallChannelSize);
907             std::string medTypeStr =
908                 jsonChInfo[mediumTypeString].get<std::string>();
909             chData.chInfo.mediumType =
910                 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
911             std::string protoTypeStr =
912                 jsonChInfo[protocolTypeString].get<std::string>();
913             chData.chInfo.protocolType =
914                 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
915             std::string sessStr =
916                 jsonChInfo[sessionSupportedString].get<std::string>();
917             chData.chInfo.sessionSupported =
918                 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
919             chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
920             chData.chInfo.authTypeSupported = defaultAuthType;
921         }
922         catch (const Json::exception& e)
923         {
924             log<level::DEBUG>("Json Exception caught.",
925                               entry("MSG=%s", e.what()));
926             return -EBADMSG;
927         }
928         catch (const std::invalid_argument& e)
929         {
930             log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
931             return -EBADMSG;
932         }
933     }
934 
935     return 0;
936 }
937 
938 int ChannelConfig::readChannelVolatileData()
939 {
940     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
941         channelLock{*channelMutex};
942 
943     Json data = readJsonFile(channelVolatileDataFilename);
944     if (data == nullptr)
945     {
946         log<level::DEBUG>("Error in opening IPMI Channel data file");
947         return -EIO;
948     }
949     try
950     {
951         // Fill in global structure
952         for (auto it = data.begin(); it != data.end(); ++it)
953         {
954             std::string chKey = it.key();
955             uint8_t chNum = std::stoi(chKey, nullptr, 10);
956             if ((chNum < 0) || (chNum > maxIpmiChannels))
957             {
958                 log<level::DEBUG>(
959                     "Invalid channel access entry in config file");
960                 throw std::out_of_range("Out of range - channel number");
961             }
962             Json jsonChData = it.value();
963             if (!jsonChData.is_null())
964             {
965                 std::string accModeStr =
966                     jsonChData[accessModeString].get<std::string>();
967                 channelData[chNum].chAccess.chVolatileData.accessMode =
968                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
969                 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
970                     jsonChData[userAuthDisabledString].get<bool>();
971                 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
972                     jsonChData[perMsgAuthDisabledString].get<bool>();
973                 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
974                     jsonChData[alertingDisabledString].get<bool>();
975                 std::string privStr =
976                     jsonChData[privLimitString].get<std::string>();
977                 channelData[chNum].chAccess.chVolatileData.privLimit =
978                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
979             }
980             else
981             {
982                 log<level::ERR>(
983                     "Invalid/corrupted volatile channel access file",
984                     entry("FILE=%s", channelVolatileDataFilename));
985                 throw std::runtime_error(
986                     "Corrupted volatile channel access file");
987             }
988         }
989     }
990     catch (const Json::exception& e)
991     {
992         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
993         throw std::runtime_error("Corrupted volatile channel access file");
994     }
995     catch (const std::invalid_argument& e)
996     {
997         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
998         throw std::runtime_error("Corrupted volatile channel access file");
999     }
1000 
1001     // Update the timestamp
1002     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1003     return 0;
1004 }
1005 
1006 int ChannelConfig::readChannelPersistData()
1007 {
1008     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1009         channelLock{*channelMutex};
1010 
1011     Json data = readJsonFile(channelNvDataFilename);
1012     if (data == nullptr)
1013     {
1014         log<level::DEBUG>("Error in opening IPMI Channel data file");
1015         return -EIO;
1016     }
1017     try
1018     {
1019         // Fill in global structure
1020         for (auto it = data.begin(); it != data.end(); ++it)
1021         {
1022             std::string chKey = it.key();
1023             uint8_t chNum = std::stoi(chKey, nullptr, 10);
1024             if ((chNum < 0) || (chNum > maxIpmiChannels))
1025             {
1026                 log<level::DEBUG>(
1027                     "Invalid channel access entry in config file");
1028                 throw std::out_of_range("Out of range - channel number");
1029             }
1030             Json jsonChData = it.value();
1031             if (!jsonChData.is_null())
1032             {
1033                 std::string accModeStr =
1034                     jsonChData[accessModeString].get<std::string>();
1035                 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1036                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1037                 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1038                     jsonChData[userAuthDisabledString].get<bool>();
1039                 channelData[chNum]
1040                     .chAccess.chNonVolatileData.perMsgAuthDisabled =
1041                     jsonChData[perMsgAuthDisabledString].get<bool>();
1042                 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1043                     jsonChData[alertingDisabledString].get<bool>();
1044                 std::string privStr =
1045                     jsonChData[privLimitString].get<std::string>();
1046                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1047                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1048             }
1049             else
1050             {
1051                 log<level::ERR>("Invalid/corrupted nv channel access file",
1052                                 entry("FILE=%s", channelNvDataFilename));
1053                 throw std::runtime_error("Corrupted nv channel access file");
1054             }
1055         }
1056     }
1057     catch (const Json::exception& e)
1058     {
1059         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
1060         throw std::runtime_error("Corrupted nv channel access file");
1061     }
1062     catch (const std::invalid_argument& e)
1063     {
1064         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1065         throw std::runtime_error("Corrupted nv channel access file");
1066     }
1067 
1068     // Update the timestamp
1069     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1070     return 0;
1071 }
1072 
1073 int ChannelConfig::writeChannelVolatileData()
1074 {
1075     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1076         channelLock{*channelMutex};
1077     Json outData;
1078 
1079     try
1080     {
1081         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1082         {
1083             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1084             {
1085                 Json jsonObj;
1086                 std::string chKey = std::to_string(chNum);
1087                 std::string accModeStr = convertToAccessModeString(
1088                     channelData[chNum].chAccess.chVolatileData.accessMode);
1089                 jsonObj[accessModeString] = accModeStr;
1090                 jsonObj[userAuthDisabledString] =
1091                     channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1092                 jsonObj[perMsgAuthDisabledString] =
1093                     channelData[chNum]
1094                         .chAccess.chVolatileData.perMsgAuthDisabled;
1095                 jsonObj[alertingDisabledString] =
1096                     channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1097                 std::string privStr = convertToPrivLimitString(
1098                     channelData[chNum].chAccess.chVolatileData.privLimit);
1099                 jsonObj[privLimitString] = privStr;
1100 
1101                 outData[chKey] = jsonObj;
1102             }
1103         }
1104     }
1105     catch (const std::invalid_argument& e)
1106     {
1107         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1108         return -EINVAL;
1109     }
1110 
1111     if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1112     {
1113         log<level::DEBUG>("Error in write JSON data to file");
1114         return -EIO;
1115     }
1116 
1117     // Update the timestamp
1118     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1119     return 0;
1120 }
1121 
1122 int ChannelConfig::writeChannelPersistData()
1123 {
1124     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1125         channelLock{*channelMutex};
1126     Json outData;
1127 
1128     try
1129     {
1130         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1131         {
1132             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1133             {
1134                 Json jsonObj;
1135                 std::string chKey = std::to_string(chNum);
1136                 std::string accModeStr = convertToAccessModeString(
1137                     channelData[chNum].chAccess.chNonVolatileData.accessMode);
1138                 jsonObj[accessModeString] = accModeStr;
1139                 jsonObj[userAuthDisabledString] =
1140                     channelData[chNum]
1141                         .chAccess.chNonVolatileData.userAuthDisabled;
1142                 jsonObj[perMsgAuthDisabledString] =
1143                     channelData[chNum]
1144                         .chAccess.chNonVolatileData.perMsgAuthDisabled;
1145                 jsonObj[alertingDisabledString] =
1146                     channelData[chNum]
1147                         .chAccess.chNonVolatileData.alertingDisabled;
1148                 std::string privStr = convertToPrivLimitString(
1149                     channelData[chNum].chAccess.chNonVolatileData.privLimit);
1150                 jsonObj[privLimitString] = privStr;
1151 
1152                 outData[chKey] = jsonObj;
1153             }
1154         }
1155     }
1156     catch (const std::invalid_argument& e)
1157     {
1158         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1159         return -EINVAL;
1160     }
1161 
1162     if (writeJsonFile(channelNvDataFilename, outData) != 0)
1163     {
1164         log<level::DEBUG>("Error in write JSON data to file");
1165         return -EIO;
1166     }
1167 
1168     // Update the timestamp
1169     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1170     return 0;
1171 }
1172 
1173 int ChannelConfig::checkAndReloadNVData()
1174 {
1175     std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1176     int ret = 0;
1177     if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1178     {
1179         try
1180         {
1181             ret = readChannelPersistData();
1182         }
1183         catch (const std::exception& e)
1184         {
1185             log<level::ERR>("Exception caught in readChannelPersistData.",
1186                             entry("MSG=%s", e.what()));
1187             ret = -EIO;
1188         }
1189     }
1190     return ret;
1191 }
1192 
1193 int ChannelConfig::checkAndReloadVolatileData()
1194 {
1195     std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1196     int ret = 0;
1197     if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1198     {
1199         try
1200         {
1201             ret = readChannelVolatileData();
1202         }
1203         catch (const std::exception& e)
1204         {
1205             log<level::ERR>("Exception caught in readChannelVolatileData.",
1206                             entry("MSG=%s", e.what()));
1207             ret = -EIO;
1208         }
1209     }
1210     return ret;
1211 }
1212 
1213 int ChannelConfig::setDbusProperty(const std::string& service,
1214                                    const std::string& objPath,
1215                                    const std::string& interface,
1216                                    const std::string& property,
1217                                    const DbusVariant& value)
1218 {
1219     try
1220     {
1221         auto method =
1222             bus.new_method_call(service.c_str(), objPath.c_str(),
1223                                 "org.freedesktop.DBus.Properties", "Set");
1224 
1225         method.append(interface, property, value);
1226 
1227         auto reply = bus.call(method);
1228     }
1229     catch (const sdbusplus::exception::SdBusError& e)
1230     {
1231         log<level::DEBUG>("set-property failed",
1232                           entry("SERVICE=%s", service.c_str()),
1233                           entry("OBJPATH=%s", objPath.c_str()),
1234                           entry("INTERFACE=%s", interface.c_str()),
1235                           entry("PROP=%s", property.c_str()));
1236         return -EIO;
1237     }
1238 
1239     return 0;
1240 }
1241 
1242 int ChannelConfig::getDbusProperty(const std::string& service,
1243                                    const std::string& objPath,
1244                                    const std::string& interface,
1245                                    const std::string& property,
1246                                    DbusVariant& value)
1247 {
1248     try
1249     {
1250         auto method =
1251             bus.new_method_call(service.c_str(), objPath.c_str(),
1252                                 "org.freedesktop.DBus.Properties", "Get");
1253 
1254         method.append(interface, property);
1255 
1256         auto reply = bus.call(method);
1257         reply.read(value);
1258     }
1259     catch (const sdbusplus::exception::SdBusError& e)
1260     {
1261         log<level::DEBUG>("get-property failed",
1262                           entry("SERVICE=%s", service.c_str()),
1263                           entry("OBJPATH=%s", objPath.c_str()),
1264                           entry("INTERFACE=%s", interface.c_str()),
1265                           entry("PROP=%s", property.c_str()));
1266         return -EIO;
1267     }
1268     return 0;
1269 }
1270 
1271 int ChannelConfig::syncNetworkChannelConfig()
1272 {
1273     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1274         channelLock{*channelMutex};
1275     bool isUpdated = false;
1276     for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1277     {
1278         if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1279         {
1280             std::string intfPrivStr;
1281             try
1282             {
1283                 std::string networkIntfObj =
1284                     std::string(networkIntfObjectBasePath) + "/" +
1285                     channelData[chNum].chName;
1286                 DbusVariant variant;
1287                 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
1288                                          networkChConfigIntfName,
1289                                          privilegePropertyString, variant))
1290                 {
1291                     log<level::DEBUG>("Network interface does not exist",
1292                                       entry("INTERFACE=%s",
1293                                             channelData[chNum].chName.c_str()));
1294                     continue;
1295                 }
1296                 intfPrivStr = std::get<std::string>(variant);
1297             }
1298             catch (const std::bad_variant_access& e)
1299             {
1300                 log<level::DEBUG>(
1301                     "exception: Network interface does not exist");
1302                 continue;
1303             }
1304             catch (const sdbusplus::exception::SdBusError& e)
1305             {
1306                 log<level::DEBUG>(
1307                     "exception: Network interface does not exist");
1308                 continue;
1309             }
1310 
1311             uint8_t intfPriv =
1312                 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1313             if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1314                 intfPriv)
1315             {
1316                 isUpdated = true;
1317                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1318                     intfPriv;
1319                 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1320             }
1321         }
1322     }
1323 
1324     if (isUpdated)
1325     {
1326         // Write persistent data to file
1327         if (writeChannelPersistData() != 0)
1328         {
1329             log<level::DEBUG>("Failed to update the persistent data file");
1330             return -EIO;
1331         }
1332         // Write Volatile data to file
1333         if (writeChannelVolatileData() != 0)
1334         {
1335             log<level::DEBUG>("Failed to update the channel volatile data");
1336             return -EIO;
1337         }
1338     }
1339 
1340     return 0;
1341 }
1342 
1343 void ChannelConfig::initChannelPersistData()
1344 {
1345     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1346         channelLock{*channelMutex};
1347 
1348     /* Always read the channel config */
1349     if (loadChannelConfig() != 0)
1350     {
1351         log<level::ERR>("Failed to read channel config file");
1352         throw std::ios_base::failure("Failed to load channel configuration");
1353     }
1354 
1355     /* Populate the channel persist data */
1356     if (readChannelPersistData() != 0)
1357     {
1358         // Copy default NV data to RW location
1359         std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1360                                                  channelNvDataFilename);
1361 
1362         // Load the channel access NV data
1363         if (readChannelPersistData() != 0)
1364         {
1365             log<level::ERR>("Failed to read channel access NV data");
1366             throw std::ios_base::failure(
1367                 "Failed to read channel access NV configuration");
1368         }
1369     }
1370 
1371     // First check the volatile data file
1372     // If not present, load the default values
1373     if (readChannelVolatileData() != 0)
1374     {
1375         // Copy default volatile data to temporary location
1376         // NV file(channelNvDataFilename) must have created by now.
1377         std::experimental::filesystem::copy_file(channelNvDataFilename,
1378                                                  channelVolatileDataFilename);
1379 
1380         // Load the channel access volatile data
1381         if (readChannelVolatileData() != 0)
1382         {
1383             log<level::ERR>("Failed to read channel access volatile data");
1384             throw std::ios_base::failure(
1385                 "Failed to read channel access volatile configuration");
1386         }
1387     }
1388 
1389     // Synchronize the channel config(priv) with network channel
1390     // configuration(priv) over dbus
1391     if (syncNetworkChannelConfig() != 0)
1392     {
1393         log<level::ERR>(
1394             "Failed to synchronize data with network channel config over dbus");
1395         throw std::ios_base::failure(
1396             "Failed to synchronize data with network channel config over dbus");
1397     }
1398 
1399     log<level::DEBUG>("Successfully completed channel data initialization.");
1400     return;
1401 }
1402 
1403 } // namespace ipmi
1404