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