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