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