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