blob: 45a703a8a5a2563997a3b0277d02e830bcf1dea0 [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
AppaRao Puli9613ed72018-09-01 23:46:44 +0530140std::string getNetIntfFromPath(const std::string& path)
141{
142 std::size_t pos = path.find(networkIntfObjectBasePath);
143 if (pos == std::string::npos)
144 {
145 log<level::ERR>("Invalid interface path.",
146 entry("PATH:%s", path.c_str()));
147 throw std::invalid_argument("Invalid interface path");
148 }
149 std::string intfName =
150 path.substr(pos + strlen(networkIntfObjectBasePath) + 1);
151 return intfName;
152}
153
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800154void ChannelConfig::processChAccessPropChange(
155 const std::string& path, const DbusChObjProperties& chProperties)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530156{
157 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530158 std::string channelName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530159 try
160 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530161 channelName = getNetIntfFromPath(path);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530162 }
163 catch (const std::invalid_argument& e)
164 {
165 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
166 return;
167 }
168
169 // Get the MaxPrivilege property value from the signal
170 std::string intfPrivStr;
171 std::string propName;
172 for (const auto& prop : chProperties)
173 {
174 if (prop.first == privilegePropertyString)
175 {
176 propName = privilegePropertyString;
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800177 intfPrivStr = variant_ns::get<std::string>(prop.second);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530178 break;
179 }
180 }
181
182 if (propName != privilegePropertyString)
183 {
184 log<level::ERR>("Unknown signal caught.");
185 return;
186 }
187
188 if (intfPrivStr.empty())
189 {
190 log<level::ERR>("Invalid privilege string.",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530191 entry("INTF:%s", channelName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530192 return;
193 }
194
195 uint8_t intfPriv = 0;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530196 try
197 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800198 intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530199 }
200 catch (const std::invalid_argument& e)
201 {
202 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
203 return;
204 }
205
206 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800207 channelLock{*channelMutex};
AppaRao Puli9613ed72018-09-01 23:46:44 +0530208 uint8_t chNum = 0;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530209 // Get the channel number based on the channel name.
210 for (chNum = 0; chNum < maxIpmiChannels; chNum++)
211 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800212 if (channelData[chNum].chName == channelName)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530213 {
214 break;
215 }
216 }
217 if (chNum >= maxIpmiChannels)
218 {
219 log<level::ERR>("Invalid interface in signal path");
220 return;
221 }
222
223 // skip updating the values, if this property change originated from IPMI.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800224 if (signalFlag & (1 << chNum))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530225 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800226 signalFlag &= ~(1 << chNum);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530227 log<level::DEBUG>("Request originated from IPMI so ignoring signal");
228 return;
229 }
230
231 // Update both volatile & Non-volatile, if there is mismatch.
232 // as property change other than IPMI, has to update both volatile &
233 // non-volatile data.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800234 checkAndReloadVolatileData();
235 checkAndReloadNVData();
236 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530237 {
238 // Update NV data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800239 channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
240 if (writeChannelPersistData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530241 {
242 log<level::ERR>("Failed to update the persist data file");
243 return;
244 }
245
246 // Update Volatile data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800247 if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530248 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800249 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
250 if (writeChannelVolatileData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530251 {
252 log<level::ERR>("Failed to update the volatile data file");
253 return;
254 }
255 }
256 }
257
258 return;
259}
260
AppaRao Puli071f3f22018-05-24 16:45:30 +0530261ChannelConfig& getChannelConfigObject()
262{
263 static ChannelConfig channelConfig;
264 return channelConfig;
265}
266
AppaRao Puli9613ed72018-09-01 23:46:44 +0530267ChannelConfig::~ChannelConfig()
268{
269 if (signalHndlrObjectState)
270 {
271 chPropertiesSignal.reset();
272 sigHndlrLock.unlock();
273 }
274}
275
AppaRao Puli071f3f22018-05-24 16:45:30 +0530276ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
277{
278 std::ofstream mutexCleanUpFile;
279 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
280 std::ofstream::out | std::ofstream::app);
281 if (!mutexCleanUpFile.good())
282 {
283 log<level::DEBUG>("Unable to open mutex cleanup file");
284 return;
285 }
286 mutexCleanUpFile.close();
287 mutexCleanupLock =
288 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
289 if (mutexCleanupLock.try_lock())
290 {
291 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
292 channelMutex =
293 std::make_unique<boost::interprocess::named_recursive_mutex>(
294 boost::interprocess::open_or_create, ipmiChannelMutex);
295 mutexCleanupLock.lock_sharable();
296 }
297 else
298 {
299 mutexCleanupLock.lock_sharable();
300 channelMutex =
301 std::make_unique<boost::interprocess::named_recursive_mutex>(
302 boost::interprocess::open_or_create, ipmiChannelMutex);
303 }
304
305 initChannelPersistData();
AppaRao Puli9613ed72018-09-01 23:46:44 +0530306
307 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
308 // Register it for single object and single process either netipimd /
309 // host-ipmid
310 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
311 {
312 log<level::DEBUG>("Registering channel signal handler.");
313 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
314 bus,
315 sdbusplus::bus::match::rules::path_namespace(
316 networkIntfObjectBasePath) +
317 sdbusplus::bus::match::rules::type::signal() +
318 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
319 sdbusplus::bus::match::rules::interface(
320 dBusPropertiesInterface) +
321 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
322 [&](sdbusplus::message::message& msg) {
323 DbusChObjProperties props;
324 std::string iface;
325 std::string path = msg.get_path();
326 msg.read(iface, props);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800327 processChAccessPropChange(path, props);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530328 });
329 signalHndlrObjectState = true;
330 }
331}
332
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530333bool ChannelConfig::isValidChannel(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530334{
335 if (chNum > maxIpmiChannels)
336 {
337 log<level::DEBUG>("Invalid channel ID - Out of range");
338 return false;
339 }
340
341 if (channelData[chNum].isChValid == false)
342 {
343 log<level::DEBUG>("Channel is not valid");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530344 }
345
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800346 return channelData[chNum].isChValid;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530347}
348
349EChannelSessSupported
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530350 ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530351{
352 EChannelSessSupported chSessSupport =
353 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
354 return chSessSupport;
355}
356
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530357bool ChannelConfig::isValidAuthType(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530358 const EAuthType& authType)
359{
360 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
361 {
362 log<level::DEBUG>("Invalid authentication type");
363 return false;
364 }
365
366 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
367 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
368 {
369 log<level::DEBUG>("Authentication type is not supported.");
370 return false;
371 }
372
373 return true;
374}
375
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530376std::string ChannelConfig::getChannelName(const uint8_t chNum)
377{
378 return channelData[chNum].chName;
379}
380
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530381int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530382{
383 // TODO: TEMPORARY FIX
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800384 // Channels active session count is managed separately
AppaRao Puli071f3f22018-05-24 16:45:30 +0530385 // by monitoring channel session which includes LAN and
386 // RAKP layer changes. This will be updated, once the
387 // authentication part is implemented.
388 return channelData[chNum].activeSessCount;
389}
390
Vernon Mauery58317122018-11-28 11:02:43 -0800391size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
392{
393 return channelData[chNum].maxTransferSize;
394}
395
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530396ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530397 ChannelInfo& chInfo)
398{
399 if (!isValidChannel(chNum))
400 {
401 log<level::DEBUG>("Invalid channel");
402 return IPMI_CC_INVALID_FIELD_REQUEST;
403 }
404
405 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
406 sizeof(channelData[chNum].chInfo),
407 reinterpret_cast<uint8_t*>(&chInfo));
408
409 return IPMI_CC_OK;
410}
411
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530412ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530413 ChannelAccess& chAccessData)
414{
415 if (!isValidChannel(chNum))
416 {
417 log<level::DEBUG>("Invalid channel");
418 return IPMI_CC_INVALID_FIELD_REQUEST;
419 }
420
421 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
422 {
423 log<level::DEBUG>("Session-less channel doesn't have access data.");
424 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
425 }
426
427 if (checkAndReloadVolatileData() != 0)
428 {
429 return IPMI_CC_UNSPECIFIED_ERROR;
430 }
431
432 std::copy_n(
433 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
434 sizeof(channelData[chNum].chAccess.chVolatileData),
435 reinterpret_cast<uint8_t*>(&chAccessData));
436
437 return IPMI_CC_OK;
438}
439
440ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530441 ChannelConfig::setChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530442 const ChannelAccess& chAccessData,
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530443 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530444{
445 if (!isValidChannel(chNum))
446 {
447 log<level::DEBUG>("Invalid channel");
448 return IPMI_CC_INVALID_FIELD_REQUEST;
449 }
450
451 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
452 {
453 log<level::DEBUG>("Session-less channel doesn't have access data.");
454 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
455 }
456
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530457 if (((setFlag & setAccessMode) &&
458 (!isValidAccessMode(chAccessData.accessMode))) ||
459 ((setFlag & setPrivLimit) &&
460 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530461 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530462 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530463 return IPMI_CC_INVALID_FIELD_REQUEST;
464 }
465
466 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
467 channelLock{*channelMutex};
468
469 if (checkAndReloadVolatileData() != 0)
470 {
471 return IPMI_CC_UNSPECIFIED_ERROR;
472 }
473
474 if (setFlag & setAccessMode)
475 {
476 channelData[chNum].chAccess.chVolatileData.accessMode =
477 chAccessData.accessMode;
478 }
479 if (setFlag & setUserAuthEnabled)
480 {
481 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
482 chAccessData.userAuthDisabled;
483 }
484 if (setFlag & setMsgAuthEnabled)
485 {
486 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
487 chAccessData.perMsgAuthDisabled;
488 }
489 if (setFlag & setAlertingEnabled)
490 {
491 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
492 chAccessData.alertingDisabled;
493 }
494 if (setFlag & setPrivLimit)
495 {
496 channelData[chNum].chAccess.chVolatileData.privLimit =
497 chAccessData.privLimit;
498 }
499
500 // Write Volatile data to file
501 if (writeChannelVolatileData() != 0)
502 {
503 log<level::DEBUG>("Failed to update the channel volatile data");
504 return IPMI_CC_UNSPECIFIED_ERROR;
505 }
506 return IPMI_CC_OK;
507}
508
509ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530510 ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530511 ChannelAccess& chAccessData)
512{
513 if (!isValidChannel(chNum))
514 {
515 log<level::DEBUG>("Invalid channel");
516 return IPMI_CC_INVALID_FIELD_REQUEST;
517 }
518
519 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
520 {
521 log<level::DEBUG>("Session-less channel doesn't have access data.");
522 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
523 }
524
525 if (checkAndReloadNVData() != 0)
526 {
527 return IPMI_CC_UNSPECIFIED_ERROR;
528 }
529
530 std::copy_n(reinterpret_cast<uint8_t*>(
531 &channelData[chNum].chAccess.chNonVolatileData),
532 sizeof(channelData[chNum].chAccess.chNonVolatileData),
533 reinterpret_cast<uint8_t*>(&chAccessData));
534
535 return IPMI_CC_OK;
536}
537
538ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530539 const uint8_t chNum, const ChannelAccess& chAccessData,
540 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530541{
542 if (!isValidChannel(chNum))
543 {
544 log<level::DEBUG>("Invalid channel");
545 return IPMI_CC_INVALID_FIELD_REQUEST;
546 }
547
548 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
549 {
550 log<level::DEBUG>("Session-less channel doesn't have access data.");
551 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
552 }
553
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530554 if (((setFlag & setAccessMode) &&
555 (!isValidAccessMode(chAccessData.accessMode))) ||
556 ((setFlag & setPrivLimit) &&
557 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530558 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530559 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530560 return IPMI_CC_INVALID_FIELD_REQUEST;
561 }
562
563 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
564 channelLock{*channelMutex};
565
566 if (checkAndReloadNVData() != 0)
567 {
568 return IPMI_CC_UNSPECIFIED_ERROR;
569 }
570
571 if (setFlag & setAccessMode)
572 {
573 channelData[chNum].chAccess.chNonVolatileData.accessMode =
574 chAccessData.accessMode;
575 }
576 if (setFlag & setUserAuthEnabled)
577 {
578 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
579 chAccessData.userAuthDisabled;
580 }
581 if (setFlag & setMsgAuthEnabled)
582 {
583 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
584 chAccessData.perMsgAuthDisabled;
585 }
586 if (setFlag & setAlertingEnabled)
587 {
588 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
589 chAccessData.alertingDisabled;
590 }
591 if (setFlag & setPrivLimit)
592 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530593 // Send Update to network channel config interfaces over dbus
AppaRao Puli9613ed72018-09-01 23:46:44 +0530594 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530595 std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
596 "/" + channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530597 try
598 {
Johnathan Manteyf92261d2018-12-10 15:49:34 -0800599 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
600 networkChConfigIntfName,
AppaRao Puli9613ed72018-09-01 23:46:44 +0530601 privilegePropertyString, privStr))
602 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530603 log<level::DEBUG>(
604 "Network interface does not exist",
605 entry("INTERFACE:%s", channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530606 return IPMI_CC_UNSPECIFIED_ERROR;
607 }
608 }
609 catch (const sdbusplus::exception::SdBusError& e)
610 {
611 log<level::ERR>("Exception: Network interface does not exist");
612 return IPMI_CC_INVALID_FIELD_REQUEST;
613 }
614 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530615 channelData[chNum].chAccess.chNonVolatileData.privLimit =
616 chAccessData.privLimit;
617 }
618
619 // Write persistent data to file
620 if (writeChannelPersistData() != 0)
621 {
622 log<level::DEBUG>("Failed to update the presist data file");
623 return IPMI_CC_UNSPECIFIED_ERROR;
624 }
625 return IPMI_CC_OK;
626}
627
628ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530629 ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530630 uint8_t& authTypeSupported)
631{
632 if (!isValidChannel(chNum))
633 {
634 log<level::DEBUG>("Invalid channel");
635 return IPMI_CC_INVALID_FIELD_REQUEST;
636 }
637
638 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
639 return IPMI_CC_OK;
640}
641
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530642ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
643 const uint8_t priv,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530644 EAuthType& authType)
645{
646 if (!isValidChannel(chNum))
647 {
648 log<level::DEBUG>("Invalid channel");
649 return IPMI_CC_INVALID_FIELD_REQUEST;
650 }
651
652 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
653 {
654 log<level::DEBUG>("Sessionless channel doesn't have access data.");
655 return IPMI_CC_INVALID_FIELD_REQUEST;
656 }
657
658 if (!isValidPrivLimit(priv))
659 {
660 log<level::DEBUG>("Invalid privilege specified.");
661 return IPMI_CC_INVALID_FIELD_REQUEST;
662 }
663
664 // TODO: Hardcoded for now. Need to implement.
665 authType = EAuthType::none;
666
667 return IPMI_CC_OK;
668}
669
670std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
671{
672 struct stat fileStat;
673 if (stat(fileName.c_str(), &fileStat) != 0)
674 {
675 log<level::DEBUG>("Error in getting last updated time stamp");
676 return -EIO;
677 }
678 return fileStat.st_mtime;
679}
680
681EChannelAccessMode
682 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
683{
684 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
685 if (iter == accessModeList.end())
686 {
687 log<level::ERR>("Invalid access mode.",
688 entry("MODE_STR=%s", mode.c_str()));
689 throw std::invalid_argument("Invalid access mode.");
690 }
691
692 return static_cast<EChannelAccessMode>(
693 std::distance(accessModeList.begin(), iter));
694}
695
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530696std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530697{
698 if (accessModeList.size() <= value)
699 {
700 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
701 throw std::invalid_argument("Invalid access mode.");
702 }
703
704 return accessModeList.at(value);
705}
706
707CommandPrivilege
708 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
709{
710 auto iter = std::find(privList.begin(), privList.end(), value);
711 if (iter == privList.end())
712 {
713 log<level::ERR>("Invalid privilege.",
714 entry("PRIV_STR=%s", value.c_str()));
715 throw std::invalid_argument("Invalid privilege.");
716 }
717
718 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
719}
720
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530721std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530722{
723 if (privList.size() <= value)
724 {
725 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
726 throw std::invalid_argument("Invalid privilege.");
727 }
728
729 return privList.at(value);
730}
731
732EChannelSessSupported
733 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
734{
735 auto iter =
736 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
737 if (iter == sessionSupportList.end())
738 {
739 log<level::ERR>("Invalid session supported.",
740 entry("SESS_STR=%s", value.c_str()));
741 throw std::invalid_argument("Invalid session supported.");
742 }
743
744 return static_cast<EChannelSessSupported>(
745 std::distance(sessionSupportList.begin(), iter));
746}
747
748EChannelMediumType
749 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
750{
751 std::unordered_map<std::string, EChannelMediumType>::iterator it =
752 mediumTypeMap.find(value);
753 if (it == mediumTypeMap.end())
754 {
755 log<level::ERR>("Invalid medium type.",
756 entry("MEDIUM_STR=%s", value.c_str()));
757 throw std::invalid_argument("Invalid medium type.");
758 }
759
760 return static_cast<EChannelMediumType>(it->second);
761}
762
763EChannelProtocolType
764 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
765{
766 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
767 protocolTypeMap.find(value);
768 if (it == protocolTypeMap.end())
769 {
770 log<level::ERR>("Invalid protocol type.",
771 entry("PROTO_STR=%s", value.c_str()));
772 throw std::invalid_argument("Invalid protocol type.");
773 }
774
775 return static_cast<EChannelProtocolType>(it->second);
776}
777
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530778uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
ssekarf4b2b092018-07-25 18:49:08 +0530779{
780
781 // TODO: There is limitation in current design. we cannot detect exact
782 // LAN interface(eth0 or eth1) so Implementation may be updated
783 // when there is any design update to figure out all the interfaces
784 // independently based on the message.
785
786 static uint8_t curChannel = 0xFF;
787
788 if (curChannel == 0xFF)
789 {
790 auto it = interfaceMap.find(getInterfaceIndex());
791 if (it == interfaceMap.end())
792 {
793 log<level::ERR>("Invalid Interface type ",
794 entry("InterfaceIndex: %d", getInterfaceIndex()));
795 throw std::invalid_argument("Invalid interface type.");
796 }
797
798 for (auto& channel : channelData)
799 {
800 std::string& interfaceName = it->second;
801 if (channel.chName == interfaceName)
802 {
803 curChannel = channel.chID;
804 break;
805 }
806 }
807 }
Richard Marian Thomaiyara39208e2018-12-08 17:27:11 +0530808 return ((chNum == currentChNum) ? curChannel : chNum);
ssekarf4b2b092018-07-25 18:49:08 +0530809}
810
AppaRao Puli071f3f22018-05-24 16:45:30 +0530811Json ChannelConfig::readJsonFile(const std::string& configFile)
812{
813 std::ifstream jsonFile(configFile);
814 if (!jsonFile.good())
815 {
816 log<level::ERR>("JSON file not found");
817 return nullptr;
818 }
819
820 Json data = nullptr;
821 try
822 {
823 data = Json::parse(jsonFile, nullptr, false);
824 }
825 catch (Json::parse_error& e)
826 {
827 log<level::DEBUG>("Corrupted channel config.",
828 entry("MSG: %s", e.what()));
829 throw std::runtime_error("Corrupted channel config file");
830 }
831
832 return data;
833}
834
835int ChannelConfig::writeJsonFile(const std::string& configFile,
836 const Json& jsonData)
837{
838 std::ofstream jsonFile(configFile);
839 if (!jsonFile.good())
840 {
841 log<level::ERR>("JSON file not found");
842 return -EIO;
843 }
844
845 // Write JSON to file
846 jsonFile << jsonData;
847
848 jsonFile.flush();
849 return 0;
850}
851
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530852void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530853 const std::string& chName)
854{
855 channelData[chNum].chName = chName;
856 channelData[chNum].chID = chNum;
857 channelData[chNum].isChValid = false;
858 channelData[chNum].activeSessCount = 0;
859
860 channelData[chNum].chInfo.mediumType = defaultMediumType;
861 channelData[chNum].chInfo.protocolType = defaultProtocolType;
862 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
863 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
864 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
865}
866
867int ChannelConfig::loadChannelConfig()
868{
869 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
870 channelLock{*channelMutex};
871
872 Json data = readJsonFile(channelConfigDefaultFilename);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800873 if (data.empty())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530874 {
875 log<level::DEBUG>("Error in opening IPMI Channel data file");
876 return -EIO;
877 }
878
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800879 channelData.fill(ChannelProperties{});
880
881 for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530882 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800883 try
AppaRao Puli071f3f22018-05-24 16:45:30 +0530884 {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530885 std::string chKey = std::to_string(chNum);
886 Json jsonChData = data[chKey].get<Json>();
887 if (jsonChData.is_null())
888 {
889 log<level::WARNING>(
890 "Channel not configured so loading default.",
891 entry("CHANNEL_NUM:%d", chNum));
892 // If user didn't want to configure specific channel (say
893 // reserved channel), then load that index with default values.
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800894 setDefaultChannelConfig(chNum, defaultChannelName);
895 continue;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530896 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800897 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
898 if (jsonChInfo.is_null())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530899 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800900 log<level::ERR>("Invalid/corrupted channel config file");
901 return -EBADMSG;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530902 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800903
904 ChannelProperties& chData = channelData[chNum];
905 chData.chName = jsonChData[nameString].get<std::string>();
906 chData.chID = chNum;
907 chData.isChValid = jsonChData[isValidString].get<bool>();
908 chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
909 chData.maxTransferSize =
910 jsonChData.value(maxTransferSizeString, smallChannelSize);
911 std::string medTypeStr =
912 jsonChInfo[mediumTypeString].get<std::string>();
913 chData.chInfo.mediumType =
914 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
915 std::string protoTypeStr =
916 jsonChInfo[protocolTypeString].get<std::string>();
917 chData.chInfo.protocolType =
918 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
919 std::string sessStr =
920 jsonChInfo[sessionSupportedString].get<std::string>();
921 chData.chInfo.sessionSupported =
922 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
923 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
924 chData.chInfo.authTypeSupported = defaultAuthType;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530925 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800926 catch (const Json::exception& e)
927 {
928 log<level::DEBUG>("Json Exception caught.",
929 entry("MSG:%s", e.what()));
930 return -EBADMSG;
931 }
932 catch (const std::invalid_argument& e)
933 {
934 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
935 return -EBADMSG;
936 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530937 }
938
939 return 0;
940}
941
942int ChannelConfig::readChannelVolatileData()
943{
944 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
945 channelLock{*channelMutex};
946
947 Json data = readJsonFile(channelVolatileDataFilename);
948 if (data == nullptr)
949 {
950 log<level::DEBUG>("Error in opening IPMI Channel data file");
951 return -EIO;
952 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530953 try
954 {
955 // Fill in global structure
956 for (auto it = data.begin(); it != data.end(); ++it)
957 {
958 std::string chKey = it.key();
959 uint8_t chNum = std::stoi(chKey, nullptr, 10);
960 if ((chNum < 0) || (chNum > maxIpmiChannels))
961 {
962 log<level::DEBUG>(
963 "Invalid channel access entry in config file");
964 throw std::out_of_range("Out of range - channel number");
965 }
966 Json jsonChData = it.value();
967 if (!jsonChData.is_null())
968 {
969 std::string accModeStr =
970 jsonChData[accessModeString].get<std::string>();
971 channelData[chNum].chAccess.chVolatileData.accessMode =
972 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
973 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
974 jsonChData[userAuthDisabledString].get<bool>();
975 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
976 jsonChData[perMsgAuthDisabledString].get<bool>();
977 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
978 jsonChData[alertingDisabledString].get<bool>();
979 std::string privStr =
980 jsonChData[privLimitString].get<std::string>();
981 channelData[chNum].chAccess.chVolatileData.privLimit =
982 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
983 }
984 else
985 {
986 log<level::ERR>(
987 "Invalid/corrupted volatile channel access file",
988 entry("FILE: %s", channelVolatileDataFilename));
989 throw std::runtime_error(
990 "Corrupted volatile channel access file");
991 }
992 }
993 }
994 catch (const Json::exception& e)
995 {
996 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
997 throw std::runtime_error("Corrupted volatile channel access file");
998 }
999 catch (const std::invalid_argument& e)
1000 {
1001 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
1002 throw std::runtime_error("Corrupted volatile channel access file");
1003 }
1004
1005 // Update the timestamp
1006 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1007 return 0;
1008}
1009
1010int ChannelConfig::readChannelPersistData()
1011{
1012 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1013 channelLock{*channelMutex};
1014
1015 Json data = readJsonFile(channelNvDataFilename);
1016 if (data == nullptr)
1017 {
1018 log<level::DEBUG>("Error in opening IPMI Channel data file");
1019 return -EIO;
1020 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301021 try
1022 {
1023 // Fill in global structure
1024 for (auto it = data.begin(); it != data.end(); ++it)
1025 {
1026 std::string chKey = it.key();
1027 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1028 if ((chNum < 0) || (chNum > maxIpmiChannels))
1029 {
1030 log<level::DEBUG>(
1031 "Invalid channel access entry in config file");
1032 throw std::out_of_range("Out of range - channel number");
1033 }
1034 Json jsonChData = it.value();
1035 if (!jsonChData.is_null())
1036 {
1037 std::string accModeStr =
1038 jsonChData[accessModeString].get<std::string>();
1039 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1040 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1041 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1042 jsonChData[userAuthDisabledString].get<bool>();
1043 channelData[chNum]
1044 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1045 jsonChData[perMsgAuthDisabledString].get<bool>();
1046 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1047 jsonChData[alertingDisabledString].get<bool>();
1048 std::string privStr =
1049 jsonChData[privLimitString].get<std::string>();
1050 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1051 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1052 }
1053 else
1054 {
1055 log<level::ERR>("Invalid/corrupted nv channel access file",
1056 entry("FILE:%s", channelNvDataFilename));
1057 throw std::runtime_error("Corrupted nv channel access file");
1058 }
1059 }
1060 }
1061 catch (const Json::exception& e)
1062 {
1063 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1064 throw std::runtime_error("Corrupted nv channel access file");
1065 }
1066 catch (const std::invalid_argument& e)
1067 {
1068 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1069 throw std::runtime_error("Corrupted nv channel access file");
1070 }
1071
1072 // Update the timestamp
1073 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1074 return 0;
1075}
1076
1077int ChannelConfig::writeChannelVolatileData()
1078{
1079 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1080 channelLock{*channelMutex};
1081 Json outData;
1082
1083 try
1084 {
1085 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1086 {
1087 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1088 {
1089 Json jsonObj;
1090 std::string chKey = std::to_string(chNum);
1091 std::string accModeStr = convertToAccessModeString(
1092 channelData[chNum].chAccess.chVolatileData.accessMode);
1093 jsonObj[accessModeString] = accModeStr;
1094 jsonObj[userAuthDisabledString] =
1095 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1096 jsonObj[perMsgAuthDisabledString] =
1097 channelData[chNum]
1098 .chAccess.chVolatileData.perMsgAuthDisabled;
1099 jsonObj[alertingDisabledString] =
1100 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1101 std::string privStr = convertToPrivLimitString(
1102 channelData[chNum].chAccess.chVolatileData.privLimit);
1103 jsonObj[privLimitString] = privStr;
1104
1105 outData[chKey] = jsonObj;
1106 }
1107 }
1108 }
1109 catch (const std::invalid_argument& e)
1110 {
1111 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1112 return -EINVAL;
1113 }
1114
1115 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1116 {
1117 log<level::DEBUG>("Error in write JSON data to file");
1118 return -EIO;
1119 }
1120
1121 // Update the timestamp
1122 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1123 return 0;
1124}
1125
1126int ChannelConfig::writeChannelPersistData()
1127{
1128 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1129 channelLock{*channelMutex};
1130 Json outData;
1131
1132 try
1133 {
1134 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1135 {
1136 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1137 {
1138 Json jsonObj;
1139 std::string chKey = std::to_string(chNum);
1140 std::string accModeStr = convertToAccessModeString(
1141 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1142 jsonObj[accessModeString] = accModeStr;
1143 jsonObj[userAuthDisabledString] =
1144 channelData[chNum]
1145 .chAccess.chNonVolatileData.userAuthDisabled;
1146 jsonObj[perMsgAuthDisabledString] =
1147 channelData[chNum]
1148 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1149 jsonObj[alertingDisabledString] =
1150 channelData[chNum]
1151 .chAccess.chNonVolatileData.alertingDisabled;
1152 std::string privStr = convertToPrivLimitString(
1153 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1154 jsonObj[privLimitString] = privStr;
1155
1156 outData[chKey] = jsonObj;
1157 }
1158 }
1159 }
1160 catch (const std::invalid_argument& e)
1161 {
1162 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1163 return -EINVAL;
1164 }
1165
1166 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1167 {
1168 log<level::DEBUG>("Error in write JSON data to file");
1169 return -EIO;
1170 }
1171
1172 // Update the timestamp
1173 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1174 return 0;
1175}
1176
1177int ChannelConfig::checkAndReloadNVData()
1178{
1179 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1180 int ret = 0;
1181 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1182 {
1183 try
1184 {
1185 ret = readChannelPersistData();
1186 }
1187 catch (const std::exception& e)
1188 {
1189 log<level::ERR>("Exception caught in readChannelPersistData.",
1190 entry("MSG=%s", e.what()));
1191 ret = -EIO;
1192 }
1193 }
1194 return ret;
1195}
1196
1197int ChannelConfig::checkAndReloadVolatileData()
1198{
1199 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1200 int ret = 0;
1201 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1202 {
1203 try
1204 {
1205 ret = readChannelVolatileData();
1206 }
1207 catch (const std::exception& e)
1208 {
1209 log<level::ERR>("Exception caught in readChannelVolatileData.",
1210 entry("MSG=%s", e.what()));
1211 ret = -EIO;
1212 }
1213 }
1214 return ret;
1215}
1216
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001217int ChannelConfig::setDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301218 const std::string& objPath,
1219 const std::string& interface,
1220 const std::string& property,
1221 const DbusVariant& value)
1222{
1223 try
1224 {
1225 auto method =
1226 bus.new_method_call(service.c_str(), objPath.c_str(),
1227 "org.freedesktop.DBus.Properties", "Set");
1228
1229 method.append(interface, property, value);
1230
1231 auto reply = bus.call(method);
1232 }
1233 catch (const sdbusplus::exception::SdBusError& e)
1234 {
1235 log<level::DEBUG>("set-property failed",
1236 entry("SERVICE:%s", service.c_str()),
1237 entry("OBJPATH:%s", objPath.c_str()),
1238 entry("INTERFACE:%s", interface.c_str()),
1239 entry("PROP:%s", property.c_str()));
1240 return -EIO;
1241 }
1242
1243 return 0;
1244}
1245
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001246int ChannelConfig::getDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301247 const std::string& objPath,
1248 const std::string& interface,
1249 const std::string& property,
1250 DbusVariant& value)
1251{
1252 try
1253 {
1254 auto method =
1255 bus.new_method_call(service.c_str(), objPath.c_str(),
1256 "org.freedesktop.DBus.Properties", "Get");
1257
1258 method.append(interface, property);
1259
1260 auto reply = bus.call(method);
1261 reply.read(value);
1262 }
1263 catch (const sdbusplus::exception::SdBusError& e)
1264 {
1265 log<level::DEBUG>("get-property failed",
1266 entry("SERVICE:%s", service.c_str()),
1267 entry("OBJPATH:%s", objPath.c_str()),
1268 entry("INTERFACE:%s", interface.c_str()),
1269 entry("PROP:%s", property.c_str()));
1270 return -EIO;
1271 }
1272 return 0;
1273}
1274
1275int ChannelConfig::syncNetworkChannelConfig()
1276{
1277 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1278 channelLock{*channelMutex};
1279 bool isUpdated = false;
1280 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1281 {
1282 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1283 {
1284 std::string intfPrivStr;
1285 try
1286 {
AppaRao Puli9613ed72018-09-01 23:46:44 +05301287 std::string networkIntfObj =
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301288 std::string(networkIntfObjectBasePath) + "/" +
1289 channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +05301290 DbusVariant variant;
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001291 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301292 networkChConfigIntfName,
1293 privilegePropertyString, variant))
1294 {
1295 log<level::DEBUG>("Network interface does not exist",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301296 entry("INTERFACE:%s",
1297 channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301298 continue;
1299 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001300 intfPrivStr = variant_ns::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301301 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001302 catch (const variant_ns::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301303 {
1304 log<level::DEBUG>(
1305 "exception: Network interface does not exist");
1306 continue;
1307 }
1308 catch (const sdbusplus::exception::SdBusError& e)
1309 {
1310 log<level::DEBUG>(
1311 "exception: Network interface does not exist");
1312 continue;
1313 }
1314
1315 uint8_t intfPriv =
1316 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1317 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1318 intfPriv)
1319 {
1320 isUpdated = true;
1321 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1322 intfPriv;
1323 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1324 }
1325 }
1326 }
1327
1328 if (isUpdated)
1329 {
1330 // Write persistent data to file
1331 if (writeChannelPersistData() != 0)
1332 {
1333 log<level::DEBUG>("Failed to update the persistent data file");
1334 return -EIO;
1335 }
1336 // Write Volatile data to file
1337 if (writeChannelVolatileData() != 0)
1338 {
1339 log<level::DEBUG>("Failed to update the channel volatile data");
1340 return -EIO;
1341 }
1342 }
1343
1344 return 0;
1345}
1346
AppaRao Puli071f3f22018-05-24 16:45:30 +05301347void ChannelConfig::initChannelPersistData()
1348{
1349 /* Always read the channel config */
1350 if (loadChannelConfig() != 0)
1351 {
1352 log<level::ERR>("Failed to read channel config file");
1353 throw std::ios_base::failure("Failed to load channel configuration");
1354 }
1355
1356 /* Populate the channel persist data */
1357 if (readChannelPersistData() != 0)
1358 {
1359 // Copy default NV data to RW location
1360 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1361 channelNvDataFilename);
1362
1363 // Load the channel access NV data
1364 if (readChannelPersistData() != 0)
1365 {
1366 log<level::ERR>("Failed to read channel access NV data");
1367 throw std::ios_base::failure(
1368 "Failed to read channel access NV configuration");
1369 }
1370 }
1371
1372 // First check the volatile data file
1373 // If not present, load the default values
1374 if (readChannelVolatileData() != 0)
1375 {
1376 // Copy default volatile data to temporary location
1377 // NV file(channelNvDataFilename) must have created by now.
1378 std::experimental::filesystem::copy_file(channelNvDataFilename,
1379 channelVolatileDataFilename);
1380
1381 // Load the channel access volatile data
1382 if (readChannelVolatileData() != 0)
1383 {
1384 log<level::ERR>("Failed to read channel access volatile data");
1385 throw std::ios_base::failure(
1386 "Failed to read channel access volatile configuration");
1387 }
1388 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301389
1390 // Synchronize the channel config(priv) with network channel
1391 // configuration(priv) over dbus
1392 if (syncNetworkChannelConfig() != 0)
1393 {
1394 log<level::ERR>(
1395 "Failed to synchronize data with network channel config over dbus");
1396 throw std::ios_base::failure(
1397 "Failed to synchronize data with network channel config over dbus");
1398 }
1399
1400 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301401 return;
1402}
1403
1404} // namespace ipmi