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