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