blob: 116521d6f6652b893508a89f68edc3e655fbd564 [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.",
Richard Marian Thomaiyar619ed5f2020-01-17 12:17:47 +0530145 entry("CHANNEL_ID=%d", chNum));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800146 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.",
Richard Marian Thomaiyar619ed5f2020-01-17 12:17:47 +0530163 entry("CHANNEL=%s", chName.c_str()));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800164 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{
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530171
172 constexpr size_t length = strlen(networkIntfObjectBasePath);
173 if (((length + 1) >= path.size()) ||
174 path.compare(0, length, networkIntfObjectBasePath))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530175 {
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530176 log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str()));
177 throw std::invalid_argument("Invalid object path");
AppaRao Puli9613ed72018-09-01 23:46:44 +0530178 }
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530179 std::string chName(path, length + 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 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530194 log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530195 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.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530220 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 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530233 log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530234 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
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000407Cc ChannelConfig::getChannelInfo(const uint8_t chNum, ChannelInfo& chInfo)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530408{
409 if (!isValidChannel(chNum))
410 {
411 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000412 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530413 }
414
415 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
416 sizeof(channelData[chNum].chInfo),
417 reinterpret_cast<uint8_t*>(&chInfo));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000418 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530419}
420
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000421Cc ChannelConfig::getChannelAccessData(const uint8_t chNum,
422 ChannelAccess& chAccessData)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530423{
424 if (!isValidChannel(chNum))
425 {
426 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000427 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530428 }
429
430 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
431 {
432 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000433 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530434 }
435
436 if (checkAndReloadVolatileData() != 0)
437 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000438 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530439 }
440
441 std::copy_n(
442 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
443 sizeof(channelData[chNum].chAccess.chVolatileData),
444 reinterpret_cast<uint8_t*>(&chAccessData));
445
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000446 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530447}
448
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000449Cc ChannelConfig::setChannelAccessData(const uint8_t chNum,
450 const ChannelAccess& chAccessData,
451 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530452{
453 if (!isValidChannel(chNum))
454 {
455 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000456 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530457 }
458
459 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
460 {
461 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000462 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530463 }
464
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530465 if (((setFlag & setAccessMode) &&
466 (!isValidAccessMode(chAccessData.accessMode))) ||
467 ((setFlag & setPrivLimit) &&
468 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530469 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530470 log<level::DEBUG>("Invalid access mode / privilege limit specified");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000471 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530472 }
473
474 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
475 channelLock{*channelMutex};
476
477 if (checkAndReloadVolatileData() != 0)
478 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000479 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530480 }
481
482 if (setFlag & setAccessMode)
483 {
484 channelData[chNum].chAccess.chVolatileData.accessMode =
485 chAccessData.accessMode;
486 }
487 if (setFlag & setUserAuthEnabled)
488 {
489 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
490 chAccessData.userAuthDisabled;
491 }
492 if (setFlag & setMsgAuthEnabled)
493 {
494 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
495 chAccessData.perMsgAuthDisabled;
496 }
497 if (setFlag & setAlertingEnabled)
498 {
499 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
500 chAccessData.alertingDisabled;
501 }
502 if (setFlag & setPrivLimit)
503 {
504 channelData[chNum].chAccess.chVolatileData.privLimit =
505 chAccessData.privLimit;
506 }
507
508 // Write Volatile data to file
509 if (writeChannelVolatileData() != 0)
510 {
511 log<level::DEBUG>("Failed to update the channel volatile data");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000512 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530513 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000514 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530515}
516
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000517Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
518 ChannelAccess& chAccessData)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530519{
520 if (!isValidChannel(chNum))
521 {
522 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000523 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530524 }
525
526 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
527 {
528 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000529 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530530 }
531
532 if (checkAndReloadNVData() != 0)
533 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000534 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530535 }
536
537 std::copy_n(reinterpret_cast<uint8_t*>(
538 &channelData[chNum].chAccess.chNonVolatileData),
539 sizeof(channelData[chNum].chAccess.chNonVolatileData),
540 reinterpret_cast<uint8_t*>(&chAccessData));
541
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000542 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530543}
544
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000545Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum,
546 const ChannelAccess& chAccessData,
547 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530548{
549 if (!isValidChannel(chNum))
550 {
551 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000552 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530553 }
554
555 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
556 {
557 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000558 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530559 }
560
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530561 if (((setFlag & setAccessMode) &&
562 (!isValidAccessMode(chAccessData.accessMode))) ||
563 ((setFlag & setPrivLimit) &&
564 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530565 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530566 log<level::DEBUG>("Invalid access mode / privilege limit specified");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000567 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530568 }
569
570 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
571 channelLock{*channelMutex};
572
573 if (checkAndReloadNVData() != 0)
574 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000575 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530576 }
577
578 if (setFlag & setAccessMode)
579 {
580 channelData[chNum].chAccess.chNonVolatileData.accessMode =
581 chAccessData.accessMode;
582 }
583 if (setFlag & setUserAuthEnabled)
584 {
585 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
586 chAccessData.userAuthDisabled;
587 }
588 if (setFlag & setMsgAuthEnabled)
589 {
590 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
591 chAccessData.perMsgAuthDisabled;
592 }
593 if (setFlag & setAlertingEnabled)
594 {
595 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
596 chAccessData.alertingDisabled;
597 }
598 if (setFlag & setPrivLimit)
599 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530600 // Send Update to network channel config interfaces over dbus
AppaRao Puli9613ed72018-09-01 23:46:44 +0530601 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530602 std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
603 "/" + channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530604 try
605 {
Johnathan Manteyf92261d2018-12-10 15:49:34 -0800606 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
607 networkChConfigIntfName,
AppaRao Puli9613ed72018-09-01 23:46:44 +0530608 privilegePropertyString, privStr))
609 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530610 log<level::DEBUG>(
611 "Network interface does not exist",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530612 entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000613 return ccUnspecifiedError;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530614 }
615 }
616 catch (const sdbusplus::exception::SdBusError& e)
617 {
618 log<level::ERR>("Exception: Network interface does not exist");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000619 return ccInvalidFieldRequest;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530620 }
621 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530622 channelData[chNum].chAccess.chNonVolatileData.privLimit =
623 chAccessData.privLimit;
624 }
625
626 // Write persistent data to file
627 if (writeChannelPersistData() != 0)
628 {
629 log<level::DEBUG>("Failed to update the presist data file");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000630 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530631 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000632 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530633}
634
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000635Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
636 uint8_t& authTypeSupported)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530637{
638 if (!isValidChannel(chNum))
639 {
640 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000641 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530642 }
643
644 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000645 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530646}
647
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000648Cc ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
649 const uint8_t priv,
650 EAuthType& authType)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530651{
652 if (!isValidChannel(chNum))
653 {
654 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000655 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530656 }
657
658 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
659 {
660 log<level::DEBUG>("Sessionless channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000661 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530662 }
663
664 if (!isValidPrivLimit(priv))
665 {
666 log<level::DEBUG>("Invalid privilege specified.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000667 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530668 }
669
670 // TODO: Hardcoded for now. Need to implement.
671 authType = EAuthType::none;
672
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000673 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530674}
675
676std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
677{
678 struct stat fileStat;
679 if (stat(fileName.c_str(), &fileStat) != 0)
680 {
681 log<level::DEBUG>("Error in getting last updated time stamp");
682 return -EIO;
683 }
684 return fileStat.st_mtime;
685}
686
687EChannelAccessMode
688 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
689{
690 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
691 if (iter == accessModeList.end())
692 {
693 log<level::ERR>("Invalid access mode.",
694 entry("MODE_STR=%s", mode.c_str()));
695 throw std::invalid_argument("Invalid access mode.");
696 }
697
698 return static_cast<EChannelAccessMode>(
699 std::distance(accessModeList.begin(), iter));
700}
701
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530702std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530703{
704 if (accessModeList.size() <= value)
705 {
706 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
707 throw std::invalid_argument("Invalid access mode.");
708 }
709
710 return accessModeList.at(value);
711}
712
713CommandPrivilege
714 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
715{
716 auto iter = std::find(privList.begin(), privList.end(), value);
717 if (iter == privList.end())
718 {
719 log<level::ERR>("Invalid privilege.",
720 entry("PRIV_STR=%s", value.c_str()));
721 throw std::invalid_argument("Invalid privilege.");
722 }
723
724 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
725}
726
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530727std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530728{
729 if (privList.size() <= value)
730 {
731 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
732 throw std::invalid_argument("Invalid privilege.");
733 }
734
735 return privList.at(value);
736}
737
738EChannelSessSupported
739 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
740{
741 auto iter =
742 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
743 if (iter == sessionSupportList.end())
744 {
745 log<level::ERR>("Invalid session supported.",
746 entry("SESS_STR=%s", value.c_str()));
747 throw std::invalid_argument("Invalid session supported.");
748 }
749
750 return static_cast<EChannelSessSupported>(
751 std::distance(sessionSupportList.begin(), iter));
752}
753
754EChannelMediumType
755 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
756{
757 std::unordered_map<std::string, EChannelMediumType>::iterator it =
758 mediumTypeMap.find(value);
759 if (it == mediumTypeMap.end())
760 {
761 log<level::ERR>("Invalid medium type.",
762 entry("MEDIUM_STR=%s", value.c_str()));
763 throw std::invalid_argument("Invalid medium type.");
764 }
765
766 return static_cast<EChannelMediumType>(it->second);
767}
768
769EChannelProtocolType
770 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
771{
772 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
773 protocolTypeMap.find(value);
774 if (it == protocolTypeMap.end())
775 {
776 log<level::ERR>("Invalid protocol type.",
777 entry("PROTO_STR=%s", value.c_str()));
778 throw std::invalid_argument("Invalid protocol type.");
779 }
780
781 return static_cast<EChannelProtocolType>(it->second);
782}
783
784Json ChannelConfig::readJsonFile(const std::string& configFile)
785{
786 std::ifstream jsonFile(configFile);
787 if (!jsonFile.good())
788 {
Richard Marian Thomaiyarc4196802019-06-03 19:27:48 +0530789 log<level::INFO>("JSON file not found",
790 entry("FILE_NAME=%s", configFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530791 return nullptr;
792 }
793
794 Json data = nullptr;
795 try
796 {
797 data = Json::parse(jsonFile, nullptr, false);
798 }
799 catch (Json::parse_error& e)
800 {
801 log<level::DEBUG>("Corrupted channel config.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530802 entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530803 throw std::runtime_error("Corrupted channel config file");
804 }
805
806 return data;
807}
808
809int ChannelConfig::writeJsonFile(const std::string& configFile,
810 const Json& jsonData)
811{
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530812 const std::string tmpFile = configFile + "_tmp";
813 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
814 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
815 if (fd < 0)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530816 {
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530817 log<level::ERR>("Error in creating json file",
818 entry("FILE_NAME = %s", tmpFile.c_str()));
819 return -EIO;
820 }
821 const auto& writeData = jsonData.dump();
822 if (write(fd, writeData.c_str(), writeData.size()) !=
823 static_cast<ssize_t>(writeData.size()))
824 {
825 close(fd);
826 log<level::ERR>("Error in writing configuration file",
827 entry("FILE_NAME = %s", tmpFile.c_str()));
828 return -EIO;
829 }
830 close(fd);
831
832 if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
833 {
834 log<level::ERR>("Error in renaming temporary data file",
835 entry("FILE_NAME = %s", tmpFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530836 return -EIO;
837 }
838
AppaRao Puli071f3f22018-05-24 16:45:30 +0530839 return 0;
840}
841
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530842void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530843 const std::string& chName)
844{
845 channelData[chNum].chName = chName;
846 channelData[chNum].chID = chNum;
847 channelData[chNum].isChValid = false;
848 channelData[chNum].activeSessCount = 0;
849
850 channelData[chNum].chInfo.mediumType = defaultMediumType;
851 channelData[chNum].chInfo.protocolType = defaultProtocolType;
852 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
853 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
854 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
855}
856
857int ChannelConfig::loadChannelConfig()
858{
859 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
860 channelLock{*channelMutex};
861
862 Json data = readJsonFile(channelConfigDefaultFilename);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800863 if (data.empty())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530864 {
865 log<level::DEBUG>("Error in opening IPMI Channel data file");
866 return -EIO;
867 }
868
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800869 channelData.fill(ChannelProperties{});
870
871 for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530872 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800873 try
AppaRao Puli071f3f22018-05-24 16:45:30 +0530874 {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530875 std::string chKey = std::to_string(chNum);
876 Json jsonChData = data[chKey].get<Json>();
877 if (jsonChData.is_null())
878 {
879 log<level::WARNING>(
880 "Channel not configured so loading default.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530881 entry("CHANNEL_NUM=%d", chNum));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530882 // If user didn't want to configure specific channel (say
883 // reserved channel), then load that index with default values.
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800884 setDefaultChannelConfig(chNum, defaultChannelName);
885 continue;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530886 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800887 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
888 if (jsonChInfo.is_null())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530889 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800890 log<level::ERR>("Invalid/corrupted channel config file");
891 return -EBADMSG;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530892 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800893
894 ChannelProperties& chData = channelData[chNum];
895 chData.chName = jsonChData[nameString].get<std::string>();
896 chData.chID = chNum;
897 chData.isChValid = jsonChData[isValidString].get<bool>();
898 chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
899 chData.maxTransferSize =
900 jsonChData.value(maxTransferSizeString, smallChannelSize);
901 std::string medTypeStr =
902 jsonChInfo[mediumTypeString].get<std::string>();
903 chData.chInfo.mediumType =
904 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
905 std::string protoTypeStr =
906 jsonChInfo[protocolTypeString].get<std::string>();
907 chData.chInfo.protocolType =
908 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
909 std::string sessStr =
910 jsonChInfo[sessionSupportedString].get<std::string>();
911 chData.chInfo.sessionSupported =
912 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
913 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
914 chData.chInfo.authTypeSupported = defaultAuthType;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530915 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800916 catch (const Json::exception& e)
917 {
918 log<level::DEBUG>("Json Exception caught.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530919 entry("MSG=%s", e.what()));
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800920 return -EBADMSG;
921 }
922 catch (const std::invalid_argument& e)
923 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530924 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800925 return -EBADMSG;
926 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530927 }
928
929 return 0;
930}
931
932int ChannelConfig::readChannelVolatileData()
933{
934 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
935 channelLock{*channelMutex};
936
937 Json data = readJsonFile(channelVolatileDataFilename);
938 if (data == nullptr)
939 {
940 log<level::DEBUG>("Error in opening IPMI Channel data file");
941 return -EIO;
942 }
AppaRao Puli071f3f22018-05-24 16:45:30 +0530943 try
944 {
945 // Fill in global structure
946 for (auto it = data.begin(); it != data.end(); ++it)
947 {
948 std::string chKey = it.key();
949 uint8_t chNum = std::stoi(chKey, nullptr, 10);
950 if ((chNum < 0) || (chNum > maxIpmiChannels))
951 {
952 log<level::DEBUG>(
953 "Invalid channel access entry in config file");
954 throw std::out_of_range("Out of range - channel number");
955 }
956 Json jsonChData = it.value();
957 if (!jsonChData.is_null())
958 {
959 std::string accModeStr =
960 jsonChData[accessModeString].get<std::string>();
961 channelData[chNum].chAccess.chVolatileData.accessMode =
962 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
963 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
964 jsonChData[userAuthDisabledString].get<bool>();
965 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
966 jsonChData[perMsgAuthDisabledString].get<bool>();
967 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
968 jsonChData[alertingDisabledString].get<bool>();
969 std::string privStr =
970 jsonChData[privLimitString].get<std::string>();
971 channelData[chNum].chAccess.chVolatileData.privLimit =
972 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
973 }
974 else
975 {
976 log<level::ERR>(
977 "Invalid/corrupted volatile channel access file",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530978 entry("FILE=%s", channelVolatileDataFilename));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530979 throw std::runtime_error(
980 "Corrupted volatile channel access file");
981 }
982 }
983 }
984 catch (const Json::exception& e)
985 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530986 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530987 throw std::runtime_error("Corrupted volatile channel access file");
988 }
989 catch (const std::invalid_argument& e)
990 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530991 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530992 throw std::runtime_error("Corrupted volatile channel access file");
993 }
994
995 // Update the timestamp
996 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
997 return 0;
998}
999
1000int ChannelConfig::readChannelPersistData()
1001{
1002 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1003 channelLock{*channelMutex};
1004
1005 Json data = readJsonFile(channelNvDataFilename);
1006 if (data == nullptr)
1007 {
1008 log<level::DEBUG>("Error in opening IPMI Channel data file");
1009 return -EIO;
1010 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301011 try
1012 {
1013 // Fill in global structure
1014 for (auto it = data.begin(); it != data.end(); ++it)
1015 {
1016 std::string chKey = it.key();
1017 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1018 if ((chNum < 0) || (chNum > maxIpmiChannels))
1019 {
1020 log<level::DEBUG>(
1021 "Invalid channel access entry in config file");
1022 throw std::out_of_range("Out of range - channel number");
1023 }
1024 Json jsonChData = it.value();
1025 if (!jsonChData.is_null())
1026 {
1027 std::string accModeStr =
1028 jsonChData[accessModeString].get<std::string>();
1029 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1030 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1031 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1032 jsonChData[userAuthDisabledString].get<bool>();
1033 channelData[chNum]
1034 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1035 jsonChData[perMsgAuthDisabledString].get<bool>();
1036 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1037 jsonChData[alertingDisabledString].get<bool>();
1038 std::string privStr =
1039 jsonChData[privLimitString].get<std::string>();
1040 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1041 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1042 }
1043 else
1044 {
1045 log<level::ERR>("Invalid/corrupted nv channel access file",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301046 entry("FILE=%s", channelNvDataFilename));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301047 throw std::runtime_error("Corrupted nv channel access file");
1048 }
1049 }
1050 }
1051 catch (const Json::exception& e)
1052 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301053 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301054 throw std::runtime_error("Corrupted nv channel access file");
1055 }
1056 catch (const std::invalid_argument& e)
1057 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301058 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301059 throw std::runtime_error("Corrupted nv channel access file");
1060 }
1061
1062 // Update the timestamp
1063 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1064 return 0;
1065}
1066
1067int ChannelConfig::writeChannelVolatileData()
1068{
1069 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1070 channelLock{*channelMutex};
1071 Json outData;
1072
1073 try
1074 {
1075 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1076 {
1077 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1078 {
1079 Json jsonObj;
1080 std::string chKey = std::to_string(chNum);
1081 std::string accModeStr = convertToAccessModeString(
1082 channelData[chNum].chAccess.chVolatileData.accessMode);
1083 jsonObj[accessModeString] = accModeStr;
1084 jsonObj[userAuthDisabledString] =
1085 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1086 jsonObj[perMsgAuthDisabledString] =
1087 channelData[chNum]
1088 .chAccess.chVolatileData.perMsgAuthDisabled;
1089 jsonObj[alertingDisabledString] =
1090 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1091 std::string privStr = convertToPrivLimitString(
1092 channelData[chNum].chAccess.chVolatileData.privLimit);
1093 jsonObj[privLimitString] = privStr;
1094
1095 outData[chKey] = jsonObj;
1096 }
1097 }
1098 }
1099 catch (const std::invalid_argument& e)
1100 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301101 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301102 return -EINVAL;
1103 }
1104
1105 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1106 {
1107 log<level::DEBUG>("Error in write JSON data to file");
1108 return -EIO;
1109 }
1110
1111 // Update the timestamp
1112 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1113 return 0;
1114}
1115
1116int ChannelConfig::writeChannelPersistData()
1117{
1118 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1119 channelLock{*channelMutex};
1120 Json outData;
1121
1122 try
1123 {
1124 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1125 {
1126 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1127 {
1128 Json jsonObj;
1129 std::string chKey = std::to_string(chNum);
1130 std::string accModeStr = convertToAccessModeString(
1131 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1132 jsonObj[accessModeString] = accModeStr;
1133 jsonObj[userAuthDisabledString] =
1134 channelData[chNum]
1135 .chAccess.chNonVolatileData.userAuthDisabled;
1136 jsonObj[perMsgAuthDisabledString] =
1137 channelData[chNum]
1138 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1139 jsonObj[alertingDisabledString] =
1140 channelData[chNum]
1141 .chAccess.chNonVolatileData.alertingDisabled;
1142 std::string privStr = convertToPrivLimitString(
1143 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1144 jsonObj[privLimitString] = privStr;
1145
1146 outData[chKey] = jsonObj;
1147 }
1148 }
1149 }
1150 catch (const std::invalid_argument& e)
1151 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301152 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301153 return -EINVAL;
1154 }
1155
1156 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1157 {
1158 log<level::DEBUG>("Error in write JSON data to file");
1159 return -EIO;
1160 }
1161
1162 // Update the timestamp
1163 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1164 return 0;
1165}
1166
1167int ChannelConfig::checkAndReloadNVData()
1168{
1169 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1170 int ret = 0;
1171 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1172 {
1173 try
1174 {
1175 ret = readChannelPersistData();
1176 }
1177 catch (const std::exception& e)
1178 {
1179 log<level::ERR>("Exception caught in readChannelPersistData.",
1180 entry("MSG=%s", e.what()));
1181 ret = -EIO;
1182 }
1183 }
1184 return ret;
1185}
1186
1187int ChannelConfig::checkAndReloadVolatileData()
1188{
1189 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1190 int ret = 0;
1191 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1192 {
1193 try
1194 {
1195 ret = readChannelVolatileData();
1196 }
1197 catch (const std::exception& e)
1198 {
1199 log<level::ERR>("Exception caught in readChannelVolatileData.",
1200 entry("MSG=%s", e.what()));
1201 ret = -EIO;
1202 }
1203 }
1204 return ret;
1205}
1206
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001207int ChannelConfig::setDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301208 const std::string& objPath,
1209 const std::string& interface,
1210 const std::string& property,
1211 const DbusVariant& value)
1212{
1213 try
1214 {
1215 auto method =
1216 bus.new_method_call(service.c_str(), objPath.c_str(),
1217 "org.freedesktop.DBus.Properties", "Set");
1218
1219 method.append(interface, property, value);
1220
1221 auto reply = bus.call(method);
1222 }
1223 catch (const sdbusplus::exception::SdBusError& e)
1224 {
1225 log<level::DEBUG>("set-property failed",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301226 entry("SERVICE=%s", service.c_str()),
1227 entry("OBJPATH=%s", objPath.c_str()),
1228 entry("INTERFACE=%s", interface.c_str()),
1229 entry("PROP=%s", property.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301230 return -EIO;
1231 }
1232
1233 return 0;
1234}
1235
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001236int ChannelConfig::getDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301237 const std::string& objPath,
1238 const std::string& interface,
1239 const std::string& property,
1240 DbusVariant& value)
1241{
1242 try
1243 {
1244 auto method =
1245 bus.new_method_call(service.c_str(), objPath.c_str(),
1246 "org.freedesktop.DBus.Properties", "Get");
1247
1248 method.append(interface, property);
1249
1250 auto reply = bus.call(method);
1251 reply.read(value);
1252 }
1253 catch (const sdbusplus::exception::SdBusError& e)
1254 {
1255 log<level::DEBUG>("get-property failed",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301256 entry("SERVICE=%s", service.c_str()),
1257 entry("OBJPATH=%s", objPath.c_str()),
1258 entry("INTERFACE=%s", interface.c_str()),
1259 entry("PROP=%s", property.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301260 return -EIO;
1261 }
1262 return 0;
1263}
1264
1265int ChannelConfig::syncNetworkChannelConfig()
1266{
1267 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1268 channelLock{*channelMutex};
1269 bool isUpdated = false;
1270 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1271 {
1272 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1273 {
1274 std::string intfPrivStr;
1275 try
1276 {
AppaRao Puli9613ed72018-09-01 23:46:44 +05301277 std::string networkIntfObj =
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301278 std::string(networkIntfObjectBasePath) + "/" +
1279 channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +05301280 DbusVariant variant;
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001281 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301282 networkChConfigIntfName,
1283 privilegePropertyString, variant))
1284 {
1285 log<level::DEBUG>("Network interface does not exist",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301286 entry("INTERFACE=%s",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301287 channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301288 continue;
1289 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001290 intfPrivStr = std::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301291 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001292 catch (const std::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301293 {
1294 log<level::DEBUG>(
1295 "exception: Network interface does not exist");
1296 continue;
1297 }
1298 catch (const sdbusplus::exception::SdBusError& e)
1299 {
1300 log<level::DEBUG>(
1301 "exception: Network interface does not exist");
1302 continue;
1303 }
1304
1305 uint8_t intfPriv =
1306 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1307 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1308 intfPriv)
1309 {
1310 isUpdated = true;
1311 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1312 intfPriv;
1313 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1314 }
1315 }
1316 }
1317
1318 if (isUpdated)
1319 {
1320 // Write persistent data to file
1321 if (writeChannelPersistData() != 0)
1322 {
1323 log<level::DEBUG>("Failed to update the persistent data file");
1324 return -EIO;
1325 }
1326 // Write Volatile data to file
1327 if (writeChannelVolatileData() != 0)
1328 {
1329 log<level::DEBUG>("Failed to update the channel volatile data");
1330 return -EIO;
1331 }
1332 }
1333
1334 return 0;
1335}
1336
AppaRao Puli071f3f22018-05-24 16:45:30 +05301337void ChannelConfig::initChannelPersistData()
1338{
Richard Marian Thomaiyare91474c2019-09-01 23:02:47 +05301339 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1340 channelLock{*channelMutex};
1341
AppaRao Puli071f3f22018-05-24 16:45:30 +05301342 /* Always read the channel config */
1343 if (loadChannelConfig() != 0)
1344 {
1345 log<level::ERR>("Failed to read channel config file");
1346 throw std::ios_base::failure("Failed to load channel configuration");
1347 }
1348
1349 /* Populate the channel persist data */
1350 if (readChannelPersistData() != 0)
1351 {
1352 // Copy default NV data to RW location
1353 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1354 channelNvDataFilename);
1355
1356 // Load the channel access NV data
1357 if (readChannelPersistData() != 0)
1358 {
1359 log<level::ERR>("Failed to read channel access NV data");
1360 throw std::ios_base::failure(
1361 "Failed to read channel access NV configuration");
1362 }
1363 }
1364
1365 // First check the volatile data file
1366 // If not present, load the default values
1367 if (readChannelVolatileData() != 0)
1368 {
1369 // Copy default volatile data to temporary location
1370 // NV file(channelNvDataFilename) must have created by now.
1371 std::experimental::filesystem::copy_file(channelNvDataFilename,
1372 channelVolatileDataFilename);
1373
1374 // Load the channel access volatile data
1375 if (readChannelVolatileData() != 0)
1376 {
1377 log<level::ERR>("Failed to read channel access volatile data");
1378 throw std::ios_base::failure(
1379 "Failed to read channel access volatile configuration");
1380 }
1381 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301382
1383 // Synchronize the channel config(priv) with network channel
1384 // configuration(priv) over dbus
1385 if (syncNetworkChannelConfig() != 0)
1386 {
1387 log<level::ERR>(
1388 "Failed to synchronize data with network channel config over dbus");
1389 throw std::ios_base::failure(
1390 "Failed to synchronize data with network channel config over dbus");
1391 }
1392
1393 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301394 return;
1395}
1396
1397} // namespace ipmi