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 uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
790 {
791 
792     // TODO: There is limitation in current design. we cannot detect exact
793     // LAN interface(eth0 or eth1) so Implementation may be updated
794     // when there is any design update to figure out all the interfaces
795     // independently based on the message.
796 
797     static uint8_t curChannel = 0xFF;
798 
799     if (curChannel == 0xFF)
800     {
801         auto it = interfaceMap.find(getInterfaceIndex());
802         if (it == interfaceMap.end())
803         {
804             log<level::ERR>("Invalid Interface type ",
805                             entry("InterfaceIndex: %d", getInterfaceIndex()));
806             throw std::invalid_argument("Invalid interface type.");
807         }
808 
809         for (auto& channel : channelData)
810         {
811             std::string& interfaceName = it->second;
812             if (channel.chName == interfaceName)
813             {
814                 curChannel = channel.chID;
815                 break;
816             }
817         }
818     }
819     return ((chNum == currentChNum) ? curChannel : chNum);
820 }
821 
822 Json ChannelConfig::readJsonFile(const std::string& configFile)
823 {
824     std::ifstream jsonFile(configFile);
825     if (!jsonFile.good())
826     {
827         log<level::ERR>("JSON file not found");
828         return nullptr;
829     }
830 
831     Json data = nullptr;
832     try
833     {
834         data = Json::parse(jsonFile, nullptr, false);
835     }
836     catch (Json::parse_error& e)
837     {
838         log<level::DEBUG>("Corrupted channel config.",
839                           entry("MSG: %s", e.what()));
840         throw std::runtime_error("Corrupted channel config file");
841     }
842 
843     return data;
844 }
845 
846 int ChannelConfig::writeJsonFile(const std::string& configFile,
847                                  const Json& jsonData)
848 {
849     std::ofstream jsonFile(configFile);
850     if (!jsonFile.good())
851     {
852         log<level::ERR>("JSON file not found");
853         return -EIO;
854     }
855 
856     // Write JSON to file
857     jsonFile << jsonData;
858 
859     jsonFile.flush();
860     return 0;
861 }
862 
863 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
864                                             const std::string& chName)
865 {
866     channelData[chNum].chName = chName;
867     channelData[chNum].chID = chNum;
868     channelData[chNum].isChValid = false;
869     channelData[chNum].activeSessCount = 0;
870 
871     channelData[chNum].chInfo.mediumType = defaultMediumType;
872     channelData[chNum].chInfo.protocolType = defaultProtocolType;
873     channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
874     channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
875     channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
876 }
877 
878 int ChannelConfig::loadChannelConfig()
879 {
880     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
881         channelLock{*channelMutex};
882 
883     Json data = readJsonFile(channelConfigDefaultFilename);
884     if (data.empty())
885     {
886         log<level::DEBUG>("Error in opening IPMI Channel data file");
887         return -EIO;
888     }
889 
890     channelData.fill(ChannelProperties{});
891 
892     for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
893     {
894         try
895         {
896             std::string chKey = std::to_string(chNum);
897             Json jsonChData = data[chKey].get<Json>();
898             if (jsonChData.is_null())
899             {
900                 log<level::WARNING>(
901                     "Channel not configured so loading default.",
902                     entry("CHANNEL_NUM:%d", chNum));
903                 // If user didn't want to configure specific channel (say
904                 // reserved channel), then load that index with default values.
905                 setDefaultChannelConfig(chNum, defaultChannelName);
906                 continue;
907             }
908             Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
909             if (jsonChInfo.is_null())
910             {
911                 log<level::ERR>("Invalid/corrupted channel config file");
912                 return -EBADMSG;
913             }
914 
915             ChannelProperties& chData = channelData[chNum];
916             chData.chName = jsonChData[nameString].get<std::string>();
917             chData.chID = chNum;
918             chData.isChValid = jsonChData[isValidString].get<bool>();
919             chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
920             chData.maxTransferSize =
921                 jsonChData.value(maxTransferSizeString, smallChannelSize);
922             std::string medTypeStr =
923                 jsonChInfo[mediumTypeString].get<std::string>();
924             chData.chInfo.mediumType =
925                 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
926             std::string protoTypeStr =
927                 jsonChInfo[protocolTypeString].get<std::string>();
928             chData.chInfo.protocolType =
929                 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
930             std::string sessStr =
931                 jsonChInfo[sessionSupportedString].get<std::string>();
932             chData.chInfo.sessionSupported =
933                 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
934             chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
935             chData.chInfo.authTypeSupported = defaultAuthType;
936         }
937         catch (const Json::exception& e)
938         {
939             log<level::DEBUG>("Json Exception caught.",
940                               entry("MSG:%s", e.what()));
941             return -EBADMSG;
942         }
943         catch (const std::invalid_argument& e)
944         {
945             log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
946             return -EBADMSG;
947         }
948     }
949 
950     return 0;
951 }
952 
953 int ChannelConfig::readChannelVolatileData()
954 {
955     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
956         channelLock{*channelMutex};
957 
958     Json data = readJsonFile(channelVolatileDataFilename);
959     if (data == nullptr)
960     {
961         log<level::DEBUG>("Error in opening IPMI Channel data file");
962         return -EIO;
963     }
964     try
965     {
966         // Fill in global structure
967         for (auto it = data.begin(); it != data.end(); ++it)
968         {
969             std::string chKey = it.key();
970             uint8_t chNum = std::stoi(chKey, nullptr, 10);
971             if ((chNum < 0) || (chNum > maxIpmiChannels))
972             {
973                 log<level::DEBUG>(
974                     "Invalid channel access entry in config file");
975                 throw std::out_of_range("Out of range - channel number");
976             }
977             Json jsonChData = it.value();
978             if (!jsonChData.is_null())
979             {
980                 std::string accModeStr =
981                     jsonChData[accessModeString].get<std::string>();
982                 channelData[chNum].chAccess.chVolatileData.accessMode =
983                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
984                 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
985                     jsonChData[userAuthDisabledString].get<bool>();
986                 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
987                     jsonChData[perMsgAuthDisabledString].get<bool>();
988                 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
989                     jsonChData[alertingDisabledString].get<bool>();
990                 std::string privStr =
991                     jsonChData[privLimitString].get<std::string>();
992                 channelData[chNum].chAccess.chVolatileData.privLimit =
993                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
994             }
995             else
996             {
997                 log<level::ERR>(
998                     "Invalid/corrupted volatile channel access file",
999                     entry("FILE: %s", channelVolatileDataFilename));
1000                 throw std::runtime_error(
1001                     "Corrupted volatile channel access file");
1002             }
1003         }
1004     }
1005     catch (const Json::exception& e)
1006     {
1007         log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1008         throw std::runtime_error("Corrupted volatile channel access file");
1009     }
1010     catch (const std::invalid_argument& e)
1011     {
1012         log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
1013         throw std::runtime_error("Corrupted volatile channel access file");
1014     }
1015 
1016     // Update the timestamp
1017     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1018     return 0;
1019 }
1020 
1021 int ChannelConfig::readChannelPersistData()
1022 {
1023     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1024         channelLock{*channelMutex};
1025 
1026     Json data = readJsonFile(channelNvDataFilename);
1027     if (data == nullptr)
1028     {
1029         log<level::DEBUG>("Error in opening IPMI Channel data file");
1030         return -EIO;
1031     }
1032     try
1033     {
1034         // Fill in global structure
1035         for (auto it = data.begin(); it != data.end(); ++it)
1036         {
1037             std::string chKey = it.key();
1038             uint8_t chNum = std::stoi(chKey, nullptr, 10);
1039             if ((chNum < 0) || (chNum > maxIpmiChannels))
1040             {
1041                 log<level::DEBUG>(
1042                     "Invalid channel access entry in config file");
1043                 throw std::out_of_range("Out of range - channel number");
1044             }
1045             Json jsonChData = it.value();
1046             if (!jsonChData.is_null())
1047             {
1048                 std::string accModeStr =
1049                     jsonChData[accessModeString].get<std::string>();
1050                 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1051                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1052                 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1053                     jsonChData[userAuthDisabledString].get<bool>();
1054                 channelData[chNum]
1055                     .chAccess.chNonVolatileData.perMsgAuthDisabled =
1056                     jsonChData[perMsgAuthDisabledString].get<bool>();
1057                 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1058                     jsonChData[alertingDisabledString].get<bool>();
1059                 std::string privStr =
1060                     jsonChData[privLimitString].get<std::string>();
1061                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1062                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1063             }
1064             else
1065             {
1066                 log<level::ERR>("Invalid/corrupted nv channel access file",
1067                                 entry("FILE:%s", channelNvDataFilename));
1068                 throw std::runtime_error("Corrupted nv channel access file");
1069             }
1070         }
1071     }
1072     catch (const Json::exception& e)
1073     {
1074         log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1075         throw std::runtime_error("Corrupted nv channel access file");
1076     }
1077     catch (const std::invalid_argument& e)
1078     {
1079         log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1080         throw std::runtime_error("Corrupted nv channel access file");
1081     }
1082 
1083     // Update the timestamp
1084     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1085     return 0;
1086 }
1087 
1088 int ChannelConfig::writeChannelVolatileData()
1089 {
1090     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1091         channelLock{*channelMutex};
1092     Json outData;
1093 
1094     try
1095     {
1096         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1097         {
1098             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1099             {
1100                 Json jsonObj;
1101                 std::string chKey = std::to_string(chNum);
1102                 std::string accModeStr = convertToAccessModeString(
1103                     channelData[chNum].chAccess.chVolatileData.accessMode);
1104                 jsonObj[accessModeString] = accModeStr;
1105                 jsonObj[userAuthDisabledString] =
1106                     channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1107                 jsonObj[perMsgAuthDisabledString] =
1108                     channelData[chNum]
1109                         .chAccess.chVolatileData.perMsgAuthDisabled;
1110                 jsonObj[alertingDisabledString] =
1111                     channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1112                 std::string privStr = convertToPrivLimitString(
1113                     channelData[chNum].chAccess.chVolatileData.privLimit);
1114                 jsonObj[privLimitString] = privStr;
1115 
1116                 outData[chKey] = jsonObj;
1117             }
1118         }
1119     }
1120     catch (const std::invalid_argument& e)
1121     {
1122         log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1123         return -EINVAL;
1124     }
1125 
1126     if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1127     {
1128         log<level::DEBUG>("Error in write JSON data to file");
1129         return -EIO;
1130     }
1131 
1132     // Update the timestamp
1133     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1134     return 0;
1135 }
1136 
1137 int ChannelConfig::writeChannelPersistData()
1138 {
1139     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1140         channelLock{*channelMutex};
1141     Json outData;
1142 
1143     try
1144     {
1145         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1146         {
1147             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1148             {
1149                 Json jsonObj;
1150                 std::string chKey = std::to_string(chNum);
1151                 std::string accModeStr = convertToAccessModeString(
1152                     channelData[chNum].chAccess.chNonVolatileData.accessMode);
1153                 jsonObj[accessModeString] = accModeStr;
1154                 jsonObj[userAuthDisabledString] =
1155                     channelData[chNum]
1156                         .chAccess.chNonVolatileData.userAuthDisabled;
1157                 jsonObj[perMsgAuthDisabledString] =
1158                     channelData[chNum]
1159                         .chAccess.chNonVolatileData.perMsgAuthDisabled;
1160                 jsonObj[alertingDisabledString] =
1161                     channelData[chNum]
1162                         .chAccess.chNonVolatileData.alertingDisabled;
1163                 std::string privStr = convertToPrivLimitString(
1164                     channelData[chNum].chAccess.chNonVolatileData.privLimit);
1165                 jsonObj[privLimitString] = privStr;
1166 
1167                 outData[chKey] = jsonObj;
1168             }
1169         }
1170     }
1171     catch (const std::invalid_argument& e)
1172     {
1173         log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1174         return -EINVAL;
1175     }
1176 
1177     if (writeJsonFile(channelNvDataFilename, outData) != 0)
1178     {
1179         log<level::DEBUG>("Error in write JSON data to file");
1180         return -EIO;
1181     }
1182 
1183     // Update the timestamp
1184     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1185     return 0;
1186 }
1187 
1188 int ChannelConfig::checkAndReloadNVData()
1189 {
1190     std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1191     int ret = 0;
1192     if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1193     {
1194         try
1195         {
1196             ret = readChannelPersistData();
1197         }
1198         catch (const std::exception& e)
1199         {
1200             log<level::ERR>("Exception caught in readChannelPersistData.",
1201                             entry("MSG=%s", e.what()));
1202             ret = -EIO;
1203         }
1204     }
1205     return ret;
1206 }
1207 
1208 int ChannelConfig::checkAndReloadVolatileData()
1209 {
1210     std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1211     int ret = 0;
1212     if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1213     {
1214         try
1215         {
1216             ret = readChannelVolatileData();
1217         }
1218         catch (const std::exception& e)
1219         {
1220             log<level::ERR>("Exception caught in readChannelVolatileData.",
1221                             entry("MSG=%s", e.what()));
1222             ret = -EIO;
1223         }
1224     }
1225     return ret;
1226 }
1227 
1228 int ChannelConfig::setDbusProperty(const std::string& service,
1229                                    const std::string& objPath,
1230                                    const std::string& interface,
1231                                    const std::string& property,
1232                                    const DbusVariant& value)
1233 {
1234     try
1235     {
1236         auto method =
1237             bus.new_method_call(service.c_str(), objPath.c_str(),
1238                                 "org.freedesktop.DBus.Properties", "Set");
1239 
1240         method.append(interface, property, value);
1241 
1242         auto reply = bus.call(method);
1243     }
1244     catch (const sdbusplus::exception::SdBusError& e)
1245     {
1246         log<level::DEBUG>("set-property failed",
1247                           entry("SERVICE:%s", service.c_str()),
1248                           entry("OBJPATH:%s", objPath.c_str()),
1249                           entry("INTERFACE:%s", interface.c_str()),
1250                           entry("PROP:%s", property.c_str()));
1251         return -EIO;
1252     }
1253 
1254     return 0;
1255 }
1256 
1257 int ChannelConfig::getDbusProperty(const std::string& service,
1258                                    const std::string& objPath,
1259                                    const std::string& interface,
1260                                    const std::string& property,
1261                                    DbusVariant& value)
1262 {
1263     try
1264     {
1265         auto method =
1266             bus.new_method_call(service.c_str(), objPath.c_str(),
1267                                 "org.freedesktop.DBus.Properties", "Get");
1268 
1269         method.append(interface, property);
1270 
1271         auto reply = bus.call(method);
1272         reply.read(value);
1273     }
1274     catch (const sdbusplus::exception::SdBusError& e)
1275     {
1276         log<level::DEBUG>("get-property failed",
1277                           entry("SERVICE:%s", service.c_str()),
1278                           entry("OBJPATH:%s", objPath.c_str()),
1279                           entry("INTERFACE:%s", interface.c_str()),
1280                           entry("PROP:%s", property.c_str()));
1281         return -EIO;
1282     }
1283     return 0;
1284 }
1285 
1286 int ChannelConfig::syncNetworkChannelConfig()
1287 {
1288     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1289         channelLock{*channelMutex};
1290     bool isUpdated = false;
1291     for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1292     {
1293         if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1294         {
1295             std::string intfPrivStr;
1296             try
1297             {
1298                 std::string networkIntfObj =
1299                     std::string(networkIntfObjectBasePath) + "/" +
1300                     channelData[chNum].chName;
1301                 DbusVariant variant;
1302                 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
1303                                          networkChConfigIntfName,
1304                                          privilegePropertyString, variant))
1305                 {
1306                     log<level::DEBUG>("Network interface does not exist",
1307                                       entry("INTERFACE:%s",
1308                                             channelData[chNum].chName.c_str()));
1309                     continue;
1310                 }
1311                 intfPrivStr = std::get<std::string>(variant);
1312             }
1313             catch (const std::bad_variant_access& e)
1314             {
1315                 log<level::DEBUG>(
1316                     "exception: Network interface does not exist");
1317                 continue;
1318             }
1319             catch (const sdbusplus::exception::SdBusError& e)
1320             {
1321                 log<level::DEBUG>(
1322                     "exception: Network interface does not exist");
1323                 continue;
1324             }
1325 
1326             uint8_t intfPriv =
1327                 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1328             if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1329                 intfPriv)
1330             {
1331                 isUpdated = true;
1332                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1333                     intfPriv;
1334                 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1335             }
1336         }
1337     }
1338 
1339     if (isUpdated)
1340     {
1341         // Write persistent data to file
1342         if (writeChannelPersistData() != 0)
1343         {
1344             log<level::DEBUG>("Failed to update the persistent data file");
1345             return -EIO;
1346         }
1347         // Write Volatile data to file
1348         if (writeChannelVolatileData() != 0)
1349         {
1350             log<level::DEBUG>("Failed to update the channel volatile data");
1351             return -EIO;
1352         }
1353     }
1354 
1355     return 0;
1356 }
1357 
1358 void ChannelConfig::initChannelPersistData()
1359 {
1360     /* Always read the channel config */
1361     if (loadChannelConfig() != 0)
1362     {
1363         log<level::ERR>("Failed to read channel config file");
1364         throw std::ios_base::failure("Failed to load channel configuration");
1365     }
1366 
1367     /* Populate the channel persist data */
1368     if (readChannelPersistData() != 0)
1369     {
1370         // Copy default NV data to RW location
1371         std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1372                                                  channelNvDataFilename);
1373 
1374         // Load the channel access NV data
1375         if (readChannelPersistData() != 0)
1376         {
1377             log<level::ERR>("Failed to read channel access NV data");
1378             throw std::ios_base::failure(
1379                 "Failed to read channel access NV configuration");
1380         }
1381     }
1382 
1383     // First check the volatile data file
1384     // If not present, load the default values
1385     if (readChannelVolatileData() != 0)
1386     {
1387         // Copy default volatile data to temporary location
1388         // NV file(channelNvDataFilename) must have created by now.
1389         std::experimental::filesystem::copy_file(channelNvDataFilename,
1390                                                  channelVolatileDataFilename);
1391 
1392         // Load the channel access volatile data
1393         if (readChannelVolatileData() != 0)
1394         {
1395             log<level::ERR>("Failed to read channel access volatile data");
1396             throw std::ios_base::failure(
1397                 "Failed to read channel access volatile configuration");
1398         }
1399     }
1400 
1401     // Synchronize the channel config(priv) with network channel
1402     // configuration(priv) over dbus
1403     if (syncNetworkChannelConfig() != 0)
1404     {
1405         log<level::ERR>(
1406             "Failed to synchronize data with network channel config over dbus");
1407         throw std::ios_base::failure(
1408             "Failed to synchronize data with network channel config over dbus");
1409     }
1410 
1411     log<level::DEBUG>("Successfully completed channel data initialization.");
1412     return;
1413 }
1414 
1415 } // namespace ipmi
1416