blob: 6559a432b86b045c5eb749675d4c86355ccd0d92 [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
37using namespace phosphor::logging;
38
39static constexpr const char* channelAccessDefaultFilename =
40 "/usr/share/ipmi-providers/channel_access.json";
41static constexpr const char* channelConfigDefaultFilename =
42 "/usr/share/ipmi-providers/channel_config.json";
43static constexpr const char* channelNvDataFilename =
44 "/var/lib/ipmi/channel_access_nv.json";
45static constexpr const char* channelVolatileDataFilename =
46 "/run/ipmi/channel_access_volatile.json";
47
AppaRao Puli9613ed72018-09-01 23:46:44 +053048// TODO: Get the service name dynamically..
49static constexpr const char* networkIntfServiceName =
50 "xyz.openbmc_project.Network";
51static constexpr const char* networkIntfObjectBasePath =
52 "/xyz/openbmc_project/network";
53static constexpr const char* networkChConfigIntfName =
54 "xyz.openbmc_project.Channel.ChannelAccess";
55static constexpr const char* privilegePropertyString = "MaxPrivilege";
56static constexpr const char* dBusPropertiesInterface =
57 "org.freedesktop.DBus.Properties";
58static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
59
AppaRao Puli071f3f22018-05-24 16:45:30 +053060// STRING DEFINES: Should sync with key's in JSON
61static constexpr const char* nameString = "name";
62static constexpr const char* isValidString = "is_valid";
63static constexpr const char* activeSessionsString = "active_sessions";
Vernon Mauery58317122018-11-28 11:02:43 -080064static constexpr const char* maxTransferSizeString = "max_transfer_size";
AppaRao Puli071f3f22018-05-24 16:45:30 +053065static constexpr const char* channelInfoString = "channel_info";
66static constexpr const char* mediumTypeString = "medium_type";
67static constexpr const char* protocolTypeString = "protocol_type";
68static constexpr const char* sessionSupportedString = "session_supported";
69static constexpr const char* isIpmiString = "is_ipmi";
70static constexpr const char* authTypeSupportedString = "auth_type_supported";
71static constexpr const char* accessModeString = "access_mode";
72static constexpr const char* userAuthDisabledString = "user_auth_disabled";
73static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
74static constexpr const char* alertingDisabledString = "alerting_disabled";
75static constexpr const char* privLimitString = "priv_limit";
76static constexpr const char* authTypeEnabledString = "auth_type_enabled";
77
78// Default values
79static constexpr const char* defaultChannelName = "RESERVED";
80static constexpr const uint8_t defaultMediumType =
81 static_cast<uint8_t>(EChannelMediumType::reserved);
82static constexpr const uint8_t defaultProtocolType =
83 static_cast<uint8_t>(EChannelProtocolType::reserved);
84static constexpr const uint8_t defaultSessionSupported =
85 static_cast<uint8_t>(EChannelSessSupported::none);
86static constexpr const uint8_t defaultAuthType =
87 static_cast<uint8_t>(EAuthType::none);
88static constexpr const bool defaultIsIpmiState = false;
Vernon Mauery58317122018-11-28 11:02:43 -080089static constexpr size_t smallChannelSize = 64;
AppaRao Puli071f3f22018-05-24 16:45:30 +053090
Lei YU4b0ddb62019-01-25 16:43:50 +080091std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal
92 __attribute__((init_priority(101)));
AppaRao Puli9613ed72018-09-01 23:46:44 +053093
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
Richard Marian Thomaiyar55768e32019-03-02 22:54:37 +0530140std::string ChannelConfig::getChannelName(const uint8_t chNum)
Johnathan Mantey74a21022018-12-13 13:17:56 -0800141{
142 if (!isValidChannel(chNum))
143 {
144 log<level::ERR>("Invalid channel number.",
145 entry("ChannelID:%d", chNum));
146 throw std::invalid_argument("Invalid channel number");
147 }
148
149 return channelData[chNum].chName;
150}
151
152int ChannelConfig::convertToChannelNumberFromChannelName(
153 const std::string& chName)
154{
155 for (const auto& it : channelData)
156 {
157 if (it.chName == chName)
158 {
159 return it.chID;
160 }
161 }
162 log<level::ERR>("Invalid channel name.",
163 entry("Channel:%s", chName.c_str()));
164 throw std::invalid_argument("Invalid channel name");
165
166 return -1;
167}
168
169std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530170{
171 std::size_t pos = path.find(networkIntfObjectBasePath);
172 if (pos == std::string::npos)
173 {
174 log<level::ERR>("Invalid interface path.",
175 entry("PATH:%s", path.c_str()));
176 throw std::invalid_argument("Invalid interface path");
177 }
Johnathan Mantey74a21022018-12-13 13:17:56 -0800178 std::string chName =
AppaRao Puli9613ed72018-09-01 23:46:44 +0530179 path.substr(pos + strlen(networkIntfObjectBasePath) + 1);
Johnathan Mantey74a21022018-12-13 13:17:56 -0800180 return chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530181}
182
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800183void ChannelConfig::processChAccessPropChange(
184 const std::string& path, const DbusChObjProperties& chProperties)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530185{
186 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
Johnathan Mantey74a21022018-12-13 13:17:56 -0800187 std::string chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530188 try
189 {
Johnathan Mantey74a21022018-12-13 13:17:56 -0800190 chName = getChannelNameFromPath(path);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530191 }
192 catch (const std::invalid_argument& e)
193 {
194 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
195 return;
196 }
197
198 // Get the MaxPrivilege property value from the signal
199 std::string intfPrivStr;
200 std::string propName;
201 for (const auto& prop : chProperties)
202 {
203 if (prop.first == privilegePropertyString)
204 {
205 propName = privilegePropertyString;
Vernon Maueryf442e112019-04-09 11:44:36 -0700206 intfPrivStr = std::get<std::string>(prop.second);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530207 break;
208 }
209 }
210
211 if (propName != privilegePropertyString)
212 {
213 log<level::ERR>("Unknown signal caught.");
214 return;
215 }
216
217 if (intfPrivStr.empty())
218 {
219 log<level::ERR>("Invalid privilege string.",
Johnathan Mantey74a21022018-12-13 13:17:56 -0800220 entry("INTF:%s", chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530221 return;
222 }
223
224 uint8_t intfPriv = 0;
Johnathan Mantey74a21022018-12-13 13:17:56 -0800225 int chNum;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530226 try
227 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800228 intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800229 chNum = convertToChannelNumberFromChannelName(chName);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530230 }
231 catch (const std::invalid_argument& e)
232 {
233 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
234 return;
235 }
236
237 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800238 channelLock{*channelMutex};
AppaRao Puli9613ed72018-09-01 23:46:44 +0530239 // skip updating the values, if this property change originated from IPMI.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800240 if (signalFlag & (1 << chNum))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530241 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800242 signalFlag &= ~(1 << chNum);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530243 log<level::DEBUG>("Request originated from IPMI so ignoring signal");
244 return;
245 }
246
247 // Update both volatile & Non-volatile, if there is mismatch.
248 // as property change other than IPMI, has to update both volatile &
249 // non-volatile data.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800250 checkAndReloadVolatileData();
251 checkAndReloadNVData();
252 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530253 {
254 // Update NV data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800255 channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
256 if (writeChannelPersistData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530257 {
258 log<level::ERR>("Failed to update the persist data file");
259 return;
260 }
261
262 // Update Volatile data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800263 if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530264 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800265 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
266 if (writeChannelVolatileData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530267 {
268 log<level::ERR>("Failed to update the volatile data file");
269 return;
270 }
271 }
272 }
273
274 return;
275}
276
AppaRao Puli071f3f22018-05-24 16:45:30 +0530277ChannelConfig& getChannelConfigObject()
278{
279 static ChannelConfig channelConfig;
280 return channelConfig;
281}
282
AppaRao Puli9613ed72018-09-01 23:46:44 +0530283ChannelConfig::~ChannelConfig()
284{
285 if (signalHndlrObjectState)
286 {
287 chPropertiesSignal.reset();
288 sigHndlrLock.unlock();
289 }
290}
291
AppaRao Puli071f3f22018-05-24 16:45:30 +0530292ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
293{
294 std::ofstream mutexCleanUpFile;
295 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
296 std::ofstream::out | std::ofstream::app);
297 if (!mutexCleanUpFile.good())
298 {
299 log<level::DEBUG>("Unable to open mutex cleanup file");
300 return;
301 }
302 mutexCleanUpFile.close();
303 mutexCleanupLock =
304 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
305 if (mutexCleanupLock.try_lock())
306 {
307 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
308 channelMutex =
309 std::make_unique<boost::interprocess::named_recursive_mutex>(
310 boost::interprocess::open_or_create, ipmiChannelMutex);
311 mutexCleanupLock.lock_sharable();
312 }
313 else
314 {
315 mutexCleanupLock.lock_sharable();
316 channelMutex =
317 std::make_unique<boost::interprocess::named_recursive_mutex>(
318 boost::interprocess::open_or_create, ipmiChannelMutex);
319 }
320
321 initChannelPersistData();
AppaRao Puli9613ed72018-09-01 23:46:44 +0530322
323 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
324 // Register it for single object and single process either netipimd /
325 // host-ipmid
326 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
327 {
328 log<level::DEBUG>("Registering channel signal handler.");
329 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
330 bus,
331 sdbusplus::bus::match::rules::path_namespace(
332 networkIntfObjectBasePath) +
333 sdbusplus::bus::match::rules::type::signal() +
334 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
335 sdbusplus::bus::match::rules::interface(
336 dBusPropertiesInterface) +
337 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
338 [&](sdbusplus::message::message& msg) {
339 DbusChObjProperties props;
340 std::string iface;
341 std::string path = msg.get_path();
342 msg.read(iface, props);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800343 processChAccessPropChange(path, props);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530344 });
345 signalHndlrObjectState = true;
346 }
347}
348
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530349bool ChannelConfig::isValidChannel(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530350{
351 if (chNum > maxIpmiChannels)
352 {
353 log<level::DEBUG>("Invalid channel ID - Out of range");
354 return false;
355 }
356
357 if (channelData[chNum].isChValid == false)
358 {
359 log<level::DEBUG>("Channel is not valid");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530360 }
361
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800362 return channelData[chNum].isChValid;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530363}
364
365EChannelSessSupported
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530366 ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530367{
368 EChannelSessSupported chSessSupport =
369 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
370 return chSessSupport;
371}
372
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530373bool ChannelConfig::isValidAuthType(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530374 const EAuthType& authType)
375{
376 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
377 {
378 log<level::DEBUG>("Invalid authentication type");
379 return false;
380 }
381
382 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
383 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
384 {
385 log<level::DEBUG>("Authentication type is not supported.");
386 return false;
387 }
388
389 return true;
390}
391
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530392int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530393{
394 // TODO: TEMPORARY FIX
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800395 // Channels active session count is managed separately
AppaRao Puli071f3f22018-05-24 16:45:30 +0530396 // by monitoring channel session which includes LAN and
397 // RAKP layer changes. This will be updated, once the
398 // authentication part is implemented.
399 return channelData[chNum].activeSessCount;
400}
401
Vernon Mauery58317122018-11-28 11:02:43 -0800402size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
403{
404 return channelData[chNum].maxTransferSize;
405}
406
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530407ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530408 ChannelInfo& chInfo)
409{
410 if (!isValidChannel(chNum))
411 {
412 log<level::DEBUG>("Invalid channel");
413 return IPMI_CC_INVALID_FIELD_REQUEST;
414 }
415
416 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
417 sizeof(channelData[chNum].chInfo),
418 reinterpret_cast<uint8_t*>(&chInfo));
419
420 return IPMI_CC_OK;
421}
422
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530423ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530424 ChannelAccess& chAccessData)
425{
426 if (!isValidChannel(chNum))
427 {
428 log<level::DEBUG>("Invalid channel");
429 return IPMI_CC_INVALID_FIELD_REQUEST;
430 }
431
432 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
433 {
434 log<level::DEBUG>("Session-less channel doesn't have access data.");
435 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
436 }
437
438 if (checkAndReloadVolatileData() != 0)
439 {
440 return IPMI_CC_UNSPECIFIED_ERROR;
441 }
442
443 std::copy_n(
444 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
445 sizeof(channelData[chNum].chAccess.chVolatileData),
446 reinterpret_cast<uint8_t*>(&chAccessData));
447
448 return IPMI_CC_OK;
449}
450
451ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530452 ChannelConfig::setChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530453 const ChannelAccess& chAccessData,
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530454 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530455{
456 if (!isValidChannel(chNum))
457 {
458 log<level::DEBUG>("Invalid channel");
459 return IPMI_CC_INVALID_FIELD_REQUEST;
460 }
461
462 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
463 {
464 log<level::DEBUG>("Session-less channel doesn't have access data.");
465 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
466 }
467
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530468 if (((setFlag & setAccessMode) &&
469 (!isValidAccessMode(chAccessData.accessMode))) ||
470 ((setFlag & setPrivLimit) &&
471 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530472 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530473 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530474 return IPMI_CC_INVALID_FIELD_REQUEST;
475 }
476
477 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
478 channelLock{*channelMutex};
479
480 if (checkAndReloadVolatileData() != 0)
481 {
482 return IPMI_CC_UNSPECIFIED_ERROR;
483 }
484
485 if (setFlag & setAccessMode)
486 {
487 channelData[chNum].chAccess.chVolatileData.accessMode =
488 chAccessData.accessMode;
489 }
490 if (setFlag & setUserAuthEnabled)
491 {
492 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
493 chAccessData.userAuthDisabled;
494 }
495 if (setFlag & setMsgAuthEnabled)
496 {
497 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
498 chAccessData.perMsgAuthDisabled;
499 }
500 if (setFlag & setAlertingEnabled)
501 {
502 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
503 chAccessData.alertingDisabled;
504 }
505 if (setFlag & setPrivLimit)
506 {
507 channelData[chNum].chAccess.chVolatileData.privLimit =
508 chAccessData.privLimit;
509 }
510
511 // Write Volatile data to file
512 if (writeChannelVolatileData() != 0)
513 {
514 log<level::DEBUG>("Failed to update the channel volatile data");
515 return IPMI_CC_UNSPECIFIED_ERROR;
516 }
517 return IPMI_CC_OK;
518}
519
520ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530521 ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530522 ChannelAccess& chAccessData)
523{
524 if (!isValidChannel(chNum))
525 {
526 log<level::DEBUG>("Invalid channel");
527 return IPMI_CC_INVALID_FIELD_REQUEST;
528 }
529
530 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
531 {
532 log<level::DEBUG>("Session-less channel doesn't have access data.");
533 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
534 }
535
536 if (checkAndReloadNVData() != 0)
537 {
538 return IPMI_CC_UNSPECIFIED_ERROR;
539 }
540
541 std::copy_n(reinterpret_cast<uint8_t*>(
542 &channelData[chNum].chAccess.chNonVolatileData),
543 sizeof(channelData[chNum].chAccess.chNonVolatileData),
544 reinterpret_cast<uint8_t*>(&chAccessData));
545
546 return IPMI_CC_OK;
547}
548
549ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530550 const uint8_t chNum, const ChannelAccess& chAccessData,
551 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530552{
553 if (!isValidChannel(chNum))
554 {
555 log<level::DEBUG>("Invalid channel");
556 return IPMI_CC_INVALID_FIELD_REQUEST;
557 }
558
559 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
560 {
561 log<level::DEBUG>("Session-less channel doesn't have access data.");
562 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
563 }
564
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530565 if (((setFlag & setAccessMode) &&
566 (!isValidAccessMode(chAccessData.accessMode))) ||
567 ((setFlag & setPrivLimit) &&
568 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530569 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530570 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530571 return IPMI_CC_INVALID_FIELD_REQUEST;
572 }
573
574 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
575 channelLock{*channelMutex};
576
577 if (checkAndReloadNVData() != 0)
578 {
579 return IPMI_CC_UNSPECIFIED_ERROR;
580 }
581
582 if (setFlag & setAccessMode)
583 {
584 channelData[chNum].chAccess.chNonVolatileData.accessMode =
585 chAccessData.accessMode;
586 }
587 if (setFlag & setUserAuthEnabled)
588 {
589 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
590 chAccessData.userAuthDisabled;
591 }
592 if (setFlag & setMsgAuthEnabled)
593 {
594 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
595 chAccessData.perMsgAuthDisabled;
596 }
597 if (setFlag & setAlertingEnabled)
598 {
599 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
600 chAccessData.alertingDisabled;
601 }
602 if (setFlag & setPrivLimit)
603 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530604 // Send Update to network channel config interfaces over dbus
AppaRao Puli9613ed72018-09-01 23:46:44 +0530605 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530606 std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
607 "/" + channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530608 try
609 {
Johnathan Manteyf92261d2018-12-10 15:49:34 -0800610 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
611 networkChConfigIntfName,
AppaRao Puli9613ed72018-09-01 23:46:44 +0530612 privilegePropertyString, privStr))
613 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530614 log<level::DEBUG>(
615 "Network interface does not exist",
616 entry("INTERFACE:%s", channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530617 return IPMI_CC_UNSPECIFIED_ERROR;
618 }
619 }
620 catch (const sdbusplus::exception::SdBusError& e)
621 {
622 log<level::ERR>("Exception: Network interface does not exist");
623 return IPMI_CC_INVALID_FIELD_REQUEST;
624 }
625 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530626 channelData[chNum].chAccess.chNonVolatileData.privLimit =
627 chAccessData.privLimit;
628 }
629
630 // Write persistent data to file
631 if (writeChannelPersistData() != 0)
632 {
633 log<level::DEBUG>("Failed to update the presist data file");
634 return IPMI_CC_UNSPECIFIED_ERROR;
635 }
636 return IPMI_CC_OK;
637}
638
639ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530640 ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530641 uint8_t& authTypeSupported)
642{
643 if (!isValidChannel(chNum))
644 {
645 log<level::DEBUG>("Invalid channel");
646 return IPMI_CC_INVALID_FIELD_REQUEST;
647 }
648
649 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
650 return IPMI_CC_OK;
651}
652
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530653ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
654 const uint8_t priv,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530655 EAuthType& authType)
656{
657 if (!isValidChannel(chNum))
658 {
659 log<level::DEBUG>("Invalid channel");
660 return IPMI_CC_INVALID_FIELD_REQUEST;
661 }
662
663 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
664 {
665 log<level::DEBUG>("Sessionless channel doesn't have access data.");
666 return IPMI_CC_INVALID_FIELD_REQUEST;
667 }
668
669 if (!isValidPrivLimit(priv))
670 {
671 log<level::DEBUG>("Invalid privilege specified.");
672 return IPMI_CC_INVALID_FIELD_REQUEST;
673 }
674
675 // TODO: Hardcoded for now. Need to implement.
676 authType = EAuthType::none;
677
678 return IPMI_CC_OK;
679}
680
681std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
682{
683 struct stat fileStat;
684 if (stat(fileName.c_str(), &fileStat) != 0)
685 {
686 log<level::DEBUG>("Error in getting last updated time stamp");
687 return -EIO;
688 }
689 return fileStat.st_mtime;
690}
691
692EChannelAccessMode
693 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
694{
695 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
696 if (iter == accessModeList.end())
697 {
698 log<level::ERR>("Invalid access mode.",
699 entry("MODE_STR=%s", mode.c_str()));
700 throw std::invalid_argument("Invalid access mode.");
701 }
702
703 return static_cast<EChannelAccessMode>(
704 std::distance(accessModeList.begin(), iter));
705}
706
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530707std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530708{
709 if (accessModeList.size() <= value)
710 {
711 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
712 throw std::invalid_argument("Invalid access mode.");
713 }
714
715 return accessModeList.at(value);
716}
717
718CommandPrivilege
719 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
720{
721 auto iter = std::find(privList.begin(), privList.end(), value);
722 if (iter == privList.end())
723 {
724 log<level::ERR>("Invalid privilege.",
725 entry("PRIV_STR=%s", value.c_str()));
726 throw std::invalid_argument("Invalid privilege.");
727 }
728
729 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
730}
731
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530732std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530733{
734 if (privList.size() <= value)
735 {
736 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
737 throw std::invalid_argument("Invalid privilege.");
738 }
739
740 return privList.at(value);
741}
742
743EChannelSessSupported
744 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
745{
746 auto iter =
747 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
748 if (iter == sessionSupportList.end())
749 {
750 log<level::ERR>("Invalid session supported.",
751 entry("SESS_STR=%s", value.c_str()));
752 throw std::invalid_argument("Invalid session supported.");
753 }
754
755 return static_cast<EChannelSessSupported>(
756 std::distance(sessionSupportList.begin(), iter));
757}
758
759EChannelMediumType
760 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
761{
762 std::unordered_map<std::string, EChannelMediumType>::iterator it =
763 mediumTypeMap.find(value);
764 if (it == mediumTypeMap.end())
765 {
766 log<level::ERR>("Invalid medium type.",
767 entry("MEDIUM_STR=%s", value.c_str()));
768 throw std::invalid_argument("Invalid medium type.");
769 }
770
771 return static_cast<EChannelMediumType>(it->second);
772}
773
774EChannelProtocolType
775 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
776{
777 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
778 protocolTypeMap.find(value);
779 if (it == protocolTypeMap.end())
780 {
781 log<level::ERR>("Invalid protocol type.",
782 entry("PROTO_STR=%s", value.c_str()));
783 throw std::invalid_argument("Invalid protocol type.");
784 }
785
786 return static_cast<EChannelProtocolType>(it->second);
787}
788
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530789uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
ssekarf4b2b092018-07-25 18:49:08 +0530790{
791
792 // TODO: There is limitation in current design. we cannot detect exact
793 // LAN interface(eth0 or eth1) so Implementation may be updated
794 // when there is any design update to figure out all the interfaces
795 // independently based on the message.
796
797 static uint8_t curChannel = 0xFF;
798
799 if (curChannel == 0xFF)
800 {
801 auto it = interfaceMap.find(getInterfaceIndex());
802 if (it == interfaceMap.end())
803 {
804 log<level::ERR>("Invalid Interface type ",
805 entry("InterfaceIndex: %d", getInterfaceIndex()));
806 throw std::invalid_argument("Invalid interface type.");
807 }
808
809 for (auto& channel : channelData)
810 {
811 std::string& interfaceName = it->second;
812 if (channel.chName == interfaceName)
813 {
814 curChannel = channel.chID;
815 break;
816 }
817 }
818 }
Richard Marian Thomaiyara39208e2018-12-08 17:27:11 +0530819 return ((chNum == currentChNum) ? curChannel : chNum);
ssekarf4b2b092018-07-25 18:49:08 +0530820}
821
AppaRao Puli071f3f22018-05-24 16:45:30 +0530822Json ChannelConfig::readJsonFile(const std::string& configFile)
823{
824 std::ifstream jsonFile(configFile);
825 if (!jsonFile.good())
826 {
Richard Marian Thomaiyarc4196802019-06-03 19:27:48 +0530827 log<level::INFO>("JSON file not found",
828 entry("FILE_NAME=%s", configFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530829 return nullptr;
830 }
831
832 Json data = nullptr;
833 try
834 {
835 data = Json::parse(jsonFile, nullptr, false);
836 }
837 catch (Json::parse_error& e)
838 {
839 log<level::DEBUG>("Corrupted channel config.",
840 entry("MSG: %s", e.what()));
841 throw std::runtime_error("Corrupted channel config file");
842 }
843
844 return data;
845}
846
847int ChannelConfig::writeJsonFile(const std::string& configFile,
848 const Json& jsonData)
849{
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530850 const std::string tmpFile = configFile + "_tmp";
851 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
852 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
853 if (fd < 0)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530854 {
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530855 log<level::ERR>("Error in creating json file",
856 entry("FILE_NAME = %s", tmpFile.c_str()));
857 return -EIO;
858 }
859 const auto& writeData = jsonData.dump();
860 if (write(fd, writeData.c_str(), writeData.size()) !=
861 static_cast<ssize_t>(writeData.size()))
862 {
863 close(fd);
864 log<level::ERR>("Error in writing configuration file",
865 entry("FILE_NAME = %s", tmpFile.c_str()));
866 return -EIO;
867 }
868 close(fd);
869
870 if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
871 {
872 log<level::ERR>("Error in renaming temporary data file",
873 entry("FILE_NAME = %s", tmpFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530874 return -EIO;
875 }
876
AppaRao Puli071f3f22018-05-24 16:45:30 +0530877 return 0;
878}
879
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530880void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530881 const std::string& chName)
882{
883 channelData[chNum].chName = chName;
884 channelData[chNum].chID = chNum;
885 channelData[chNum].isChValid = false;
886 channelData[chNum].activeSessCount = 0;
887
888 channelData[chNum].chInfo.mediumType = defaultMediumType;
889 channelData[chNum].chInfo.protocolType = defaultProtocolType;
890 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
891 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
892 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
893}
894
895int ChannelConfig::loadChannelConfig()
896{
897 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
898 channelLock{*channelMutex};
899
900 Json data = readJsonFile(channelConfigDefaultFilename);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800901 if (data.empty())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530902 {
903 log<level::DEBUG>("Error in opening IPMI Channel data file");
904 return -EIO;
905 }
906
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800907 channelData.fill(ChannelProperties{});
908
909 for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530910 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800911 try
AppaRao Puli071f3f22018-05-24 16:45:30 +0530912 {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530913 std::string chKey = std::to_string(chNum);
914 Json jsonChData = data[chKey].get<Json>();
915 if (jsonChData.is_null())
916 {
917 log<level::WARNING>(
918 "Channel not configured so loading default.",
919 entry("CHANNEL_NUM:%d", chNum));
920 // If user didn't want to configure specific channel (say
921 // reserved channel), then load that index with default values.
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800922 setDefaultChannelConfig(chNum, defaultChannelName);
923 continue;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530924 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800925 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
926 if (jsonChInfo.is_null())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530927 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800928 log<level::ERR>("Invalid/corrupted channel config file");
929 return -EBADMSG;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530930 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800931
932 ChannelProperties& chData = channelData[chNum];
933 chData.chName = jsonChData[nameString].get<std::string>();
934 chData.chID = chNum;
935 chData.isChValid = jsonChData[isValidString].get<bool>();
936 chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
937 chData.maxTransferSize =
938 jsonChData.value(maxTransferSizeString, smallChannelSize);
939 std::string medTypeStr =
940 jsonChInfo[mediumTypeString].get<std::string>();
941 chData.chInfo.mediumType =
942 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
943 std::string protoTypeStr =
944 jsonChInfo[protocolTypeString].get<std::string>();
945 chData.chInfo.protocolType =
946 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
947 std::string sessStr =
948 jsonChInfo[sessionSupportedString].get<std::string>();
949 chData.chInfo.sessionSupported =
950 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
951 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
952 chData.chInfo.authTypeSupported = defaultAuthType;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530953 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800954 catch (const Json::exception& e)
955 {
956 log<level::DEBUG>("Json Exception caught.",
957 entry("MSG:%s", e.what()));
958 return -EBADMSG;
959 }
960 catch (const std::invalid_argument& e)
961 {
962 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
963 return -EBADMSG;
964 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530965 }
966
967 return 0;
968}
969
970int ChannelConfig::readChannelVolatileData()
971{
972 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
973 channelLock{*channelMutex};
974
975 Json data = readJsonFile(channelVolatileDataFilename);
976 if (data == nullptr)
977 {
978 log<level::DEBUG>("Error in opening IPMI Channel data file");
979 return -EIO;
980 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530981 try
982 {
983 // Fill in global structure
984 for (auto it = data.begin(); it != data.end(); ++it)
985 {
986 std::string chKey = it.key();
987 uint8_t chNum = std::stoi(chKey, nullptr, 10);
988 if ((chNum < 0) || (chNum > maxIpmiChannels))
989 {
990 log<level::DEBUG>(
991 "Invalid channel access entry in config file");
992 throw std::out_of_range("Out of range - channel number");
993 }
994 Json jsonChData = it.value();
995 if (!jsonChData.is_null())
996 {
997 std::string accModeStr =
998 jsonChData[accessModeString].get<std::string>();
999 channelData[chNum].chAccess.chVolatileData.accessMode =
1000 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1001 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
1002 jsonChData[userAuthDisabledString].get<bool>();
1003 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
1004 jsonChData[perMsgAuthDisabledString].get<bool>();
1005 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
1006 jsonChData[alertingDisabledString].get<bool>();
1007 std::string privStr =
1008 jsonChData[privLimitString].get<std::string>();
1009 channelData[chNum].chAccess.chVolatileData.privLimit =
1010 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1011 }
1012 else
1013 {
1014 log<level::ERR>(
1015 "Invalid/corrupted volatile channel access file",
1016 entry("FILE: %s", channelVolatileDataFilename));
1017 throw std::runtime_error(
1018 "Corrupted volatile channel access file");
1019 }
1020 }
1021 }
1022 catch (const Json::exception& e)
1023 {
1024 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1025 throw std::runtime_error("Corrupted volatile channel access file");
1026 }
1027 catch (const std::invalid_argument& e)
1028 {
1029 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
1030 throw std::runtime_error("Corrupted volatile channel access file");
1031 }
1032
1033 // Update the timestamp
1034 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1035 return 0;
1036}
1037
1038int ChannelConfig::readChannelPersistData()
1039{
1040 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1041 channelLock{*channelMutex};
1042
1043 Json data = readJsonFile(channelNvDataFilename);
1044 if (data == nullptr)
1045 {
1046 log<level::DEBUG>("Error in opening IPMI Channel data file");
1047 return -EIO;
1048 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301049 try
1050 {
1051 // Fill in global structure
1052 for (auto it = data.begin(); it != data.end(); ++it)
1053 {
1054 std::string chKey = it.key();
1055 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1056 if ((chNum < 0) || (chNum > maxIpmiChannels))
1057 {
1058 log<level::DEBUG>(
1059 "Invalid channel access entry in config file");
1060 throw std::out_of_range("Out of range - channel number");
1061 }
1062 Json jsonChData = it.value();
1063 if (!jsonChData.is_null())
1064 {
1065 std::string accModeStr =
1066 jsonChData[accessModeString].get<std::string>();
1067 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1068 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1069 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1070 jsonChData[userAuthDisabledString].get<bool>();
1071 channelData[chNum]
1072 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1073 jsonChData[perMsgAuthDisabledString].get<bool>();
1074 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1075 jsonChData[alertingDisabledString].get<bool>();
1076 std::string privStr =
1077 jsonChData[privLimitString].get<std::string>();
1078 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1079 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1080 }
1081 else
1082 {
1083 log<level::ERR>("Invalid/corrupted nv channel access file",
1084 entry("FILE:%s", channelNvDataFilename));
1085 throw std::runtime_error("Corrupted nv channel access file");
1086 }
1087 }
1088 }
1089 catch (const Json::exception& e)
1090 {
1091 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1092 throw std::runtime_error("Corrupted nv channel access file");
1093 }
1094 catch (const std::invalid_argument& e)
1095 {
1096 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1097 throw std::runtime_error("Corrupted nv channel access file");
1098 }
1099
1100 // Update the timestamp
1101 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1102 return 0;
1103}
1104
1105int ChannelConfig::writeChannelVolatileData()
1106{
1107 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1108 channelLock{*channelMutex};
1109 Json outData;
1110
1111 try
1112 {
1113 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1114 {
1115 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1116 {
1117 Json jsonObj;
1118 std::string chKey = std::to_string(chNum);
1119 std::string accModeStr = convertToAccessModeString(
1120 channelData[chNum].chAccess.chVolatileData.accessMode);
1121 jsonObj[accessModeString] = accModeStr;
1122 jsonObj[userAuthDisabledString] =
1123 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1124 jsonObj[perMsgAuthDisabledString] =
1125 channelData[chNum]
1126 .chAccess.chVolatileData.perMsgAuthDisabled;
1127 jsonObj[alertingDisabledString] =
1128 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1129 std::string privStr = convertToPrivLimitString(
1130 channelData[chNum].chAccess.chVolatileData.privLimit);
1131 jsonObj[privLimitString] = privStr;
1132
1133 outData[chKey] = jsonObj;
1134 }
1135 }
1136 }
1137 catch (const std::invalid_argument& e)
1138 {
1139 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1140 return -EINVAL;
1141 }
1142
1143 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1144 {
1145 log<level::DEBUG>("Error in write JSON data to file");
1146 return -EIO;
1147 }
1148
1149 // Update the timestamp
1150 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1151 return 0;
1152}
1153
1154int ChannelConfig::writeChannelPersistData()
1155{
1156 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1157 channelLock{*channelMutex};
1158 Json outData;
1159
1160 try
1161 {
1162 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1163 {
1164 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1165 {
1166 Json jsonObj;
1167 std::string chKey = std::to_string(chNum);
1168 std::string accModeStr = convertToAccessModeString(
1169 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1170 jsonObj[accessModeString] = accModeStr;
1171 jsonObj[userAuthDisabledString] =
1172 channelData[chNum]
1173 .chAccess.chNonVolatileData.userAuthDisabled;
1174 jsonObj[perMsgAuthDisabledString] =
1175 channelData[chNum]
1176 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1177 jsonObj[alertingDisabledString] =
1178 channelData[chNum]
1179 .chAccess.chNonVolatileData.alertingDisabled;
1180 std::string privStr = convertToPrivLimitString(
1181 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1182 jsonObj[privLimitString] = privStr;
1183
1184 outData[chKey] = jsonObj;
1185 }
1186 }
1187 }
1188 catch (const std::invalid_argument& e)
1189 {
1190 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1191 return -EINVAL;
1192 }
1193
1194 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1195 {
1196 log<level::DEBUG>("Error in write JSON data to file");
1197 return -EIO;
1198 }
1199
1200 // Update the timestamp
1201 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1202 return 0;
1203}
1204
1205int ChannelConfig::checkAndReloadNVData()
1206{
1207 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1208 int ret = 0;
1209 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1210 {
1211 try
1212 {
1213 ret = readChannelPersistData();
1214 }
1215 catch (const std::exception& e)
1216 {
1217 log<level::ERR>("Exception caught in readChannelPersistData.",
1218 entry("MSG=%s", e.what()));
1219 ret = -EIO;
1220 }
1221 }
1222 return ret;
1223}
1224
1225int ChannelConfig::checkAndReloadVolatileData()
1226{
1227 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1228 int ret = 0;
1229 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1230 {
1231 try
1232 {
1233 ret = readChannelVolatileData();
1234 }
1235 catch (const std::exception& e)
1236 {
1237 log<level::ERR>("Exception caught in readChannelVolatileData.",
1238 entry("MSG=%s", e.what()));
1239 ret = -EIO;
1240 }
1241 }
1242 return ret;
1243}
1244
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001245int ChannelConfig::setDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301246 const std::string& objPath,
1247 const std::string& interface,
1248 const std::string& property,
1249 const DbusVariant& value)
1250{
1251 try
1252 {
1253 auto method =
1254 bus.new_method_call(service.c_str(), objPath.c_str(),
1255 "org.freedesktop.DBus.Properties", "Set");
1256
1257 method.append(interface, property, value);
1258
1259 auto reply = bus.call(method);
1260 }
1261 catch (const sdbusplus::exception::SdBusError& e)
1262 {
1263 log<level::DEBUG>("set-property failed",
1264 entry("SERVICE:%s", service.c_str()),
1265 entry("OBJPATH:%s", objPath.c_str()),
1266 entry("INTERFACE:%s", interface.c_str()),
1267 entry("PROP:%s", property.c_str()));
1268 return -EIO;
1269 }
1270
1271 return 0;
1272}
1273
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001274int ChannelConfig::getDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301275 const std::string& objPath,
1276 const std::string& interface,
1277 const std::string& property,
1278 DbusVariant& value)
1279{
1280 try
1281 {
1282 auto method =
1283 bus.new_method_call(service.c_str(), objPath.c_str(),
1284 "org.freedesktop.DBus.Properties", "Get");
1285
1286 method.append(interface, property);
1287
1288 auto reply = bus.call(method);
1289 reply.read(value);
1290 }
1291 catch (const sdbusplus::exception::SdBusError& e)
1292 {
1293 log<level::DEBUG>("get-property failed",
1294 entry("SERVICE:%s", service.c_str()),
1295 entry("OBJPATH:%s", objPath.c_str()),
1296 entry("INTERFACE:%s", interface.c_str()),
1297 entry("PROP:%s", property.c_str()));
1298 return -EIO;
1299 }
1300 return 0;
1301}
1302
1303int ChannelConfig::syncNetworkChannelConfig()
1304{
1305 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1306 channelLock{*channelMutex};
1307 bool isUpdated = false;
1308 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1309 {
1310 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1311 {
1312 std::string intfPrivStr;
1313 try
1314 {
AppaRao Puli9613ed72018-09-01 23:46:44 +05301315 std::string networkIntfObj =
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301316 std::string(networkIntfObjectBasePath) + "/" +
1317 channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +05301318 DbusVariant variant;
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001319 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301320 networkChConfigIntfName,
1321 privilegePropertyString, variant))
1322 {
1323 log<level::DEBUG>("Network interface does not exist",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301324 entry("INTERFACE:%s",
1325 channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301326 continue;
1327 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001328 intfPrivStr = std::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301329 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001330 catch (const std::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301331 {
1332 log<level::DEBUG>(
1333 "exception: Network interface does not exist");
1334 continue;
1335 }
1336 catch (const sdbusplus::exception::SdBusError& e)
1337 {
1338 log<level::DEBUG>(
1339 "exception: Network interface does not exist");
1340 continue;
1341 }
1342
1343 uint8_t intfPriv =
1344 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1345 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1346 intfPriv)
1347 {
1348 isUpdated = true;
1349 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1350 intfPriv;
1351 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1352 }
1353 }
1354 }
1355
1356 if (isUpdated)
1357 {
1358 // Write persistent data to file
1359 if (writeChannelPersistData() != 0)
1360 {
1361 log<level::DEBUG>("Failed to update the persistent data file");
1362 return -EIO;
1363 }
1364 // Write Volatile data to file
1365 if (writeChannelVolatileData() != 0)
1366 {
1367 log<level::DEBUG>("Failed to update the channel volatile data");
1368 return -EIO;
1369 }
1370 }
1371
1372 return 0;
1373}
1374
AppaRao Puli071f3f22018-05-24 16:45:30 +05301375void ChannelConfig::initChannelPersistData()
1376{
1377 /* Always read the channel config */
1378 if (loadChannelConfig() != 0)
1379 {
1380 log<level::ERR>("Failed to read channel config file");
1381 throw std::ios_base::failure("Failed to load channel configuration");
1382 }
1383
1384 /* Populate the channel persist data */
1385 if (readChannelPersistData() != 0)
1386 {
1387 // Copy default NV data to RW location
1388 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1389 channelNvDataFilename);
1390
1391 // Load the channel access NV data
1392 if (readChannelPersistData() != 0)
1393 {
1394 log<level::ERR>("Failed to read channel access NV data");
1395 throw std::ios_base::failure(
1396 "Failed to read channel access NV configuration");
1397 }
1398 }
1399
1400 // First check the volatile data file
1401 // If not present, load the default values
1402 if (readChannelVolatileData() != 0)
1403 {
1404 // Copy default volatile data to temporary location
1405 // NV file(channelNvDataFilename) must have created by now.
1406 std::experimental::filesystem::copy_file(channelNvDataFilename,
1407 channelVolatileDataFilename);
1408
1409 // Load the channel access volatile data
1410 if (readChannelVolatileData() != 0)
1411 {
1412 log<level::ERR>("Failed to read channel access volatile data");
1413 throw std::ios_base::failure(
1414 "Failed to read channel access volatile configuration");
1415 }
1416 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301417
1418 // Synchronize the channel config(priv) with network channel
1419 // configuration(priv) over dbus
1420 if (syncNetworkChannelConfig() != 0)
1421 {
1422 log<level::ERR>(
1423 "Failed to synchronize data with network channel config over dbus");
1424 throw std::ios_base::failure(
1425 "Failed to synchronize data with network channel config over dbus");
1426 }
1427
1428 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301429 return;
1430}
1431
1432} // namespace ipmi