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 != NULL; 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