blob: 585d4411dcc8534fe9bc4c110469ca5222de2e09 [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";
Vernon Mauery58317122018-11-28 11:02:43 -080065static constexpr const char* maxTransferSizeString = "max_transfer_size";
AppaRao Puli071f3f22018-05-24 16:45:30 +053066static constexpr const char* channelInfoString = "channel_info";
67static constexpr const char* mediumTypeString = "medium_type";
68static constexpr const char* protocolTypeString = "protocol_type";
69static constexpr const char* sessionSupportedString = "session_supported";
70static constexpr const char* isIpmiString = "is_ipmi";
71static constexpr const char* authTypeSupportedString = "auth_type_supported";
72static constexpr const char* accessModeString = "access_mode";
73static constexpr const char* userAuthDisabledString = "user_auth_disabled";
74static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
75static constexpr const char* alertingDisabledString = "alerting_disabled";
76static constexpr const char* privLimitString = "priv_limit";
77static constexpr const char* authTypeEnabledString = "auth_type_enabled";
78
79// Default values
80static constexpr const char* defaultChannelName = "RESERVED";
81static constexpr const uint8_t defaultMediumType =
82 static_cast<uint8_t>(EChannelMediumType::reserved);
83static constexpr const uint8_t defaultProtocolType =
84 static_cast<uint8_t>(EChannelProtocolType::reserved);
85static constexpr const uint8_t defaultSessionSupported =
86 static_cast<uint8_t>(EChannelSessSupported::none);
87static constexpr const uint8_t defaultAuthType =
88 static_cast<uint8_t>(EAuthType::none);
89static constexpr const bool defaultIsIpmiState = false;
Vernon Mauery58317122018-11-28 11:02:43 -080090static constexpr size_t smallChannelSize = 64;
AppaRao Puli071f3f22018-05-24 16:45:30 +053091
AppaRao Puli9613ed72018-09-01 23:46:44 +053092std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal(nullptr);
93
AppaRao Puli071f3f22018-05-24 16:45:30 +053094// String mappings use in JSON config file
95static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
96 {"reserved", EChannelMediumType::reserved},
97 {"ipmb", EChannelMediumType::ipmb},
98 {"icmb-v1.0", EChannelMediumType::icmbV10},
99 {"icmb-v0.9", EChannelMediumType::icmbV09},
100 {"lan-802.3", EChannelMediumType::lan8032},
101 {"serial", EChannelMediumType::serial},
102 {"other-lan", EChannelMediumType::otherLan},
103 {"pci-smbus", EChannelMediumType::pciSmbus},
104 {"smbus-v1.0", EChannelMediumType::smbusV11},
105 {"smbus-v2.0", EChannelMediumType::smbusV20},
106 {"usb-1x", EChannelMediumType::usbV1x},
107 {"usb-2x", EChannelMediumType::usbV2x},
108 {"system-interface", EChannelMediumType::systemInterface},
109 {"oem", EChannelMediumType::oem},
110 {"unknown", EChannelMediumType::unknown}};
111
ssekarf4b2b092018-07-25 18:49:08 +0530112static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = {
Richard Marian Thomaiyar43cb1282018-12-08 17:22:53 +0530113 {interfaceKCS, "SMS"},
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530114 {interfaceLAN1, "eth0"},
ssekarf4b2b092018-07-25 18:49:08 +0530115 {interfaceUnknown, "unknown"}};
116
AppaRao Puli071f3f22018-05-24 16:45:30 +0530117static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
118 {"na", EChannelProtocolType::na},
119 {"ipmb-1.0", EChannelProtocolType::ipmbV10},
120 {"icmb-2.0", EChannelProtocolType::icmbV11},
121 {"reserved", EChannelProtocolType::reserved},
122 {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
123 {"kcs", EChannelProtocolType::kcs},
124 {"smic", EChannelProtocolType::smic},
125 {"bt-10", EChannelProtocolType::bt10},
126 {"bt-15", EChannelProtocolType::bt15},
127 {"tmode", EChannelProtocolType::tMode},
128 {"oem", EChannelProtocolType::oem}};
129
130static std::array<std::string, 4> accessModeList = {
131 "disabled", "pre-boot", "always_available", "shared"};
132
133static std::array<std::string, 4> sessionSupportList = {
134 "session-less", "single-session", "multi-session", "session-based"};
135
136static std::array<std::string, PRIVILEGE_OEM + 1> privList = {
137 "priv-reserved", "priv-callback", "priv-user",
138 "priv-operator", "priv-admin", "priv-oem"};
139
Johnathan Mantey74a21022018-12-13 13:17:56 -0800140std::string ChannelConfig::getChannelName(const int chNum)
141{
142 if (!isValidChannel(chNum))
143 {
144 log<level::ERR>("Invalid channel number.",
145 entry("ChannelID:%d", chNum));
146 throw std::invalid_argument("Invalid channel number");
147 }
148
149 return channelData[chNum].chName;
150}
151
152int ChannelConfig::convertToChannelNumberFromChannelName(
153 const std::string& chName)
154{
155 for (const auto& it : channelData)
156 {
157 if (it.chName == chName)
158 {
159 return it.chID;
160 }
161 }
162 log<level::ERR>("Invalid channel name.",
163 entry("Channel:%s", chName.c_str()));
164 throw std::invalid_argument("Invalid channel name");
165
166 return -1;
167}
168
169std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530170{
171 std::size_t pos = path.find(networkIntfObjectBasePath);
172 if (pos == std::string::npos)
173 {
174 log<level::ERR>("Invalid interface path.",
175 entry("PATH:%s", path.c_str()));
176 throw std::invalid_argument("Invalid interface path");
177 }
Johnathan Mantey74a21022018-12-13 13:17:56 -0800178 std::string chName =
AppaRao Puli9613ed72018-09-01 23:46:44 +0530179 path.substr(pos + strlen(networkIntfObjectBasePath) + 1);
Johnathan Mantey74a21022018-12-13 13:17:56 -0800180 return chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530181}
182
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800183void ChannelConfig::processChAccessPropChange(
184 const std::string& path, const DbusChObjProperties& chProperties)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530185{
186 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
Johnathan Mantey74a21022018-12-13 13:17:56 -0800187 std::string chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530188 try
189 {
Johnathan Mantey74a21022018-12-13 13:17:56 -0800190 chName = getChannelNameFromPath(path);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530191 }
192 catch (const std::invalid_argument& e)
193 {
194 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
195 return;
196 }
197
198 // Get the MaxPrivilege property value from the signal
199 std::string intfPrivStr;
200 std::string propName;
201 for (const auto& prop : chProperties)
202 {
203 if (prop.first == privilegePropertyString)
204 {
205 propName = privilegePropertyString;
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800206 intfPrivStr = variant_ns::get<std::string>(prop.second);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530207 break;
208 }
209 }
210
211 if (propName != privilegePropertyString)
212 {
213 log<level::ERR>("Unknown signal caught.");
214 return;
215 }
216
217 if (intfPrivStr.empty())
218 {
219 log<level::ERR>("Invalid privilege string.",
Johnathan Mantey74a21022018-12-13 13:17:56 -0800220 entry("INTF:%s", chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530221 return;
222 }
223
224 uint8_t intfPriv = 0;
Johnathan Mantey74a21022018-12-13 13:17:56 -0800225 int chNum;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530226 try
227 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800228 intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800229 chNum = convertToChannelNumberFromChannelName(chName);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530230 }
231 catch (const std::invalid_argument& e)
232 {
233 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
234 return;
235 }
236
237 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800238 channelLock{*channelMutex};
AppaRao Puli9613ed72018-09-01 23:46:44 +0530239 // skip updating the values, if this property change originated from IPMI.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800240 if (signalFlag & (1 << chNum))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530241 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800242 signalFlag &= ~(1 << chNum);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530243 log<level::DEBUG>("Request originated from IPMI so ignoring signal");
244 return;
245 }
246
247 // Update both volatile & Non-volatile, if there is mismatch.
248 // as property change other than IPMI, has to update both volatile &
249 // non-volatile data.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800250 checkAndReloadVolatileData();
251 checkAndReloadNVData();
252 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530253 {
254 // Update NV data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800255 channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
256 if (writeChannelPersistData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530257 {
258 log<level::ERR>("Failed to update the persist data file");
259 return;
260 }
261
262 // Update Volatile data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800263 if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530264 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800265 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
266 if (writeChannelVolatileData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530267 {
268 log<level::ERR>("Failed to update the volatile data file");
269 return;
270 }
271 }
272 }
273
274 return;
275}
276
AppaRao Puli071f3f22018-05-24 16:45:30 +0530277ChannelConfig& getChannelConfigObject()
278{
279 static ChannelConfig channelConfig;
280 return channelConfig;
281}
282
AppaRao Puli9613ed72018-09-01 23:46:44 +0530283ChannelConfig::~ChannelConfig()
284{
285 if (signalHndlrObjectState)
286 {
287 chPropertiesSignal.reset();
288 sigHndlrLock.unlock();
289 }
290}
291
AppaRao Puli071f3f22018-05-24 16:45:30 +0530292ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
293{
294 std::ofstream mutexCleanUpFile;
295 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
296 std::ofstream::out | std::ofstream::app);
297 if (!mutexCleanUpFile.good())
298 {
299 log<level::DEBUG>("Unable to open mutex cleanup file");
300 return;
301 }
302 mutexCleanUpFile.close();
303 mutexCleanupLock =
304 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
305 if (mutexCleanupLock.try_lock())
306 {
307 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
308 channelMutex =
309 std::make_unique<boost::interprocess::named_recursive_mutex>(
310 boost::interprocess::open_or_create, ipmiChannelMutex);
311 mutexCleanupLock.lock_sharable();
312 }
313 else
314 {
315 mutexCleanupLock.lock_sharable();
316 channelMutex =
317 std::make_unique<boost::interprocess::named_recursive_mutex>(
318 boost::interprocess::open_or_create, ipmiChannelMutex);
319 }
320
321 initChannelPersistData();
AppaRao Puli9613ed72018-09-01 23:46:44 +0530322
323 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
324 // Register it for single object and single process either netipimd /
325 // host-ipmid
326 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
327 {
328 log<level::DEBUG>("Registering channel signal handler.");
329 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
330 bus,
331 sdbusplus::bus::match::rules::path_namespace(
332 networkIntfObjectBasePath) +
333 sdbusplus::bus::match::rules::type::signal() +
334 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
335 sdbusplus::bus::match::rules::interface(
336 dBusPropertiesInterface) +
337 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
338 [&](sdbusplus::message::message& msg) {
339 DbusChObjProperties props;
340 std::string iface;
341 std::string path = msg.get_path();
342 msg.read(iface, props);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800343 processChAccessPropChange(path, props);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530344 });
345 signalHndlrObjectState = true;
346 }
347}
348
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530349bool ChannelConfig::isValidChannel(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530350{
351 if (chNum > maxIpmiChannels)
352 {
353 log<level::DEBUG>("Invalid channel ID - Out of range");
354 return false;
355 }
356
357 if (channelData[chNum].isChValid == false)
358 {
359 log<level::DEBUG>("Channel is not valid");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530360 }
361
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800362 return channelData[chNum].isChValid;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530363}
364
365EChannelSessSupported
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530366 ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530367{
368 EChannelSessSupported chSessSupport =
369 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
370 return chSessSupport;
371}
372
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530373bool ChannelConfig::isValidAuthType(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530374 const EAuthType& authType)
375{
376 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
377 {
378 log<level::DEBUG>("Invalid authentication type");
379 return false;
380 }
381
382 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
383 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
384 {
385 log<level::DEBUG>("Authentication type is not supported.");
386 return false;
387 }
388
389 return true;
390}
391
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530392std::string ChannelConfig::getChannelName(const uint8_t chNum)
393{
394 return channelData[chNum].chName;
395}
396
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530397int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530398{
399 // TODO: TEMPORARY FIX
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800400 // Channels active session count is managed separately
AppaRao Puli071f3f22018-05-24 16:45:30 +0530401 // by monitoring channel session which includes LAN and
402 // RAKP layer changes. This will be updated, once the
403 // authentication part is implemented.
404 return channelData[chNum].activeSessCount;
405}
406
Vernon Mauery58317122018-11-28 11:02:43 -0800407size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
408{
409 return channelData[chNum].maxTransferSize;
410}
411
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530412ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530413 ChannelInfo& chInfo)
414{
415 if (!isValidChannel(chNum))
416 {
417 log<level::DEBUG>("Invalid channel");
418 return IPMI_CC_INVALID_FIELD_REQUEST;
419 }
420
421 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
422 sizeof(channelData[chNum].chInfo),
423 reinterpret_cast<uint8_t*>(&chInfo));
424
425 return IPMI_CC_OK;
426}
427
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530428ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530429 ChannelAccess& chAccessData)
430{
431 if (!isValidChannel(chNum))
432 {
433 log<level::DEBUG>("Invalid channel");
434 return IPMI_CC_INVALID_FIELD_REQUEST;
435 }
436
437 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
438 {
439 log<level::DEBUG>("Session-less channel doesn't have access data.");
440 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
441 }
442
443 if (checkAndReloadVolatileData() != 0)
444 {
445 return IPMI_CC_UNSPECIFIED_ERROR;
446 }
447
448 std::copy_n(
449 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
450 sizeof(channelData[chNum].chAccess.chVolatileData),
451 reinterpret_cast<uint8_t*>(&chAccessData));
452
453 return IPMI_CC_OK;
454}
455
456ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530457 ChannelConfig::setChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530458 const ChannelAccess& chAccessData,
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530459 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530460{
461 if (!isValidChannel(chNum))
462 {
463 log<level::DEBUG>("Invalid channel");
464 return IPMI_CC_INVALID_FIELD_REQUEST;
465 }
466
467 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
468 {
469 log<level::DEBUG>("Session-less channel doesn't have access data.");
470 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
471 }
472
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530473 if (((setFlag & setAccessMode) &&
474 (!isValidAccessMode(chAccessData.accessMode))) ||
475 ((setFlag & setPrivLimit) &&
476 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530477 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530478 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530479 return IPMI_CC_INVALID_FIELD_REQUEST;
480 }
481
482 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
483 channelLock{*channelMutex};
484
485 if (checkAndReloadVolatileData() != 0)
486 {
487 return IPMI_CC_UNSPECIFIED_ERROR;
488 }
489
490 if (setFlag & setAccessMode)
491 {
492 channelData[chNum].chAccess.chVolatileData.accessMode =
493 chAccessData.accessMode;
494 }
495 if (setFlag & setUserAuthEnabled)
496 {
497 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
498 chAccessData.userAuthDisabled;
499 }
500 if (setFlag & setMsgAuthEnabled)
501 {
502 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
503 chAccessData.perMsgAuthDisabled;
504 }
505 if (setFlag & setAlertingEnabled)
506 {
507 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
508 chAccessData.alertingDisabled;
509 }
510 if (setFlag & setPrivLimit)
511 {
512 channelData[chNum].chAccess.chVolatileData.privLimit =
513 chAccessData.privLimit;
514 }
515
516 // Write Volatile data to file
517 if (writeChannelVolatileData() != 0)
518 {
519 log<level::DEBUG>("Failed to update the channel volatile data");
520 return IPMI_CC_UNSPECIFIED_ERROR;
521 }
522 return IPMI_CC_OK;
523}
524
525ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530526 ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530527 ChannelAccess& chAccessData)
528{
529 if (!isValidChannel(chNum))
530 {
531 log<level::DEBUG>("Invalid channel");
532 return IPMI_CC_INVALID_FIELD_REQUEST;
533 }
534
535 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
536 {
537 log<level::DEBUG>("Session-less channel doesn't have access data.");
538 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
539 }
540
541 if (checkAndReloadNVData() != 0)
542 {
543 return IPMI_CC_UNSPECIFIED_ERROR;
544 }
545
546 std::copy_n(reinterpret_cast<uint8_t*>(
547 &channelData[chNum].chAccess.chNonVolatileData),
548 sizeof(channelData[chNum].chAccess.chNonVolatileData),
549 reinterpret_cast<uint8_t*>(&chAccessData));
550
551 return IPMI_CC_OK;
552}
553
554ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530555 const uint8_t chNum, const ChannelAccess& chAccessData,
556 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530557{
558 if (!isValidChannel(chNum))
559 {
560 log<level::DEBUG>("Invalid channel");
561 return IPMI_CC_INVALID_FIELD_REQUEST;
562 }
563
564 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
565 {
566 log<level::DEBUG>("Session-less channel doesn't have access data.");
567 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
568 }
569
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530570 if (((setFlag & setAccessMode) &&
571 (!isValidAccessMode(chAccessData.accessMode))) ||
572 ((setFlag & setPrivLimit) &&
573 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530574 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530575 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530576 return IPMI_CC_INVALID_FIELD_REQUEST;
577 }
578
579 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
580 channelLock{*channelMutex};
581
582 if (checkAndReloadNVData() != 0)
583 {
584 return IPMI_CC_UNSPECIFIED_ERROR;
585 }
586
587 if (setFlag & setAccessMode)
588 {
589 channelData[chNum].chAccess.chNonVolatileData.accessMode =
590 chAccessData.accessMode;
591 }
592 if (setFlag & setUserAuthEnabled)
593 {
594 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
595 chAccessData.userAuthDisabled;
596 }
597 if (setFlag & setMsgAuthEnabled)
598 {
599 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
600 chAccessData.perMsgAuthDisabled;
601 }
602 if (setFlag & setAlertingEnabled)
603 {
604 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
605 chAccessData.alertingDisabled;
606 }
607 if (setFlag & setPrivLimit)
608 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530609 // Send Update to network channel config interfaces over dbus
AppaRao Puli9613ed72018-09-01 23:46:44 +0530610 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530611 std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
612 "/" + channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530613 try
614 {
Johnathan Manteyf92261d2018-12-10 15:49:34 -0800615 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
616 networkChConfigIntfName,
AppaRao Puli9613ed72018-09-01 23:46:44 +0530617 privilegePropertyString, privStr))
618 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530619 log<level::DEBUG>(
620 "Network interface does not exist",
621 entry("INTERFACE:%s", channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530622 return IPMI_CC_UNSPECIFIED_ERROR;
623 }
624 }
625 catch (const sdbusplus::exception::SdBusError& e)
626 {
627 log<level::ERR>("Exception: Network interface does not exist");
628 return IPMI_CC_INVALID_FIELD_REQUEST;
629 }
630 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530631 channelData[chNum].chAccess.chNonVolatileData.privLimit =
632 chAccessData.privLimit;
633 }
634
635 // Write persistent data to file
636 if (writeChannelPersistData() != 0)
637 {
638 log<level::DEBUG>("Failed to update the presist data file");
639 return IPMI_CC_UNSPECIFIED_ERROR;
640 }
641 return IPMI_CC_OK;
642}
643
644ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530645 ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530646 uint8_t& authTypeSupported)
647{
648 if (!isValidChannel(chNum))
649 {
650 log<level::DEBUG>("Invalid channel");
651 return IPMI_CC_INVALID_FIELD_REQUEST;
652 }
653
654 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
655 return IPMI_CC_OK;
656}
657
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530658ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
659 const uint8_t priv,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530660 EAuthType& authType)
661{
662 if (!isValidChannel(chNum))
663 {
664 log<level::DEBUG>("Invalid channel");
665 return IPMI_CC_INVALID_FIELD_REQUEST;
666 }
667
668 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
669 {
670 log<level::DEBUG>("Sessionless channel doesn't have access data.");
671 return IPMI_CC_INVALID_FIELD_REQUEST;
672 }
673
674 if (!isValidPrivLimit(priv))
675 {
676 log<level::DEBUG>("Invalid privilege specified.");
677 return IPMI_CC_INVALID_FIELD_REQUEST;
678 }
679
680 // TODO: Hardcoded for now. Need to implement.
681 authType = EAuthType::none;
682
683 return IPMI_CC_OK;
684}
685
686std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
687{
688 struct stat fileStat;
689 if (stat(fileName.c_str(), &fileStat) != 0)
690 {
691 log<level::DEBUG>("Error in getting last updated time stamp");
692 return -EIO;
693 }
694 return fileStat.st_mtime;
695}
696
697EChannelAccessMode
698 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
699{
700 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
701 if (iter == accessModeList.end())
702 {
703 log<level::ERR>("Invalid access mode.",
704 entry("MODE_STR=%s", mode.c_str()));
705 throw std::invalid_argument("Invalid access mode.");
706 }
707
708 return static_cast<EChannelAccessMode>(
709 std::distance(accessModeList.begin(), iter));
710}
711
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530712std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530713{
714 if (accessModeList.size() <= value)
715 {
716 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
717 throw std::invalid_argument("Invalid access mode.");
718 }
719
720 return accessModeList.at(value);
721}
722
723CommandPrivilege
724 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
725{
726 auto iter = std::find(privList.begin(), privList.end(), value);
727 if (iter == privList.end())
728 {
729 log<level::ERR>("Invalid privilege.",
730 entry("PRIV_STR=%s", value.c_str()));
731 throw std::invalid_argument("Invalid privilege.");
732 }
733
734 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
735}
736
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530737std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530738{
739 if (privList.size() <= value)
740 {
741 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
742 throw std::invalid_argument("Invalid privilege.");
743 }
744
745 return privList.at(value);
746}
747
748EChannelSessSupported
749 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
750{
751 auto iter =
752 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
753 if (iter == sessionSupportList.end())
754 {
755 log<level::ERR>("Invalid session supported.",
756 entry("SESS_STR=%s", value.c_str()));
757 throw std::invalid_argument("Invalid session supported.");
758 }
759
760 return static_cast<EChannelSessSupported>(
761 std::distance(sessionSupportList.begin(), iter));
762}
763
764EChannelMediumType
765 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
766{
767 std::unordered_map<std::string, EChannelMediumType>::iterator it =
768 mediumTypeMap.find(value);
769 if (it == mediumTypeMap.end())
770 {
771 log<level::ERR>("Invalid medium type.",
772 entry("MEDIUM_STR=%s", value.c_str()));
773 throw std::invalid_argument("Invalid medium type.");
774 }
775
776 return static_cast<EChannelMediumType>(it->second);
777}
778
779EChannelProtocolType
780 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
781{
782 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
783 protocolTypeMap.find(value);
784 if (it == protocolTypeMap.end())
785 {
786 log<level::ERR>("Invalid protocol type.",
787 entry("PROTO_STR=%s", value.c_str()));
788 throw std::invalid_argument("Invalid protocol type.");
789 }
790
791 return static_cast<EChannelProtocolType>(it->second);
792}
793
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530794uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
ssekarf4b2b092018-07-25 18:49:08 +0530795{
796
797 // TODO: There is limitation in current design. we cannot detect exact
798 // LAN interface(eth0 or eth1) so Implementation may be updated
799 // when there is any design update to figure out all the interfaces
800 // independently based on the message.
801
802 static uint8_t curChannel = 0xFF;
803
804 if (curChannel == 0xFF)
805 {
806 auto it = interfaceMap.find(getInterfaceIndex());
807 if (it == interfaceMap.end())
808 {
809 log<level::ERR>("Invalid Interface type ",
810 entry("InterfaceIndex: %d", getInterfaceIndex()));
811 throw std::invalid_argument("Invalid interface type.");
812 }
813
814 for (auto& channel : channelData)
815 {
816 std::string& interfaceName = it->second;
817 if (channel.chName == interfaceName)
818 {
819 curChannel = channel.chID;
820 break;
821 }
822 }
823 }
Richard Marian Thomaiyara39208e2018-12-08 17:27:11 +0530824 return ((chNum == currentChNum) ? curChannel : chNum);
ssekarf4b2b092018-07-25 18:49:08 +0530825}
826
AppaRao Puli071f3f22018-05-24 16:45:30 +0530827Json ChannelConfig::readJsonFile(const std::string& configFile)
828{
829 std::ifstream jsonFile(configFile);
830 if (!jsonFile.good())
831 {
832 log<level::ERR>("JSON file not found");
833 return nullptr;
834 }
835
836 Json data = nullptr;
837 try
838 {
839 data = Json::parse(jsonFile, nullptr, false);
840 }
841 catch (Json::parse_error& e)
842 {
843 log<level::DEBUG>("Corrupted channel config.",
844 entry("MSG: %s", e.what()));
845 throw std::runtime_error("Corrupted channel config file");
846 }
847
848 return data;
849}
850
851int ChannelConfig::writeJsonFile(const std::string& configFile,
852 const Json& jsonData)
853{
854 std::ofstream jsonFile(configFile);
855 if (!jsonFile.good())
856 {
857 log<level::ERR>("JSON file not found");
858 return -EIO;
859 }
860
861 // Write JSON to file
862 jsonFile << jsonData;
863
864 jsonFile.flush();
865 return 0;
866}
867
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530868void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530869 const std::string& chName)
870{
871 channelData[chNum].chName = chName;
872 channelData[chNum].chID = chNum;
873 channelData[chNum].isChValid = false;
874 channelData[chNum].activeSessCount = 0;
875
876 channelData[chNum].chInfo.mediumType = defaultMediumType;
877 channelData[chNum].chInfo.protocolType = defaultProtocolType;
878 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
879 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
880 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
881}
882
883int ChannelConfig::loadChannelConfig()
884{
885 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
886 channelLock{*channelMutex};
887
888 Json data = readJsonFile(channelConfigDefaultFilename);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800889 if (data.empty())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530890 {
891 log<level::DEBUG>("Error in opening IPMI Channel data file");
892 return -EIO;
893 }
894
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800895 channelData.fill(ChannelProperties{});
896
897 for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530898 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800899 try
AppaRao Puli071f3f22018-05-24 16:45:30 +0530900 {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530901 std::string chKey = std::to_string(chNum);
902 Json jsonChData = data[chKey].get<Json>();
903 if (jsonChData.is_null())
904 {
905 log<level::WARNING>(
906 "Channel not configured so loading default.",
907 entry("CHANNEL_NUM:%d", chNum));
908 // If user didn't want to configure specific channel (say
909 // reserved channel), then load that index with default values.
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800910 setDefaultChannelConfig(chNum, defaultChannelName);
911 continue;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530912 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800913 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
914 if (jsonChInfo.is_null())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530915 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800916 log<level::ERR>("Invalid/corrupted channel config file");
917 return -EBADMSG;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530918 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800919
920 ChannelProperties& chData = channelData[chNum];
921 chData.chName = jsonChData[nameString].get<std::string>();
922 chData.chID = chNum;
923 chData.isChValid = jsonChData[isValidString].get<bool>();
924 chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
925 chData.maxTransferSize =
926 jsonChData.value(maxTransferSizeString, smallChannelSize);
927 std::string medTypeStr =
928 jsonChInfo[mediumTypeString].get<std::string>();
929 chData.chInfo.mediumType =
930 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
931 std::string protoTypeStr =
932 jsonChInfo[protocolTypeString].get<std::string>();
933 chData.chInfo.protocolType =
934 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
935 std::string sessStr =
936 jsonChInfo[sessionSupportedString].get<std::string>();
937 chData.chInfo.sessionSupported =
938 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
939 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
940 chData.chInfo.authTypeSupported = defaultAuthType;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530941 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800942 catch (const Json::exception& e)
943 {
944 log<level::DEBUG>("Json Exception caught.",
945 entry("MSG:%s", e.what()));
946 return -EBADMSG;
947 }
948 catch (const std::invalid_argument& e)
949 {
950 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
951 return -EBADMSG;
952 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530953 }
954
955 return 0;
956}
957
958int ChannelConfig::readChannelVolatileData()
959{
960 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
961 channelLock{*channelMutex};
962
963 Json data = readJsonFile(channelVolatileDataFilename);
964 if (data == nullptr)
965 {
966 log<level::DEBUG>("Error in opening IPMI Channel data file");
967 return -EIO;
968 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530969 try
970 {
971 // Fill in global structure
972 for (auto it = data.begin(); it != data.end(); ++it)
973 {
974 std::string chKey = it.key();
975 uint8_t chNum = std::stoi(chKey, nullptr, 10);
976 if ((chNum < 0) || (chNum > maxIpmiChannels))
977 {
978 log<level::DEBUG>(
979 "Invalid channel access entry in config file");
980 throw std::out_of_range("Out of range - channel number");
981 }
982 Json jsonChData = it.value();
983 if (!jsonChData.is_null())
984 {
985 std::string accModeStr =
986 jsonChData[accessModeString].get<std::string>();
987 channelData[chNum].chAccess.chVolatileData.accessMode =
988 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
989 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
990 jsonChData[userAuthDisabledString].get<bool>();
991 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
992 jsonChData[perMsgAuthDisabledString].get<bool>();
993 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
994 jsonChData[alertingDisabledString].get<bool>();
995 std::string privStr =
996 jsonChData[privLimitString].get<std::string>();
997 channelData[chNum].chAccess.chVolatileData.privLimit =
998 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
999 }
1000 else
1001 {
1002 log<level::ERR>(
1003 "Invalid/corrupted volatile channel access file",
1004 entry("FILE: %s", channelVolatileDataFilename));
1005 throw std::runtime_error(
1006 "Corrupted volatile channel access file");
1007 }
1008 }
1009 }
1010 catch (const Json::exception& e)
1011 {
1012 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1013 throw std::runtime_error("Corrupted volatile channel access file");
1014 }
1015 catch (const std::invalid_argument& e)
1016 {
1017 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
1018 throw std::runtime_error("Corrupted volatile channel access file");
1019 }
1020
1021 // Update the timestamp
1022 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1023 return 0;
1024}
1025
1026int ChannelConfig::readChannelPersistData()
1027{
1028 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1029 channelLock{*channelMutex};
1030
1031 Json data = readJsonFile(channelNvDataFilename);
1032 if (data == nullptr)
1033 {
1034 log<level::DEBUG>("Error in opening IPMI Channel data file");
1035 return -EIO;
1036 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301037 try
1038 {
1039 // Fill in global structure
1040 for (auto it = data.begin(); it != data.end(); ++it)
1041 {
1042 std::string chKey = it.key();
1043 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1044 if ((chNum < 0) || (chNum > maxIpmiChannels))
1045 {
1046 log<level::DEBUG>(
1047 "Invalid channel access entry in config file");
1048 throw std::out_of_range("Out of range - channel number");
1049 }
1050 Json jsonChData = it.value();
1051 if (!jsonChData.is_null())
1052 {
1053 std::string accModeStr =
1054 jsonChData[accessModeString].get<std::string>();
1055 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1056 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1057 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1058 jsonChData[userAuthDisabledString].get<bool>();
1059 channelData[chNum]
1060 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1061 jsonChData[perMsgAuthDisabledString].get<bool>();
1062 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1063 jsonChData[alertingDisabledString].get<bool>();
1064 std::string privStr =
1065 jsonChData[privLimitString].get<std::string>();
1066 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1067 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1068 }
1069 else
1070 {
1071 log<level::ERR>("Invalid/corrupted nv channel access file",
1072 entry("FILE:%s", channelNvDataFilename));
1073 throw std::runtime_error("Corrupted nv channel access file");
1074 }
1075 }
1076 }
1077 catch (const Json::exception& e)
1078 {
1079 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1080 throw std::runtime_error("Corrupted nv channel access file");
1081 }
1082 catch (const std::invalid_argument& e)
1083 {
1084 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1085 throw std::runtime_error("Corrupted nv channel access file");
1086 }
1087
1088 // Update the timestamp
1089 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1090 return 0;
1091}
1092
1093int ChannelConfig::writeChannelVolatileData()
1094{
1095 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1096 channelLock{*channelMutex};
1097 Json outData;
1098
1099 try
1100 {
1101 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1102 {
1103 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1104 {
1105 Json jsonObj;
1106 std::string chKey = std::to_string(chNum);
1107 std::string accModeStr = convertToAccessModeString(
1108 channelData[chNum].chAccess.chVolatileData.accessMode);
1109 jsonObj[accessModeString] = accModeStr;
1110 jsonObj[userAuthDisabledString] =
1111 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1112 jsonObj[perMsgAuthDisabledString] =
1113 channelData[chNum]
1114 .chAccess.chVolatileData.perMsgAuthDisabled;
1115 jsonObj[alertingDisabledString] =
1116 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1117 std::string privStr = convertToPrivLimitString(
1118 channelData[chNum].chAccess.chVolatileData.privLimit);
1119 jsonObj[privLimitString] = privStr;
1120
1121 outData[chKey] = jsonObj;
1122 }
1123 }
1124 }
1125 catch (const std::invalid_argument& e)
1126 {
1127 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1128 return -EINVAL;
1129 }
1130
1131 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1132 {
1133 log<level::DEBUG>("Error in write JSON data to file");
1134 return -EIO;
1135 }
1136
1137 // Update the timestamp
1138 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1139 return 0;
1140}
1141
1142int ChannelConfig::writeChannelPersistData()
1143{
1144 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1145 channelLock{*channelMutex};
1146 Json outData;
1147
1148 try
1149 {
1150 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1151 {
1152 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1153 {
1154 Json jsonObj;
1155 std::string chKey = std::to_string(chNum);
1156 std::string accModeStr = convertToAccessModeString(
1157 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1158 jsonObj[accessModeString] = accModeStr;
1159 jsonObj[userAuthDisabledString] =
1160 channelData[chNum]
1161 .chAccess.chNonVolatileData.userAuthDisabled;
1162 jsonObj[perMsgAuthDisabledString] =
1163 channelData[chNum]
1164 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1165 jsonObj[alertingDisabledString] =
1166 channelData[chNum]
1167 .chAccess.chNonVolatileData.alertingDisabled;
1168 std::string privStr = convertToPrivLimitString(
1169 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1170 jsonObj[privLimitString] = privStr;
1171
1172 outData[chKey] = jsonObj;
1173 }
1174 }
1175 }
1176 catch (const std::invalid_argument& e)
1177 {
1178 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1179 return -EINVAL;
1180 }
1181
1182 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1183 {
1184 log<level::DEBUG>("Error in write JSON data to file");
1185 return -EIO;
1186 }
1187
1188 // Update the timestamp
1189 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1190 return 0;
1191}
1192
1193int ChannelConfig::checkAndReloadNVData()
1194{
1195 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1196 int ret = 0;
1197 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1198 {
1199 try
1200 {
1201 ret = readChannelPersistData();
1202 }
1203 catch (const std::exception& e)
1204 {
1205 log<level::ERR>("Exception caught in readChannelPersistData.",
1206 entry("MSG=%s", e.what()));
1207 ret = -EIO;
1208 }
1209 }
1210 return ret;
1211}
1212
1213int ChannelConfig::checkAndReloadVolatileData()
1214{
1215 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1216 int ret = 0;
1217 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1218 {
1219 try
1220 {
1221 ret = readChannelVolatileData();
1222 }
1223 catch (const std::exception& e)
1224 {
1225 log<level::ERR>("Exception caught in readChannelVolatileData.",
1226 entry("MSG=%s", e.what()));
1227 ret = -EIO;
1228 }
1229 }
1230 return ret;
1231}
1232
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001233int ChannelConfig::setDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301234 const std::string& objPath,
1235 const std::string& interface,
1236 const std::string& property,
1237 const DbusVariant& value)
1238{
1239 try
1240 {
1241 auto method =
1242 bus.new_method_call(service.c_str(), objPath.c_str(),
1243 "org.freedesktop.DBus.Properties", "Set");
1244
1245 method.append(interface, property, value);
1246
1247 auto reply = bus.call(method);
1248 }
1249 catch (const sdbusplus::exception::SdBusError& e)
1250 {
1251 log<level::DEBUG>("set-property failed",
1252 entry("SERVICE:%s", service.c_str()),
1253 entry("OBJPATH:%s", objPath.c_str()),
1254 entry("INTERFACE:%s", interface.c_str()),
1255 entry("PROP:%s", property.c_str()));
1256 return -EIO;
1257 }
1258
1259 return 0;
1260}
1261
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001262int ChannelConfig::getDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301263 const std::string& objPath,
1264 const std::string& interface,
1265 const std::string& property,
1266 DbusVariant& value)
1267{
1268 try
1269 {
1270 auto method =
1271 bus.new_method_call(service.c_str(), objPath.c_str(),
1272 "org.freedesktop.DBus.Properties", "Get");
1273
1274 method.append(interface, property);
1275
1276 auto reply = bus.call(method);
1277 reply.read(value);
1278 }
1279 catch (const sdbusplus::exception::SdBusError& e)
1280 {
1281 log<level::DEBUG>("get-property failed",
1282 entry("SERVICE:%s", service.c_str()),
1283 entry("OBJPATH:%s", objPath.c_str()),
1284 entry("INTERFACE:%s", interface.c_str()),
1285 entry("PROP:%s", property.c_str()));
1286 return -EIO;
1287 }
1288 return 0;
1289}
1290
1291int ChannelConfig::syncNetworkChannelConfig()
1292{
1293 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1294 channelLock{*channelMutex};
1295 bool isUpdated = false;
1296 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1297 {
1298 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1299 {
1300 std::string intfPrivStr;
1301 try
1302 {
AppaRao Puli9613ed72018-09-01 23:46:44 +05301303 std::string networkIntfObj =
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301304 std::string(networkIntfObjectBasePath) + "/" +
1305 channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +05301306 DbusVariant variant;
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001307 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301308 networkChConfigIntfName,
1309 privilegePropertyString, variant))
1310 {
1311 log<level::DEBUG>("Network interface does not exist",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301312 entry("INTERFACE:%s",
1313 channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301314 continue;
1315 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001316 intfPrivStr = variant_ns::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301317 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001318 catch (const variant_ns::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301319 {
1320 log<level::DEBUG>(
1321 "exception: Network interface does not exist");
1322 continue;
1323 }
1324 catch (const sdbusplus::exception::SdBusError& e)
1325 {
1326 log<level::DEBUG>(
1327 "exception: Network interface does not exist");
1328 continue;
1329 }
1330
1331 uint8_t intfPriv =
1332 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1333 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1334 intfPriv)
1335 {
1336 isUpdated = true;
1337 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1338 intfPriv;
1339 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1340 }
1341 }
1342 }
1343
1344 if (isUpdated)
1345 {
1346 // Write persistent data to file
1347 if (writeChannelPersistData() != 0)
1348 {
1349 log<level::DEBUG>("Failed to update the persistent data file");
1350 return -EIO;
1351 }
1352 // Write Volatile data to file
1353 if (writeChannelVolatileData() != 0)
1354 {
1355 log<level::DEBUG>("Failed to update the channel volatile data");
1356 return -EIO;
1357 }
1358 }
1359
1360 return 0;
1361}
1362
AppaRao Puli071f3f22018-05-24 16:45:30 +05301363void ChannelConfig::initChannelPersistData()
1364{
1365 /* Always read the channel config */
1366 if (loadChannelConfig() != 0)
1367 {
1368 log<level::ERR>("Failed to read channel config file");
1369 throw std::ios_base::failure("Failed to load channel configuration");
1370 }
1371
1372 /* Populate the channel persist data */
1373 if (readChannelPersistData() != 0)
1374 {
1375 // Copy default NV data to RW location
1376 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1377 channelNvDataFilename);
1378
1379 // Load the channel access NV data
1380 if (readChannelPersistData() != 0)
1381 {
1382 log<level::ERR>("Failed to read channel access NV data");
1383 throw std::ios_base::failure(
1384 "Failed to read channel access NV configuration");
1385 }
1386 }
1387
1388 // First check the volatile data file
1389 // If not present, load the default values
1390 if (readChannelVolatileData() != 0)
1391 {
1392 // Copy default volatile data to temporary location
1393 // NV file(channelNvDataFilename) must have created by now.
1394 std::experimental::filesystem::copy_file(channelNvDataFilename,
1395 channelVolatileDataFilename);
1396
1397 // Load the channel access volatile data
1398 if (readChannelVolatileData() != 0)
1399 {
1400 log<level::ERR>("Failed to read channel access volatile data");
1401 throw std::ios_base::failure(
1402 "Failed to read channel access volatile configuration");
1403 }
1404 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301405
1406 // Synchronize the channel config(priv) with network channel
1407 // configuration(priv) over dbus
1408 if (syncNetworkChannelConfig() != 0)
1409 {
1410 log<level::ERR>(
1411 "Failed to synchronize data with network channel config over dbus");
1412 throw std::ios_base::failure(
1413 "Failed to synchronize data with network channel config over dbus");
1414 }
1415
1416 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301417 return;
1418}
1419
1420} // namespace ipmi