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