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