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