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