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