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 #include "user_layer.hpp"
21 
22 #include <ifaddrs.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <boost/interprocess/sync/scoped_lock.hpp>
28 #include <cerrno>
29 #include <exception>
30 #include <experimental/filesystem>
31 #include <fstream>
32 #include <phosphor-logging/log.hpp>
33 #include <sdbusplus/bus/match.hpp>
34 #include <sdbusplus/server/object.hpp>
35 #include <unordered_map>
36 
37 namespace ipmi
38 {
39 
40 using namespace phosphor::logging;
41 
42 static constexpr const char* channelAccessDefaultFilename =
43     "/usr/share/ipmi-providers/channel_access.json";
44 static constexpr const char* channelConfigDefaultFilename =
45     "/usr/share/ipmi-providers/channel_config.json";
46 static constexpr const char* channelNvDataFilename =
47     "/var/lib/ipmi/channel_access_nv.json";
48 static constexpr const char* channelVolatileDataFilename =
49     "/run/ipmi/channel_access_volatile.json";
50 
51 // TODO: Get the service name dynamically..
52 static constexpr const char* networkIntfServiceName =
53     "xyz.openbmc_project.Network";
54 static constexpr const char* networkIntfObjectBasePath =
55     "/xyz/openbmc_project/network";
56 static constexpr const char* networkChConfigIntfName =
57     "xyz.openbmc_project.Channel.ChannelAccess";
58 static constexpr const char* privilegePropertyString = "MaxPrivilege";
59 static constexpr const char* dBusPropertiesInterface =
60     "org.freedesktop.DBus.Properties";
61 static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
62 
63 // STRING DEFINES: Should sync with key's in JSON
64 static constexpr const char* nameString = "name";
65 static constexpr const char* isValidString = "is_valid";
66 static constexpr const char* activeSessionsString = "active_sessions";
67 static constexpr const char* maxTransferSizeString = "max_transfer_size";
68 static constexpr const char* channelInfoString = "channel_info";
69 static constexpr const char* mediumTypeString = "medium_type";
70 static constexpr const char* protocolTypeString = "protocol_type";
71 static constexpr const char* sessionSupportedString = "session_supported";
72 static constexpr const char* isIpmiString = "is_ipmi";
73 static constexpr const char* isManagementNIC = "is_management_nic";
74 static constexpr const char* authTypeSupportedString = "auth_type_supported";
75 static constexpr const char* accessModeString = "access_mode";
76 static constexpr const char* userAuthDisabledString = "user_auth_disabled";
77 static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
78 static constexpr const char* alertingDisabledString = "alerting_disabled";
79 static constexpr const char* privLimitString = "priv_limit";
80 static constexpr const char* authTypeEnabledString = "auth_type_enabled";
81 
82 // Default values
83 static constexpr const char* defaultChannelName = "RESERVED";
84 static constexpr const uint8_t defaultMediumType =
85     static_cast<uint8_t>(EChannelMediumType::reserved);
86 static constexpr const uint8_t defaultProtocolType =
87     static_cast<uint8_t>(EChannelProtocolType::reserved);
88 static constexpr const uint8_t defaultSessionSupported =
89     static_cast<uint8_t>(EChannelSessSupported::none);
90 static constexpr const uint8_t defaultAuthType =
91     static_cast<uint8_t>(EAuthType::none);
92 static constexpr const bool defaultIsIpmiState = false;
93 static constexpr size_t smallChannelSize = 64;
94 
95 std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal
96     __attribute__((init_priority(101)));
97 
98 // String mappings use in JSON config file
99 static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
100     {"reserved", EChannelMediumType::reserved},
101     {"ipmb", EChannelMediumType::ipmb},
102     {"icmb-v1.0", EChannelMediumType::icmbV10},
103     {"icmb-v0.9", EChannelMediumType::icmbV09},
104     {"lan-802.3", EChannelMediumType::lan8032},
105     {"serial", EChannelMediumType::serial},
106     {"other-lan", EChannelMediumType::otherLan},
107     {"pci-smbus", EChannelMediumType::pciSmbus},
108     {"smbus-v1.0", EChannelMediumType::smbusV11},
109     {"smbus-v2.0", EChannelMediumType::smbusV20},
110     {"usb-1x", EChannelMediumType::usbV1x},
111     {"usb-2x", EChannelMediumType::usbV2x},
112     {"system-interface", EChannelMediumType::systemInterface},
113     {"oem", EChannelMediumType::oem},
114     {"unknown", EChannelMediumType::unknown}};
115 
116 static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = {
117     {interfaceKCS, "SMS"},
118     {interfaceLAN1, "eth0"},
119     {interfaceUnknown, "unknown"}};
120 
121 static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
122     {"na", EChannelProtocolType::na},
123     {"ipmb-1.0", EChannelProtocolType::ipmbV10},
124     {"icmb-2.0", EChannelProtocolType::icmbV11},
125     {"reserved", EChannelProtocolType::reserved},
126     {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
127     {"kcs", EChannelProtocolType::kcs},
128     {"smic", EChannelProtocolType::smic},
129     {"bt-10", EChannelProtocolType::bt10},
130     {"bt-15", EChannelProtocolType::bt15},
131     {"tmode", EChannelProtocolType::tMode},
132     {"oem", EChannelProtocolType::oem}};
133 
134 static std::array<std::string, 4> accessModeList = {
135     "disabled", "pre-boot", "always_available", "shared"};
136 
137 static std::array<std::string, 4> sessionSupportList = {
138     "session-less", "single-session", "multi-session", "session-based"};
139 
140 const std::array<std::string, PRIVILEGE_OEM + 1> privList = {
141     "priv-reserved", "priv-callback", "priv-user",
142     "priv-operator", "priv-admin",    "priv-oem"};
143 
144 std::string ChannelConfig::getChannelName(const uint8_t chNum)
145 {
146     if (!isValidChannel(chNum))
147     {
148         log<level::ERR>("Invalid channel number.",
149                         entry("CHANNEL_ID=%d", chNum));
150         throw std::invalid_argument("Invalid channel number");
151     }
152 
153     return channelData[chNum].chName;
154 }
155 
156 int ChannelConfig::convertToChannelNumberFromChannelName(
157     const std::string& chName)
158 {
159     for (const auto& it : channelData)
160     {
161         if (it.chName == chName)
162         {
163             return it.chID;
164         }
165     }
166     log<level::ERR>("Invalid channel name.",
167                     entry("CHANNEL=%s", chName.c_str()));
168     throw std::invalid_argument("Invalid channel name");
169 
170     return -1;
171 }
172 
173 std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
174 {
175 
176     constexpr size_t length = strlen(networkIntfObjectBasePath);
177     if (((length + 1) >= path.size()) ||
178         path.compare(0, length, networkIntfObjectBasePath))
179     {
180         log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str()));
181         throw std::invalid_argument("Invalid object path");
182     }
183     std::string chName(path, length + 1);
184     return chName;
185 }
186 
187 void ChannelConfig::processChAccessPropChange(
188     const std::string& path, const DbusChObjProperties& chProperties)
189 {
190     // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
191     std::string chName;
192     try
193     {
194         chName = getChannelNameFromPath(path);
195     }
196     catch (const std::invalid_argument& e)
197     {
198         log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
199         return;
200     }
201 
202     // Get the MaxPrivilege property value from the signal
203     std::string intfPrivStr;
204     std::string propName;
205     for (const auto& prop : chProperties)
206     {
207         if (prop.first == privilegePropertyString)
208         {
209             propName = privilegePropertyString;
210             intfPrivStr = std::get<std::string>(prop.second);
211             break;
212         }
213     }
214 
215     if (propName != privilegePropertyString)
216     {
217         log<level::ERR>("Unknown signal caught.");
218         return;
219     }
220 
221     if (intfPrivStr.empty())
222     {
223         log<level::ERR>("Invalid privilege string.",
224                         entry("INTF=%s", chName.c_str()));
225         return;
226     }
227 
228     uint8_t intfPriv = 0;
229     int chNum;
230     try
231     {
232         intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
233         chNum = convertToChannelNumberFromChannelName(chName);
234     }
235     catch (const std::invalid_argument& e)
236     {
237         log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
238         return;
239     }
240 
241     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
242         channelLock{*channelMutex};
243     // skip updating the values, if this property change originated from IPMI.
244     if (signalFlag & (1 << chNum))
245     {
246         signalFlag &= ~(1 << chNum);
247         log<level::DEBUG>("Request originated from IPMI so ignoring signal");
248         return;
249     }
250 
251     // Update both volatile & Non-volatile, if there is mismatch.
252     // as property change other than IPMI, has to update both volatile &
253     // non-volatile data.
254     checkAndReloadVolatileData();
255     checkAndReloadNVData();
256     if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
257     {
258         // Update NV data
259         channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
260         if (writeChannelPersistData() != 0)
261         {
262             log<level::ERR>("Failed to update the persist data file");
263             return;
264         }
265 
266         // Update Volatile data
267         if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
268         {
269             channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
270             if (writeChannelVolatileData() != 0)
271             {
272                 log<level::ERR>("Failed to update the volatile data file");
273                 return;
274             }
275         }
276     }
277 
278     return;
279 }
280 
281 ChannelConfig& getChannelConfigObject()
282 {
283     static ChannelConfig channelConfig;
284     return channelConfig;
285 }
286 
287 ChannelConfig::~ChannelConfig()
288 {
289     if (signalHndlrObjectState)
290     {
291         chPropertiesSignal.reset();
292         sigHndlrLock.unlock();
293     }
294 }
295 
296 ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
297 {
298     std::ofstream mutexCleanUpFile;
299     mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
300                           std::ofstream::out | std::ofstream::app);
301     if (!mutexCleanUpFile.good())
302     {
303         log<level::DEBUG>("Unable to open mutex cleanup file");
304         return;
305     }
306     mutexCleanUpFile.close();
307     mutexCleanupLock =
308         boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
309     if (mutexCleanupLock.try_lock())
310     {
311         boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
312         channelMutex =
313             std::make_unique<boost::interprocess::named_recursive_mutex>(
314                 boost::interprocess::open_or_create, ipmiChannelMutex);
315         mutexCleanupLock.lock_sharable();
316     }
317     else
318     {
319         mutexCleanupLock.lock_sharable();
320         channelMutex =
321             std::make_unique<boost::interprocess::named_recursive_mutex>(
322                 boost::interprocess::open_or_create, ipmiChannelMutex);
323     }
324 
325     initChannelPersistData();
326 
327     sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
328     // Register it for single object and single process either netipimd /
329     // host-ipmid
330     if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
331     {
332         log<level::DEBUG>("Registering channel signal handler.");
333         chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
334             bus,
335             sdbusplus::bus::match::rules::path_namespace(
336                 networkIntfObjectBasePath) +
337                 sdbusplus::bus::match::rules::type::signal() +
338                 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
339                 sdbusplus::bus::match::rules::interface(
340                     dBusPropertiesInterface) +
341                 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
342             [&](sdbusplus::message::message& msg) {
343                 DbusChObjProperties props;
344                 std::string iface;
345                 std::string path = msg.get_path();
346                 msg.read(iface, props);
347                 processChAccessPropChange(path, props);
348             });
349         signalHndlrObjectState = true;
350     }
351 }
352 
353 bool ChannelConfig::isValidChannel(const uint8_t chNum)
354 {
355     if (chNum > maxIpmiChannels)
356     {
357         log<level::DEBUG>("Invalid channel ID - Out of range");
358         return false;
359     }
360 
361     if (channelData[chNum].isChValid == false)
362     {
363         log<level::DEBUG>("Channel is not valid");
364     }
365 
366     return channelData[chNum].isChValid;
367 }
368 
369 EChannelSessSupported
370     ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
371 {
372     EChannelSessSupported chSessSupport =
373         (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
374     return chSessSupport;
375 }
376 
377 bool ChannelConfig::isValidAuthType(const uint8_t chNum,
378                                     const EAuthType& authType)
379 {
380     if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
381     {
382         log<level::DEBUG>("Invalid authentication type");
383         return false;
384     }
385 
386     uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
387     if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
388     {
389         log<level::DEBUG>("Authentication type is not supported.");
390         return false;
391     }
392 
393     return true;
394 }
395 
396 int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
397 {
398     // TODO: TEMPORARY FIX
399     // Channels active session count is managed separately
400     // by monitoring channel session which includes LAN and
401     // RAKP layer changes. This will be updated, once the
402     // authentication part is implemented.
403     return channelData[chNum].activeSessCount;
404 }
405 
406 size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
407 {
408     return channelData[chNum].maxTransferSize;
409 }
410 
411 Cc ChannelConfig::getChannelInfo(const uint8_t chNum, ChannelInfo& chInfo)
412 {
413     if (!isValidChannel(chNum))
414     {
415         log<level::DEBUG>("Invalid channel");
416         return ccInvalidFieldRequest;
417     }
418 
419     std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
420                 sizeof(channelData[chNum].chInfo),
421                 reinterpret_cast<uint8_t*>(&chInfo));
422     return ccSuccess;
423 }
424 
425 Cc ChannelConfig::getChannelAccessData(const uint8_t chNum,
426                                        ChannelAccess& chAccessData)
427 {
428     if (!isValidChannel(chNum))
429     {
430         log<level::DEBUG>("Invalid channel");
431         return ccInvalidFieldRequest;
432     }
433 
434     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
435     {
436         log<level::DEBUG>("Session-less channel doesn't have access data.");
437         return ccActionNotSupportedForChannel;
438     }
439 
440     if (checkAndReloadVolatileData() != 0)
441     {
442         return ccUnspecifiedError;
443     }
444 
445     std::copy_n(
446         reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
447         sizeof(channelData[chNum].chAccess.chVolatileData),
448         reinterpret_cast<uint8_t*>(&chAccessData));
449 
450     return ccSuccess;
451 }
452 
453 Cc ChannelConfig::setChannelAccessData(const uint8_t chNum,
454                                        const ChannelAccess& chAccessData,
455                                        const uint8_t setFlag)
456 {
457     if (!isValidChannel(chNum))
458     {
459         log<level::DEBUG>("Invalid channel");
460         return ccInvalidFieldRequest;
461     }
462 
463     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
464     {
465         log<level::DEBUG>("Session-less channel doesn't have access data.");
466         return ccActionNotSupportedForChannel;
467     }
468 
469     if ((setFlag & setAccessMode) &&
470         (!isValidAccessMode(chAccessData.accessMode)))
471     {
472         log<level::DEBUG>("Invalid access mode specified");
473         return ccAccessModeNotSupportedForChannel;
474     }
475     if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
476     {
477         log<level::DEBUG>("Invalid privilege limit specified");
478         return ccInvalidFieldRequest;
479     }
480 
481     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
482         channelLock{*channelMutex};
483 
484     if (checkAndReloadVolatileData() != 0)
485     {
486         return ccUnspecifiedError;
487     }
488 
489     if (setFlag & setAccessMode)
490     {
491         channelData[chNum].chAccess.chVolatileData.accessMode =
492             chAccessData.accessMode;
493     }
494     if (setFlag & setUserAuthEnabled)
495     {
496         channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
497             chAccessData.userAuthDisabled;
498     }
499     if (setFlag & setMsgAuthEnabled)
500     {
501         channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
502             chAccessData.perMsgAuthDisabled;
503     }
504     if (setFlag & setAlertingEnabled)
505     {
506         channelData[chNum].chAccess.chVolatileData.alertingDisabled =
507             chAccessData.alertingDisabled;
508     }
509     if (setFlag & setPrivLimit)
510     {
511         channelData[chNum].chAccess.chVolatileData.privLimit =
512             chAccessData.privLimit;
513     }
514 
515     // Write Volatile data to file
516     if (writeChannelVolatileData() != 0)
517     {
518         log<level::DEBUG>("Failed to update the channel volatile data");
519         return ccUnspecifiedError;
520     }
521     return ccSuccess;
522 }
523 
524 Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
525                                               ChannelAccess& chAccessData)
526 {
527     if (!isValidChannel(chNum))
528     {
529         log<level::DEBUG>("Invalid channel");
530         return ccInvalidFieldRequest;
531     }
532 
533     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
534     {
535         log<level::DEBUG>("Session-less channel doesn't have access data.");
536         return ccActionNotSupportedForChannel;
537     }
538 
539     if (checkAndReloadNVData() != 0)
540     {
541         return ccUnspecifiedError;
542     }
543 
544     std::copy_n(reinterpret_cast<uint8_t*>(
545                     &channelData[chNum].chAccess.chNonVolatileData),
546                 sizeof(channelData[chNum].chAccess.chNonVolatileData),
547                 reinterpret_cast<uint8_t*>(&chAccessData));
548 
549     return ccSuccess;
550 }
551 
552 Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum,
553                                               const ChannelAccess& chAccessData,
554                                               const uint8_t setFlag)
555 {
556     if (!isValidChannel(chNum))
557     {
558         log<level::DEBUG>("Invalid channel");
559         return ccInvalidFieldRequest;
560     }
561 
562     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
563     {
564         log<level::DEBUG>("Session-less channel doesn't have access data.");
565         return ccActionNotSupportedForChannel;
566     }
567 
568     if ((setFlag & setAccessMode) &&
569         (!isValidAccessMode(chAccessData.accessMode)))
570     {
571         log<level::DEBUG>("Invalid access mode specified");
572         return ccAccessModeNotSupportedForChannel;
573     }
574     if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
575     {
576         log<level::DEBUG>("Invalid privilege limit specified");
577         return ccInvalidFieldRequest;
578     }
579 
580     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
581         channelLock{*channelMutex};
582 
583     if (checkAndReloadNVData() != 0)
584     {
585         return ccUnspecifiedError;
586     }
587 
588     if (setFlag & setAccessMode)
589     {
590         channelData[chNum].chAccess.chNonVolatileData.accessMode =
591             chAccessData.accessMode;
592     }
593     if (setFlag & setUserAuthEnabled)
594     {
595         channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
596             chAccessData.userAuthDisabled;
597     }
598     if (setFlag & setMsgAuthEnabled)
599     {
600         channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
601             chAccessData.perMsgAuthDisabled;
602     }
603     if (setFlag & setAlertingEnabled)
604     {
605         channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
606             chAccessData.alertingDisabled;
607     }
608     if (setFlag & setPrivLimit)
609     {
610         // Send Update to network channel config interfaces over dbus
611         std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
612         std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
613                                      "/" + channelData[chNum].chName;
614         try
615         {
616             if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
617                                      networkChConfigIntfName,
618                                      privilegePropertyString, privStr))
619             {
620                 log<level::DEBUG>(
621                     "Network interface does not exist",
622                     entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
623                 return ccUnspecifiedError;
624             }
625         }
626         catch (const sdbusplus::exception::SdBusError& e)
627         {
628             log<level::ERR>("Exception: Network interface does not exist");
629             return ccInvalidFieldRequest;
630         }
631         signalFlag |= (1 << chNum);
632         channelData[chNum].chAccess.chNonVolatileData.privLimit =
633             chAccessData.privLimit;
634     }
635 
636     // Write persistent data to file
637     if (writeChannelPersistData() != 0)
638     {
639         log<level::DEBUG>("Failed to update the presist data file");
640         return ccUnspecifiedError;
641     }
642     return ccSuccess;
643 }
644 
645 Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
646                                               uint8_t& authTypeSupported)
647 {
648     if (!isValidChannel(chNum))
649     {
650         log<level::DEBUG>("Invalid channel");
651         return ccInvalidFieldRequest;
652     }
653 
654     authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
655     return ccSuccess;
656 }
657 
658 Cc 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 ccInvalidFieldRequest;
666     }
667 
668     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
669     {
670         log<level::DEBUG>("Sessionless channel doesn't have access data.");
671         return ccInvalidFieldRequest;
672     }
673 
674     if (!isValidPrivLimit(priv))
675     {
676         log<level::DEBUG>("Invalid privilege specified.");
677         return ccInvalidFieldRequest;
678     }
679 
680     // TODO: Hardcoded for now. Need to implement.
681     authType = EAuthType::none;
682 
683     return ccSuccess;
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 Json ChannelConfig::readJsonFile(const std::string& configFile)
795 {
796     std::ifstream jsonFile(configFile);
797     if (!jsonFile.good())
798     {
799         log<level::INFO>("JSON file not found",
800                          entry("FILE_NAME=%s", configFile.c_str()));
801         return nullptr;
802     }
803 
804     Json data = nullptr;
805     try
806     {
807         data = Json::parse(jsonFile, nullptr, false);
808     }
809     catch (Json::parse_error& e)
810     {
811         log<level::DEBUG>("Corrupted channel config.",
812                           entry("MSG=%s", e.what()));
813         throw std::runtime_error("Corrupted channel config file");
814     }
815 
816     return data;
817 }
818 
819 int ChannelConfig::writeJsonFile(const std::string& configFile,
820                                  const Json& jsonData)
821 {
822     const std::string tmpFile = configFile + "_tmp";
823     int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
824                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
825     if (fd < 0)
826     {
827         log<level::ERR>("Error in creating json file",
828                         entry("FILE_NAME = %s", tmpFile.c_str()));
829         return -EIO;
830     }
831     const auto& writeData = jsonData.dump();
832     if (write(fd, writeData.c_str(), writeData.size()) !=
833         static_cast<ssize_t>(writeData.size()))
834     {
835         close(fd);
836         log<level::ERR>("Error in writing configuration file",
837                         entry("FILE_NAME = %s", tmpFile.c_str()));
838         return -EIO;
839     }
840     close(fd);
841 
842     if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
843     {
844         log<level::ERR>("Error in renaming temporary data file",
845                         entry("FILE_NAME = %s", tmpFile.c_str()));
846         return -EIO;
847     }
848 
849     return 0;
850 }
851 
852 void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
853                                             const std::string& chName)
854 {
855     channelData[chNum].chName = chName;
856     channelData[chNum].chID = chNum;
857     channelData[chNum].isChValid = false;
858     channelData[chNum].activeSessCount = 0;
859     channelData[chNum].isManagementNIC = false;
860 
861     channelData[chNum].chInfo.mediumType = defaultMediumType;
862     channelData[chNum].chInfo.protocolType = defaultProtocolType;
863     channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
864     channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
865     channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
866 }
867 
868 uint8_t ChannelConfig::getManagementNICID()
869 {
870     static bool idFound = false;
871     static uint8_t id = 0;
872 
873     if (idFound)
874     {
875         return id;
876     }
877 
878     for (uint8_t chIdx = 0; chIdx < maxIpmiChannels; chIdx++)
879     {
880         if (channelData[chIdx].isManagementNIC)
881         {
882             id = chIdx;
883             idFound = true;
884             break;
885         }
886     }
887 
888     if (!idFound)
889     {
890         id = static_cast<uint8_t>(EChannelID::chanLan1);
891         idFound = true;
892     }
893     return id;
894 }
895 
896 int ChannelConfig::loadChannelConfig()
897 {
898     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
899         channelLock{*channelMutex};
900 
901     Json data = readJsonFile(channelConfigDefaultFilename);
902     if (data.empty())
903     {
904         log<level::DEBUG>("Error in opening IPMI Channel data file");
905         return -EIO;
906     }
907 
908     channelData.fill(ChannelProperties{});
909 
910     // Collect the list of NIC interfaces connected to the BMC. Use this
911     // information to only add IPMI channels that have active NIC interfaces.
912     struct ifaddrs *ifaddr, *ifa;
913     if (int err = getifaddrs(&ifaddr); err < 0)
914     {
915         log<level::DEBUG>("Unable to acquire network interfaces");
916         return -EIO;
917     }
918 
919     for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
920     {
921         try
922         {
923             std::string chKey = std::to_string(chNum);
924             Json jsonChData = data[chKey].get<Json>();
925             if (jsonChData.is_null())
926             {
927                 log<level::WARNING>(
928                     "Channel not configured so loading default.",
929                     entry("CHANNEL_NUM=%d", chNum));
930                 // If user didn't want to configure specific channel (say
931                 // reserved channel), then load that index with default values.
932                 setDefaultChannelConfig(chNum, defaultChannelName);
933                 continue;
934             }
935             Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
936             if (jsonChInfo.is_null())
937             {
938                 log<level::ERR>("Invalid/corrupted channel config file");
939                 freeifaddrs(ifaddr);
940                 return -EBADMSG;
941             }
942 
943             bool channelFound = true;
944             // Confirm the LAN channel is present
945             if (jsonChInfo[mediumTypeString].get<std::string>() == "lan-802.3")
946             {
947                 channelFound = false;
948                 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
949                 {
950                     if (jsonChData[nameString].get<std::string>() ==
951                         ifa->ifa_name)
952                     {
953                         channelFound = true;
954                         break;
955                     }
956                 }
957             }
958             ChannelProperties& chData = channelData[chNum];
959             chData.chID = chNum;
960             chData.chName = jsonChData[nameString].get<std::string>();
961             chData.isChValid =
962                 channelFound && jsonChData[isValidString].get<bool>();
963             chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
964             chData.maxTransferSize =
965                 jsonChData.value(maxTransferSizeString, smallChannelSize);
966             if (jsonChData.count(isManagementNIC) != 0)
967             {
968                 chData.isManagementNIC =
969                     jsonChData[isManagementNIC].get<bool>();
970             }
971 
972             std::string medTypeStr =
973                 jsonChInfo[mediumTypeString].get<std::string>();
974             chData.chInfo.mediumType =
975                 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
976             std::string protoTypeStr =
977                 jsonChInfo[protocolTypeString].get<std::string>();
978             chData.chInfo.protocolType =
979                 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
980             std::string sessStr =
981                 jsonChInfo[sessionSupportedString].get<std::string>();
982             chData.chInfo.sessionSupported =
983                 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
984             chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
985             chData.chInfo.authTypeSupported = defaultAuthType;
986         }
987         catch (const Json::exception& e)
988         {
989             log<level::DEBUG>("Json Exception caught.",
990                               entry("MSG=%s", e.what()));
991             freeifaddrs(ifaddr);
992 
993             return -EBADMSG;
994         }
995         catch (const std::invalid_argument& e)
996         {
997             log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
998             freeifaddrs(ifaddr);
999             return -EBADMSG;
1000         }
1001     }
1002     freeifaddrs(ifaddr);
1003 
1004     return 0;
1005 }
1006 
1007 int ChannelConfig::readChannelVolatileData()
1008 {
1009     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1010         channelLock{*channelMutex};
1011 
1012     Json data = readJsonFile(channelVolatileDataFilename);
1013     if (data == nullptr)
1014     {
1015         log<level::DEBUG>("Error in opening IPMI Channel data file");
1016         return -EIO;
1017     }
1018     try
1019     {
1020         // Fill in global structure
1021         for (auto it = data.begin(); it != data.end(); ++it)
1022         {
1023             std::string chKey = it.key();
1024             uint8_t chNum = std::stoi(chKey, nullptr, 10);
1025             if ((chNum < 0) || (chNum > maxIpmiChannels))
1026             {
1027                 log<level::DEBUG>(
1028                     "Invalid channel access entry in config file");
1029                 throw std::out_of_range("Out of range - channel number");
1030             }
1031             Json jsonChData = it.value();
1032             if (!jsonChData.is_null())
1033             {
1034                 std::string accModeStr =
1035                     jsonChData[accessModeString].get<std::string>();
1036                 channelData[chNum].chAccess.chVolatileData.accessMode =
1037                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1038                 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
1039                     jsonChData[userAuthDisabledString].get<bool>();
1040                 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
1041                     jsonChData[perMsgAuthDisabledString].get<bool>();
1042                 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
1043                     jsonChData[alertingDisabledString].get<bool>();
1044                 std::string privStr =
1045                     jsonChData[privLimitString].get<std::string>();
1046                 channelData[chNum].chAccess.chVolatileData.privLimit =
1047                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1048             }
1049             else
1050             {
1051                 log<level::ERR>(
1052                     "Invalid/corrupted volatile channel access file",
1053                     entry("FILE=%s", channelVolatileDataFilename));
1054                 throw std::runtime_error(
1055                     "Corrupted volatile channel access file");
1056             }
1057         }
1058     }
1059     catch (const Json::exception& e)
1060     {
1061         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
1062         throw std::runtime_error("Corrupted volatile channel access file");
1063     }
1064     catch (const std::invalid_argument& e)
1065     {
1066         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1067         throw std::runtime_error("Corrupted volatile channel access file");
1068     }
1069 
1070     // Update the timestamp
1071     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1072     return 0;
1073 }
1074 
1075 int ChannelConfig::readChannelPersistData()
1076 {
1077     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1078         channelLock{*channelMutex};
1079 
1080     Json data = readJsonFile(channelNvDataFilename);
1081     if (data == nullptr)
1082     {
1083         log<level::DEBUG>("Error in opening IPMI Channel data file");
1084         return -EIO;
1085     }
1086     try
1087     {
1088         // Fill in global structure
1089         for (auto it = data.begin(); it != data.end(); ++it)
1090         {
1091             std::string chKey = it.key();
1092             uint8_t chNum = std::stoi(chKey, nullptr, 10);
1093             if ((chNum < 0) || (chNum > maxIpmiChannels))
1094             {
1095                 log<level::DEBUG>(
1096                     "Invalid channel access entry in config file");
1097                 throw std::out_of_range("Out of range - channel number");
1098             }
1099             Json jsonChData = it.value();
1100             if (!jsonChData.is_null())
1101             {
1102                 std::string accModeStr =
1103                     jsonChData[accessModeString].get<std::string>();
1104                 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1105                     static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1106                 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1107                     jsonChData[userAuthDisabledString].get<bool>();
1108                 channelData[chNum]
1109                     .chAccess.chNonVolatileData.perMsgAuthDisabled =
1110                     jsonChData[perMsgAuthDisabledString].get<bool>();
1111                 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1112                     jsonChData[alertingDisabledString].get<bool>();
1113                 std::string privStr =
1114                     jsonChData[privLimitString].get<std::string>();
1115                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1116                     static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1117             }
1118             else
1119             {
1120                 log<level::ERR>("Invalid/corrupted nv channel access file",
1121                                 entry("FILE=%s", channelNvDataFilename));
1122                 throw std::runtime_error("Corrupted nv channel access file");
1123             }
1124         }
1125     }
1126     catch (const Json::exception& e)
1127     {
1128         log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
1129         throw std::runtime_error("Corrupted nv channel access file");
1130     }
1131     catch (const std::invalid_argument& e)
1132     {
1133         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1134         throw std::runtime_error("Corrupted nv channel access file");
1135     }
1136 
1137     // Update the timestamp
1138     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1139     return 0;
1140 }
1141 
1142 int ChannelConfig::writeChannelVolatileData()
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.chVolatileData.accessMode);
1158                 jsonObj[accessModeString] = accModeStr;
1159                 jsonObj[userAuthDisabledString] =
1160                     channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1161                 jsonObj[perMsgAuthDisabledString] =
1162                     channelData[chNum]
1163                         .chAccess.chVolatileData.perMsgAuthDisabled;
1164                 jsonObj[alertingDisabledString] =
1165                     channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1166                 std::string privStr = convertToPrivLimitString(
1167                     channelData[chNum].chAccess.chVolatileData.privLimit);
1168                 jsonObj[privLimitString] = privStr;
1169 
1170                 outData[chKey] = jsonObj;
1171             }
1172         }
1173     }
1174     catch (const std::invalid_argument& e)
1175     {
1176         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1177         return -EINVAL;
1178     }
1179 
1180     if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1181     {
1182         log<level::DEBUG>("Error in write JSON data to file");
1183         return -EIO;
1184     }
1185 
1186     // Update the timestamp
1187     voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1188     return 0;
1189 }
1190 
1191 int ChannelConfig::writeChannelPersistData()
1192 {
1193     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1194         channelLock{*channelMutex};
1195     Json outData;
1196 
1197     try
1198     {
1199         for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1200         {
1201             if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1202             {
1203                 Json jsonObj;
1204                 std::string chKey = std::to_string(chNum);
1205                 std::string accModeStr = convertToAccessModeString(
1206                     channelData[chNum].chAccess.chNonVolatileData.accessMode);
1207                 jsonObj[accessModeString] = accModeStr;
1208                 jsonObj[userAuthDisabledString] =
1209                     channelData[chNum]
1210                         .chAccess.chNonVolatileData.userAuthDisabled;
1211                 jsonObj[perMsgAuthDisabledString] =
1212                     channelData[chNum]
1213                         .chAccess.chNonVolatileData.perMsgAuthDisabled;
1214                 jsonObj[alertingDisabledString] =
1215                     channelData[chNum]
1216                         .chAccess.chNonVolatileData.alertingDisabled;
1217                 std::string privStr = convertToPrivLimitString(
1218                     channelData[chNum].chAccess.chNonVolatileData.privLimit);
1219                 jsonObj[privLimitString] = privStr;
1220 
1221                 outData[chKey] = jsonObj;
1222             }
1223         }
1224     }
1225     catch (const std::invalid_argument& e)
1226     {
1227         log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
1228         return -EINVAL;
1229     }
1230 
1231     if (writeJsonFile(channelNvDataFilename, outData) != 0)
1232     {
1233         log<level::DEBUG>("Error in write JSON data to file");
1234         return -EIO;
1235     }
1236 
1237     // Update the timestamp
1238     nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1239     return 0;
1240 }
1241 
1242 int ChannelConfig::checkAndReloadNVData()
1243 {
1244     std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1245     int ret = 0;
1246     if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1247     {
1248         try
1249         {
1250             ret = readChannelPersistData();
1251         }
1252         catch (const std::exception& e)
1253         {
1254             log<level::ERR>("Exception caught in readChannelPersistData.",
1255                             entry("MSG=%s", e.what()));
1256             ret = -EIO;
1257         }
1258     }
1259     return ret;
1260 }
1261 
1262 int ChannelConfig::checkAndReloadVolatileData()
1263 {
1264     std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1265     int ret = 0;
1266     if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1267     {
1268         try
1269         {
1270             ret = readChannelVolatileData();
1271         }
1272         catch (const std::exception& e)
1273         {
1274             log<level::ERR>("Exception caught in readChannelVolatileData.",
1275                             entry("MSG=%s", e.what()));
1276             ret = -EIO;
1277         }
1278     }
1279     return ret;
1280 }
1281 
1282 int ChannelConfig::setDbusProperty(const std::string& service,
1283                                    const std::string& objPath,
1284                                    const std::string& interface,
1285                                    const std::string& property,
1286                                    const DbusVariant& value)
1287 {
1288     try
1289     {
1290         auto method =
1291             bus.new_method_call(service.c_str(), objPath.c_str(),
1292                                 "org.freedesktop.DBus.Properties", "Set");
1293 
1294         method.append(interface, property, value);
1295 
1296         auto reply = bus.call(method);
1297     }
1298     catch (const sdbusplus::exception::SdBusError& e)
1299     {
1300         log<level::DEBUG>("set-property failed",
1301                           entry("SERVICE=%s", service.c_str()),
1302                           entry("OBJPATH=%s", objPath.c_str()),
1303                           entry("INTERFACE=%s", interface.c_str()),
1304                           entry("PROP=%s", property.c_str()));
1305         return -EIO;
1306     }
1307 
1308     return 0;
1309 }
1310 
1311 int ChannelConfig::getDbusProperty(const std::string& service,
1312                                    const std::string& objPath,
1313                                    const std::string& interface,
1314                                    const std::string& property,
1315                                    DbusVariant& value)
1316 {
1317     try
1318     {
1319         auto method =
1320             bus.new_method_call(service.c_str(), objPath.c_str(),
1321                                 "org.freedesktop.DBus.Properties", "Get");
1322 
1323         method.append(interface, property);
1324 
1325         auto reply = bus.call(method);
1326         reply.read(value);
1327     }
1328     catch (const sdbusplus::exception::SdBusError& e)
1329     {
1330         log<level::DEBUG>("get-property failed",
1331                           entry("SERVICE=%s", service.c_str()),
1332                           entry("OBJPATH=%s", objPath.c_str()),
1333                           entry("INTERFACE=%s", interface.c_str()),
1334                           entry("PROP=%s", property.c_str()));
1335         return -EIO;
1336     }
1337     return 0;
1338 }
1339 
1340 int ChannelConfig::syncNetworkChannelConfig()
1341 {
1342     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1343         channelLock{*channelMutex};
1344     bool isUpdated = false;
1345     for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1346     {
1347         if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1348         {
1349             std::string intfPrivStr;
1350             try
1351             {
1352                 std::string networkIntfObj =
1353                     std::string(networkIntfObjectBasePath) + "/" +
1354                     channelData[chNum].chName;
1355                 DbusVariant variant;
1356                 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
1357                                          networkChConfigIntfName,
1358                                          privilegePropertyString, variant))
1359                 {
1360                     log<level::DEBUG>("Network interface does not exist",
1361                                       entry("INTERFACE=%s",
1362                                             channelData[chNum].chName.c_str()));
1363                     continue;
1364                 }
1365                 intfPrivStr = std::get<std::string>(variant);
1366             }
1367             catch (const std::bad_variant_access& e)
1368             {
1369                 log<level::DEBUG>(
1370                     "exception: Network interface does not exist");
1371                 continue;
1372             }
1373             catch (const sdbusplus::exception::SdBusError& e)
1374             {
1375                 log<level::DEBUG>(
1376                     "exception: Network interface does not exist");
1377                 continue;
1378             }
1379 
1380             uint8_t intfPriv =
1381                 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1382             if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1383                 intfPriv)
1384             {
1385                 isUpdated = true;
1386                 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1387                     intfPriv;
1388                 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1389             }
1390         }
1391     }
1392 
1393     if (isUpdated)
1394     {
1395         // Write persistent data to file
1396         if (writeChannelPersistData() != 0)
1397         {
1398             log<level::DEBUG>("Failed to update the persistent data file");
1399             return -EIO;
1400         }
1401         // Write Volatile data to file
1402         if (writeChannelVolatileData() != 0)
1403         {
1404             log<level::DEBUG>("Failed to update the channel volatile data");
1405             return -EIO;
1406         }
1407     }
1408 
1409     return 0;
1410 }
1411 
1412 void ChannelConfig::initChannelPersistData()
1413 {
1414     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1415         channelLock{*channelMutex};
1416 
1417     /* Always read the channel config */
1418     if (loadChannelConfig() != 0)
1419     {
1420         log<level::ERR>("Failed to read channel config file");
1421         throw std::ios_base::failure("Failed to load channel configuration");
1422     }
1423 
1424     /* Populate the channel persist data */
1425     if (readChannelPersistData() != 0)
1426     {
1427         // Copy default NV data to RW location
1428         std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1429                                                  channelNvDataFilename);
1430 
1431         // Load the channel access NV data
1432         if (readChannelPersistData() != 0)
1433         {
1434             log<level::ERR>("Failed to read channel access NV data");
1435             throw std::ios_base::failure(
1436                 "Failed to read channel access NV configuration");
1437         }
1438     }
1439 
1440     // First check the volatile data file
1441     // If not present, load the default values
1442     if (readChannelVolatileData() != 0)
1443     {
1444         // Copy default volatile data to temporary location
1445         // NV file(channelNvDataFilename) must have created by now.
1446         std::experimental::filesystem::copy_file(channelNvDataFilename,
1447                                                  channelVolatileDataFilename);
1448 
1449         // Load the channel access volatile data
1450         if (readChannelVolatileData() != 0)
1451         {
1452             log<level::ERR>("Failed to read channel access volatile data");
1453             throw std::ios_base::failure(
1454                 "Failed to read channel access volatile configuration");
1455         }
1456     }
1457 
1458     // Synchronize the channel config(priv) with network channel
1459     // configuration(priv) over dbus
1460     if (syncNetworkChannelConfig() != 0)
1461     {
1462         log<level::ERR>(
1463             "Failed to synchronize data with network channel config over dbus");
1464         throw std::ios_base::failure(
1465             "Failed to synchronize data with network channel config over dbus");
1466     }
1467 
1468     log<level::DEBUG>("Successfully completed channel data initialization.");
1469     return;
1470 }
1471 
1472 } // namespace ipmi
1473