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