blob: 574b058e59da54f25e29a576530cbdb78d54436d [file] [log] [blame]
AppaRao Puli071f3f22018-05-24 16:45:30 +05301/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "channel_mgmt.hpp"
18
19#include "apphandler.hpp"
20
21#include <sys/stat.h>
22#include <unistd.h>
23
24#include <boost/interprocess/sync/scoped_lock.hpp>
25#include <cerrno>
AppaRao Puli9613ed72018-09-01 23:46:44 +053026#include <exception>
AppaRao Puli071f3f22018-05-24 16:45:30 +053027#include <experimental/filesystem>
28#include <fstream>
29#include <phosphor-logging/log.hpp>
AppaRao Puli9613ed72018-09-01 23:46:44 +053030#include <sdbusplus/bus/match.hpp>
31#include <sdbusplus/server/object.hpp>
AppaRao Puli071f3f22018-05-24 16:45:30 +053032#include <unordered_map>
33
34namespace ipmi
35{
36
William A. Kennington IIIdfad4862018-11-19 17:45:35 -080037namespace variant_ns = sdbusplus::message::variant_ns;
AppaRao Puli071f3f22018-05-24 16:45:30 +053038using namespace phosphor::logging;
39
40static constexpr const char* channelAccessDefaultFilename =
41 "/usr/share/ipmi-providers/channel_access.json";
42static constexpr const char* channelConfigDefaultFilename =
43 "/usr/share/ipmi-providers/channel_config.json";
44static constexpr const char* channelNvDataFilename =
45 "/var/lib/ipmi/channel_access_nv.json";
46static constexpr const char* channelVolatileDataFilename =
47 "/run/ipmi/channel_access_volatile.json";
48
AppaRao Puli9613ed72018-09-01 23:46:44 +053049// TODO: Get the service name dynamically..
50static constexpr const char* networkIntfServiceName =
51 "xyz.openbmc_project.Network";
52static constexpr const char* networkIntfObjectBasePath =
53 "/xyz/openbmc_project/network";
54static constexpr const char* networkChConfigIntfName =
55 "xyz.openbmc_project.Channel.ChannelAccess";
56static constexpr const char* privilegePropertyString = "MaxPrivilege";
57static constexpr const char* dBusPropertiesInterface =
58 "org.freedesktop.DBus.Properties";
59static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
60
AppaRao Puli071f3f22018-05-24 16:45:30 +053061// STRING DEFINES: Should sync with key's in JSON
62static constexpr const char* nameString = "name";
63static constexpr const char* isValidString = "is_valid";
64static constexpr const char* activeSessionsString = "active_sessions";
Vernon Mauery58317122018-11-28 11:02:43 -080065static constexpr const char* maxTransferSizeString = "max_transfer_size";
AppaRao Puli071f3f22018-05-24 16:45:30 +053066static constexpr const char* channelInfoString = "channel_info";
67static constexpr const char* mediumTypeString = "medium_type";
68static constexpr const char* protocolTypeString = "protocol_type";
69static constexpr const char* sessionSupportedString = "session_supported";
70static constexpr const char* isIpmiString = "is_ipmi";
71static constexpr const char* authTypeSupportedString = "auth_type_supported";
72static constexpr const char* accessModeString = "access_mode";
73static constexpr const char* userAuthDisabledString = "user_auth_disabled";
74static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
75static constexpr const char* alertingDisabledString = "alerting_disabled";
76static constexpr const char* privLimitString = "priv_limit";
77static constexpr const char* authTypeEnabledString = "auth_type_enabled";
78
79// Default values
80static constexpr const char* defaultChannelName = "RESERVED";
81static constexpr const uint8_t defaultMediumType =
82 static_cast<uint8_t>(EChannelMediumType::reserved);
83static constexpr const uint8_t defaultProtocolType =
84 static_cast<uint8_t>(EChannelProtocolType::reserved);
85static constexpr const uint8_t defaultSessionSupported =
86 static_cast<uint8_t>(EChannelSessSupported::none);
87static constexpr const uint8_t defaultAuthType =
88 static_cast<uint8_t>(EAuthType::none);
89static constexpr const bool defaultIsIpmiState = false;
Vernon Mauery58317122018-11-28 11:02:43 -080090static constexpr size_t smallChannelSize = 64;
AppaRao Puli071f3f22018-05-24 16:45:30 +053091
AppaRao Puli9613ed72018-09-01 23:46:44 +053092std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal(nullptr);
93
AppaRao Puli071f3f22018-05-24 16:45:30 +053094// String mappings use in JSON config file
95static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
96 {"reserved", EChannelMediumType::reserved},
97 {"ipmb", EChannelMediumType::ipmb},
98 {"icmb-v1.0", EChannelMediumType::icmbV10},
99 {"icmb-v0.9", EChannelMediumType::icmbV09},
100 {"lan-802.3", EChannelMediumType::lan8032},
101 {"serial", EChannelMediumType::serial},
102 {"other-lan", EChannelMediumType::otherLan},
103 {"pci-smbus", EChannelMediumType::pciSmbus},
104 {"smbus-v1.0", EChannelMediumType::smbusV11},
105 {"smbus-v2.0", EChannelMediumType::smbusV20},
106 {"usb-1x", EChannelMediumType::usbV1x},
107 {"usb-2x", EChannelMediumType::usbV2x},
108 {"system-interface", EChannelMediumType::systemInterface},
109 {"oem", EChannelMediumType::oem},
110 {"unknown", EChannelMediumType::unknown}};
111
ssekarf4b2b092018-07-25 18:49:08 +0530112static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = {
Richard Marian Thomaiyar43cb1282018-12-08 17:22:53 +0530113 {interfaceKCS, "SMS"},
ssekarf4b2b092018-07-25 18:49:08 +0530114 {interfaceLAN1, "LAN1"},
115 {interfaceUnknown, "unknown"}};
116
AppaRao Puli071f3f22018-05-24 16:45:30 +0530117static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
118 {"na", EChannelProtocolType::na},
119 {"ipmb-1.0", EChannelProtocolType::ipmbV10},
120 {"icmb-2.0", EChannelProtocolType::icmbV11},
121 {"reserved", EChannelProtocolType::reserved},
122 {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
123 {"kcs", EChannelProtocolType::kcs},
124 {"smic", EChannelProtocolType::smic},
125 {"bt-10", EChannelProtocolType::bt10},
126 {"bt-15", EChannelProtocolType::bt15},
127 {"tmode", EChannelProtocolType::tMode},
128 {"oem", EChannelProtocolType::oem}};
129
130static std::array<std::string, 4> accessModeList = {
131 "disabled", "pre-boot", "always_available", "shared"};
132
133static std::array<std::string, 4> sessionSupportList = {
134 "session-less", "single-session", "multi-session", "session-based"};
135
136static std::array<std::string, PRIVILEGE_OEM + 1> privList = {
137 "priv-reserved", "priv-callback", "priv-user",
138 "priv-operator", "priv-admin", "priv-oem"};
139
AppaRao Puli9613ed72018-09-01 23:46:44 +0530140static constexpr const char* LAN1_STR = "LAN1";
141static constexpr const char* LAN2_STR = "LAN2";
142static constexpr const char* LAN3_STR = "LAN3";
143static constexpr const char* ETH0_STR = "eth0";
144static constexpr const char* ETH1_STR = "eth1";
145static constexpr const char* ETH2_STR = "eth2";
146
147static std::unordered_map<std::string, std::string> channelToInterfaceMap = {
148 {LAN1_STR, ETH0_STR}, {LAN2_STR, ETH1_STR}, {LAN3_STR, ETH2_STR}};
149
150static std::unordered_map<std::string, std::string> interfaceToChannelMap = {
151 {ETH0_STR, LAN1_STR}, {ETH1_STR, LAN2_STR}, {ETH2_STR, LAN3_STR}};
152
153std::string convertToChannelName(const std::string& intfName)
154{
155
156 auto it = interfaceToChannelMap.find(intfName);
157 if (it == interfaceToChannelMap.end())
158 {
159 log<level::ERR>("Invalid network interface.",
160 entry("INTF:%s", intfName.c_str()));
161 throw std::invalid_argument("Invalid network interface");
162 }
163
164 return it->second;
165}
166
167std::string getNetIntfFromPath(const std::string& path)
168{
169 std::size_t pos = path.find(networkIntfObjectBasePath);
170 if (pos == std::string::npos)
171 {
172 log<level::ERR>("Invalid interface path.",
173 entry("PATH:%s", path.c_str()));
174 throw std::invalid_argument("Invalid interface path");
175 }
176 std::string intfName =
177 path.substr(pos + strlen(networkIntfObjectBasePath) + 1);
178 return intfName;
179}
180
181void processChAccessPropChange(ChannelConfig& chConfig, const std::string& path,
182 const DbusChObjProperties& chProperties)
183{
184 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
185 std::string intfName;
186 try
187 {
188 intfName = getNetIntfFromPath(path);
189 }
190 catch (const std::invalid_argument& e)
191 {
192 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
193 return;
194 }
195
196 // Get the MaxPrivilege property value from the signal
197 std::string intfPrivStr;
198 std::string propName;
199 for (const auto& prop : chProperties)
200 {
201 if (prop.first == privilegePropertyString)
202 {
203 propName = privilegePropertyString;
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800204 intfPrivStr = variant_ns::get<std::string>(prop.second);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530205 break;
206 }
207 }
208
209 if (propName != privilegePropertyString)
210 {
211 log<level::ERR>("Unknown signal caught.");
212 return;
213 }
214
215 if (intfPrivStr.empty())
216 {
217 log<level::ERR>("Invalid privilege string.",
218 entry("INTF:%s", intfName.c_str()));
219 return;
220 }
221
222 uint8_t intfPriv = 0;
223 std::string channelName;
224 try
225 {
226 intfPriv =
227 static_cast<uint8_t>(chConfig.convertToPrivLimitIndex(intfPrivStr));
228 channelName = convertToChannelName(intfName);
229 }
230 catch (const std::invalid_argument& e)
231 {
232 log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
233 return;
234 }
235
236 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
237 channelLock{*chConfig.channelMutex};
238 uint8_t chNum = 0;
239 ChannelData* chData;
240 // Get the channel number based on the channel name.
241 for (chNum = 0; chNum < maxIpmiChannels; chNum++)
242 {
243 chData = chConfig.getChannelDataPtr(chNum);
244 if (chData->chName == channelName)
245 {
246 break;
247 }
248 }
249 if (chNum >= maxIpmiChannels)
250 {
251 log<level::ERR>("Invalid interface in signal path");
252 return;
253 }
254
255 // skip updating the values, if this property change originated from IPMI.
256 if (chConfig.signalFlag & (1 << chNum))
257 {
258 chConfig.signalFlag &= ~(1 << chNum);
259 log<level::DEBUG>("Request originated from IPMI so ignoring signal");
260 return;
261 }
262
263 // Update both volatile & Non-volatile, if there is mismatch.
264 // as property change other than IPMI, has to update both volatile &
265 // non-volatile data.
266 if (chData->chAccess.chNonVolatileData.privLimit != intfPriv)
267 {
268 // Update NV data
269 chData->chAccess.chNonVolatileData.privLimit = intfPriv;
270 if (chConfig.writeChannelPersistData() != 0)
271 {
272 log<level::ERR>("Failed to update the persist data file");
273 return;
274 }
275
276 // Update Volatile data
277 if (chData->chAccess.chVolatileData.privLimit != intfPriv)
278 {
279 chData->chAccess.chVolatileData.privLimit = intfPriv;
280 if (chConfig.writeChannelVolatileData() != 0)
281 {
282 log<level::ERR>("Failed to update the volatile data file");
283 return;
284 }
285 }
286 }
287
288 return;
289}
290
AppaRao Puli071f3f22018-05-24 16:45:30 +0530291ChannelConfig& getChannelConfigObject()
292{
293 static ChannelConfig channelConfig;
294 return channelConfig;
295}
296
AppaRao Puli9613ed72018-09-01 23:46:44 +0530297ChannelConfig::~ChannelConfig()
298{
299 if (signalHndlrObjectState)
300 {
301 chPropertiesSignal.reset();
302 sigHndlrLock.unlock();
303 }
304}
305
AppaRao Puli071f3f22018-05-24 16:45:30 +0530306ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
307{
308 std::ofstream mutexCleanUpFile;
309 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
310 std::ofstream::out | std::ofstream::app);
311 if (!mutexCleanUpFile.good())
312 {
313 log<level::DEBUG>("Unable to open mutex cleanup file");
314 return;
315 }
316 mutexCleanUpFile.close();
317 mutexCleanupLock =
318 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
319 if (mutexCleanupLock.try_lock())
320 {
321 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
322 channelMutex =
323 std::make_unique<boost::interprocess::named_recursive_mutex>(
324 boost::interprocess::open_or_create, ipmiChannelMutex);
325 mutexCleanupLock.lock_sharable();
326 }
327 else
328 {
329 mutexCleanupLock.lock_sharable();
330 channelMutex =
331 std::make_unique<boost::interprocess::named_recursive_mutex>(
332 boost::interprocess::open_or_create, ipmiChannelMutex);
333 }
334
335 initChannelPersistData();
AppaRao Puli9613ed72018-09-01 23:46:44 +0530336
337 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
338 // Register it for single object and single process either netipimd /
339 // host-ipmid
340 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
341 {
342 log<level::DEBUG>("Registering channel signal handler.");
343 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
344 bus,
345 sdbusplus::bus::match::rules::path_namespace(
346 networkIntfObjectBasePath) +
347 sdbusplus::bus::match::rules::type::signal() +
348 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
349 sdbusplus::bus::match::rules::interface(
350 dBusPropertiesInterface) +
351 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
352 [&](sdbusplus::message::message& msg) {
353 DbusChObjProperties props;
354 std::string iface;
355 std::string path = msg.get_path();
356 msg.read(iface, props);
357 processChAccessPropChange(*this, path, props);
358 });
359 signalHndlrObjectState = true;
360 }
361}
362
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530363ChannelData* ChannelConfig::getChannelDataPtr(const uint8_t chNum)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530364{
365 // reload data before using it.
366 checkAndReloadVolatileData();
367 return &channelData[chNum];
AppaRao Puli071f3f22018-05-24 16:45:30 +0530368}
369
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530370bool ChannelConfig::isValidChannel(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530371{
372 if (chNum > maxIpmiChannels)
373 {
374 log<level::DEBUG>("Invalid channel ID - Out of range");
375 return false;
376 }
377
378 if (channelData[chNum].isChValid == false)
379 {
380 log<level::DEBUG>("Channel is not valid");
381 return false;
382 }
383
384 return true;
385}
386
387EChannelSessSupported
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530388 ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530389{
390 EChannelSessSupported chSessSupport =
391 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
392 return chSessSupport;
393}
394
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530395bool ChannelConfig::isValidAuthType(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530396 const EAuthType& authType)
397{
398 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
399 {
400 log<level::DEBUG>("Invalid authentication type");
401 return false;
402 }
403
404 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
405 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
406 {
407 log<level::DEBUG>("Authentication type is not supported.");
408 return false;
409 }
410
411 return true;
412}
413
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530414int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530415{
416 // TODO: TEMPORARY FIX
417 // Channels active session count is managed separatly
418 // by monitoring channel session which includes LAN and
419 // RAKP layer changes. This will be updated, once the
420 // authentication part is implemented.
421 return channelData[chNum].activeSessCount;
422}
423
Vernon Mauery58317122018-11-28 11:02:43 -0800424size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
425{
426 return channelData[chNum].maxTransferSize;
427}
428
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530429ipmi_ret_t ChannelConfig::getChannelInfo(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530430 ChannelInfo& chInfo)
431{
432 if (!isValidChannel(chNum))
433 {
434 log<level::DEBUG>("Invalid channel");
435 return IPMI_CC_INVALID_FIELD_REQUEST;
436 }
437
438 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
439 sizeof(channelData[chNum].chInfo),
440 reinterpret_cast<uint8_t*>(&chInfo));
441
442 return IPMI_CC_OK;
443}
444
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530445ipmi_ret_t ChannelConfig::getChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530446 ChannelAccess& chAccessData)
447{
448 if (!isValidChannel(chNum))
449 {
450 log<level::DEBUG>("Invalid channel");
451 return IPMI_CC_INVALID_FIELD_REQUEST;
452 }
453
454 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
455 {
456 log<level::DEBUG>("Session-less channel doesn't have access data.");
457 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
458 }
459
460 if (checkAndReloadVolatileData() != 0)
461 {
462 return IPMI_CC_UNSPECIFIED_ERROR;
463 }
464
465 std::copy_n(
466 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
467 sizeof(channelData[chNum].chAccess.chVolatileData),
468 reinterpret_cast<uint8_t*>(&chAccessData));
469
470 return IPMI_CC_OK;
471}
472
473ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530474 ChannelConfig::setChannelAccessData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530475 const ChannelAccess& chAccessData,
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530476 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530477{
478 if (!isValidChannel(chNum))
479 {
480 log<level::DEBUG>("Invalid channel");
481 return IPMI_CC_INVALID_FIELD_REQUEST;
482 }
483
484 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
485 {
486 log<level::DEBUG>("Session-less channel doesn't have access data.");
487 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
488 }
489
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530490 if (((setFlag & setAccessMode) &&
491 (!isValidAccessMode(chAccessData.accessMode))) ||
492 ((setFlag & setPrivLimit) &&
493 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530494 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530495 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530496 return IPMI_CC_INVALID_FIELD_REQUEST;
497 }
498
499 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
500 channelLock{*channelMutex};
501
502 if (checkAndReloadVolatileData() != 0)
503 {
504 return IPMI_CC_UNSPECIFIED_ERROR;
505 }
506
507 if (setFlag & setAccessMode)
508 {
509 channelData[chNum].chAccess.chVolatileData.accessMode =
510 chAccessData.accessMode;
511 }
512 if (setFlag & setUserAuthEnabled)
513 {
514 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
515 chAccessData.userAuthDisabled;
516 }
517 if (setFlag & setMsgAuthEnabled)
518 {
519 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
520 chAccessData.perMsgAuthDisabled;
521 }
522 if (setFlag & setAlertingEnabled)
523 {
524 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
525 chAccessData.alertingDisabled;
526 }
527 if (setFlag & setPrivLimit)
528 {
529 channelData[chNum].chAccess.chVolatileData.privLimit =
530 chAccessData.privLimit;
531 }
532
533 // Write Volatile data to file
534 if (writeChannelVolatileData() != 0)
535 {
536 log<level::DEBUG>("Failed to update the channel volatile data");
537 return IPMI_CC_UNSPECIFIED_ERROR;
538 }
539 return IPMI_CC_OK;
540}
541
542ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530543 ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530544 ChannelAccess& chAccessData)
545{
546 if (!isValidChannel(chNum))
547 {
548 log<level::DEBUG>("Invalid channel");
549 return IPMI_CC_INVALID_FIELD_REQUEST;
550 }
551
552 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
553 {
554 log<level::DEBUG>("Session-less channel doesn't have access data.");
555 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
556 }
557
558 if (checkAndReloadNVData() != 0)
559 {
560 return IPMI_CC_UNSPECIFIED_ERROR;
561 }
562
563 std::copy_n(reinterpret_cast<uint8_t*>(
564 &channelData[chNum].chAccess.chNonVolatileData),
565 sizeof(channelData[chNum].chAccess.chNonVolatileData),
566 reinterpret_cast<uint8_t*>(&chAccessData));
567
568 return IPMI_CC_OK;
569}
570
571ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530572 const uint8_t chNum, const ChannelAccess& chAccessData,
573 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530574{
575 if (!isValidChannel(chNum))
576 {
577 log<level::DEBUG>("Invalid channel");
578 return IPMI_CC_INVALID_FIELD_REQUEST;
579 }
580
581 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
582 {
583 log<level::DEBUG>("Session-less channel doesn't have access data.");
584 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
585 }
586
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530587 if (((setFlag & setAccessMode) &&
588 (!isValidAccessMode(chAccessData.accessMode))) ||
589 ((setFlag & setPrivLimit) &&
590 (!isValidPrivLimit(chAccessData.privLimit))))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530591 {
Richard Marian Thomaiyar93411602019-01-29 10:56:57 +0530592 log<level::DEBUG>("Invalid access mode / privilege limit specified");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530593 return IPMI_CC_INVALID_FIELD_REQUEST;
594 }
595
596 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
597 channelLock{*channelMutex};
598
599 if (checkAndReloadNVData() != 0)
600 {
601 return IPMI_CC_UNSPECIFIED_ERROR;
602 }
603
604 if (setFlag & setAccessMode)
605 {
606 channelData[chNum].chAccess.chNonVolatileData.accessMode =
607 chAccessData.accessMode;
608 }
609 if (setFlag & setUserAuthEnabled)
610 {
611 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
612 chAccessData.userAuthDisabled;
613 }
614 if (setFlag & setMsgAuthEnabled)
615 {
616 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
617 chAccessData.perMsgAuthDisabled;
618 }
619 if (setFlag & setAlertingEnabled)
620 {
621 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
622 chAccessData.alertingDisabled;
623 }
624 if (setFlag & setPrivLimit)
625 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530626 // Send Update to network channel config interfaces over dbus
627 std::string intfName = convertToNetInterface(channelData[chNum].chName);
628 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
629 std::string networkIntfObj =
630 std::string(networkIntfObjectBasePath) + "/" + intfName;
631 try
632 {
633 if (0 != setDbusProperty(bus, networkIntfServiceName,
634 networkIntfObj, networkChConfigIntfName,
635 privilegePropertyString, privStr))
636 {
637 log<level::DEBUG>("Network interface does not exist",
638 entry("INTERFACE:%s", intfName.c_str()));
639 return IPMI_CC_UNSPECIFIED_ERROR;
640 }
641 }
642 catch (const sdbusplus::exception::SdBusError& e)
643 {
644 log<level::ERR>("Exception: Network interface does not exist");
645 return IPMI_CC_INVALID_FIELD_REQUEST;
646 }
647 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530648 channelData[chNum].chAccess.chNonVolatileData.privLimit =
649 chAccessData.privLimit;
650 }
651
652 // Write persistent data to file
653 if (writeChannelPersistData() != 0)
654 {
655 log<level::DEBUG>("Failed to update the presist data file");
656 return IPMI_CC_UNSPECIFIED_ERROR;
657 }
658 return IPMI_CC_OK;
659}
660
661ipmi_ret_t
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530662 ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530663 uint8_t& authTypeSupported)
664{
665 if (!isValidChannel(chNum))
666 {
667 log<level::DEBUG>("Invalid channel");
668 return IPMI_CC_INVALID_FIELD_REQUEST;
669 }
670
671 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
672 return IPMI_CC_OK;
673}
674
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530675ipmi_ret_t ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
676 const uint8_t priv,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530677 EAuthType& authType)
678{
679 if (!isValidChannel(chNum))
680 {
681 log<level::DEBUG>("Invalid channel");
682 return IPMI_CC_INVALID_FIELD_REQUEST;
683 }
684
685 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
686 {
687 log<level::DEBUG>("Sessionless channel doesn't have access data.");
688 return IPMI_CC_INVALID_FIELD_REQUEST;
689 }
690
691 if (!isValidPrivLimit(priv))
692 {
693 log<level::DEBUG>("Invalid privilege specified.");
694 return IPMI_CC_INVALID_FIELD_REQUEST;
695 }
696
697 // TODO: Hardcoded for now. Need to implement.
698 authType = EAuthType::none;
699
700 return IPMI_CC_OK;
701}
702
703std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
704{
705 struct stat fileStat;
706 if (stat(fileName.c_str(), &fileStat) != 0)
707 {
708 log<level::DEBUG>("Error in getting last updated time stamp");
709 return -EIO;
710 }
711 return fileStat.st_mtime;
712}
713
714EChannelAccessMode
715 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
716{
717 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
718 if (iter == accessModeList.end())
719 {
720 log<level::ERR>("Invalid access mode.",
721 entry("MODE_STR=%s", mode.c_str()));
722 throw std::invalid_argument("Invalid access mode.");
723 }
724
725 return static_cast<EChannelAccessMode>(
726 std::distance(accessModeList.begin(), iter));
727}
728
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530729std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530730{
731 if (accessModeList.size() <= value)
732 {
733 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
734 throw std::invalid_argument("Invalid access mode.");
735 }
736
737 return accessModeList.at(value);
738}
739
740CommandPrivilege
741 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
742{
743 auto iter = std::find(privList.begin(), privList.end(), value);
744 if (iter == privList.end())
745 {
746 log<level::ERR>("Invalid privilege.",
747 entry("PRIV_STR=%s", value.c_str()));
748 throw std::invalid_argument("Invalid privilege.");
749 }
750
751 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
752}
753
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530754std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530755{
756 if (privList.size() <= value)
757 {
758 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
759 throw std::invalid_argument("Invalid privilege.");
760 }
761
762 return privList.at(value);
763}
764
765EChannelSessSupported
766 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
767{
768 auto iter =
769 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
770 if (iter == sessionSupportList.end())
771 {
772 log<level::ERR>("Invalid session supported.",
773 entry("SESS_STR=%s", value.c_str()));
774 throw std::invalid_argument("Invalid session supported.");
775 }
776
777 return static_cast<EChannelSessSupported>(
778 std::distance(sessionSupportList.begin(), iter));
779}
780
781EChannelMediumType
782 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
783{
784 std::unordered_map<std::string, EChannelMediumType>::iterator it =
785 mediumTypeMap.find(value);
786 if (it == mediumTypeMap.end())
787 {
788 log<level::ERR>("Invalid medium type.",
789 entry("MEDIUM_STR=%s", value.c_str()));
790 throw std::invalid_argument("Invalid medium type.");
791 }
792
793 return static_cast<EChannelMediumType>(it->second);
794}
795
796EChannelProtocolType
797 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
798{
799 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
800 protocolTypeMap.find(value);
801 if (it == protocolTypeMap.end())
802 {
803 log<level::ERR>("Invalid protocol type.",
804 entry("PROTO_STR=%s", value.c_str()));
805 throw std::invalid_argument("Invalid protocol type.");
806 }
807
808 return static_cast<EChannelProtocolType>(it->second);
809}
810
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530811uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
ssekarf4b2b092018-07-25 18:49:08 +0530812{
813
814 // TODO: There is limitation in current design. we cannot detect exact
815 // LAN interface(eth0 or eth1) so Implementation may be updated
816 // when there is any design update to figure out all the interfaces
817 // independently based on the message.
818
819 static uint8_t curChannel = 0xFF;
820
821 if (curChannel == 0xFF)
822 {
823 auto it = interfaceMap.find(getInterfaceIndex());
824 if (it == interfaceMap.end())
825 {
826 log<level::ERR>("Invalid Interface type ",
827 entry("InterfaceIndex: %d", getInterfaceIndex()));
828 throw std::invalid_argument("Invalid interface type.");
829 }
830
831 for (auto& channel : channelData)
832 {
833 std::string& interfaceName = it->second;
834 if (channel.chName == interfaceName)
835 {
836 curChannel = channel.chID;
837 break;
838 }
839 }
840 }
Richard Marian Thomaiyara39208e2018-12-08 17:27:11 +0530841 return ((chNum == currentChNum) ? curChannel : chNum);
ssekarf4b2b092018-07-25 18:49:08 +0530842}
843
AppaRao Puli9613ed72018-09-01 23:46:44 +0530844std::string ChannelConfig::convertToNetInterface(const std::string& value)
845{
846 auto it = channelToInterfaceMap.find(value);
847 if (it == channelToInterfaceMap.end())
848 {
849 log<level::DEBUG>("Invalid channel name.",
850 entry("NAME:%s", value.c_str()));
851 throw std::invalid_argument("Invalid channel name.");
852 }
853
854 return it->second;
855}
856
AppaRao Puli071f3f22018-05-24 16:45:30 +0530857Json ChannelConfig::readJsonFile(const std::string& configFile)
858{
859 std::ifstream jsonFile(configFile);
860 if (!jsonFile.good())
861 {
862 log<level::ERR>("JSON file not found");
863 return nullptr;
864 }
865
866 Json data = nullptr;
867 try
868 {
869 data = Json::parse(jsonFile, nullptr, false);
870 }
871 catch (Json::parse_error& e)
872 {
873 log<level::DEBUG>("Corrupted channel config.",
874 entry("MSG: %s", e.what()));
875 throw std::runtime_error("Corrupted channel config file");
876 }
877
878 return data;
879}
880
881int ChannelConfig::writeJsonFile(const std::string& configFile,
882 const Json& jsonData)
883{
884 std::ofstream jsonFile(configFile);
885 if (!jsonFile.good())
886 {
887 log<level::ERR>("JSON file not found");
888 return -EIO;
889 }
890
891 // Write JSON to file
892 jsonFile << jsonData;
893
894 jsonFile.flush();
895 return 0;
896}
897
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530898void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530899 const std::string& chName)
900{
901 channelData[chNum].chName = chName;
902 channelData[chNum].chID = chNum;
903 channelData[chNum].isChValid = false;
904 channelData[chNum].activeSessCount = 0;
905
906 channelData[chNum].chInfo.mediumType = defaultMediumType;
907 channelData[chNum].chInfo.protocolType = defaultProtocolType;
908 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
909 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
910 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
911}
912
913int ChannelConfig::loadChannelConfig()
914{
915 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
916 channelLock{*channelMutex};
917
918 Json data = readJsonFile(channelConfigDefaultFilename);
919 if (data == nullptr)
920 {
921 log<level::DEBUG>("Error in opening IPMI Channel data file");
922 return -EIO;
923 }
924
925 try
926 {
927 // Fill in global structure
928 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
929 {
930 std::fill(reinterpret_cast<uint8_t*>(&channelData[chNum]),
931 reinterpret_cast<uint8_t*>(&channelData[chNum]) +
932 sizeof(ChannelData),
933 0);
934 std::string chKey = std::to_string(chNum);
935 Json jsonChData = data[chKey].get<Json>();
936 if (jsonChData.is_null())
937 {
938 log<level::WARNING>(
939 "Channel not configured so loading default.",
940 entry("CHANNEL_NUM:%d", chNum));
941 // If user didn't want to configure specific channel (say
942 // reserved channel), then load that index with default values.
943 std::string chName(defaultChannelName);
944 setDefaultChannelConfig(chNum, chName);
945 }
946 else
947 {
948 std::string chName = jsonChData[nameString].get<std::string>();
949 channelData[chNum].chName = chName;
950 channelData[chNum].chID = chNum;
951 channelData[chNum].isChValid =
952 jsonChData[isValidString].get<bool>();
953 channelData[chNum].activeSessCount =
954 jsonChData.value(activeSessionsString, 0);
Vernon Mauery58317122018-11-28 11:02:43 -0800955 channelData[chNum].maxTransferSize =
956 jsonChData.value(maxTransferSizeString, smallChannelSize);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530957 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
958 if (jsonChInfo.is_null())
959 {
960 log<level::ERR>("Invalid/corrupted channel config file");
961 return -EBADMSG;
962 }
963 else
964 {
965 std::string medTypeStr =
966 jsonChInfo[mediumTypeString].get<std::string>();
967 channelData[chNum].chInfo.mediumType = static_cast<uint8_t>(
968 convertToMediumTypeIndex(medTypeStr));
969 std::string protoTypeStr =
970 jsonChInfo[protocolTypeString].get<std::string>();
971 channelData[chNum].chInfo.protocolType =
972 static_cast<uint8_t>(
973 convertToProtocolTypeIndex(protoTypeStr));
974 std::string sessStr =
975 jsonChInfo[sessionSupportedString].get<std::string>();
976 channelData[chNum].chInfo.sessionSupported =
977 static_cast<uint8_t>(
978 convertToSessionSupportIndex(sessStr));
979 channelData[chNum].chInfo.isIpmi =
980 jsonChInfo[isIpmiString].get<bool>();
981 channelData[chNum].chInfo.authTypeSupported =
982 defaultAuthType;
983 }
984 }
985 }
986 }
987 catch (const Json::exception& e)
988 {
989 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
990 return -EBADMSG;
991 }
992 catch (const std::invalid_argument& e)
993 {
994 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
995 return -EBADMSG;
996 }
997
998 return 0;
999}
1000
1001int ChannelConfig::readChannelVolatileData()
1002{
1003 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1004 channelLock{*channelMutex};
1005
1006 Json data = readJsonFile(channelVolatileDataFilename);
1007 if (data == nullptr)
1008 {
1009 log<level::DEBUG>("Error in opening IPMI Channel data file");
1010 return -EIO;
1011 }
1012
1013 try
1014 {
1015 // Fill in global structure
1016 for (auto it = data.begin(); it != data.end(); ++it)
1017 {
1018 std::string chKey = it.key();
1019 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1020 if ((chNum < 0) || (chNum > maxIpmiChannels))
1021 {
1022 log<level::DEBUG>(
1023 "Invalid channel access entry in config file");
1024 throw std::out_of_range("Out of range - channel number");
1025 }
1026 Json jsonChData = it.value();
1027 if (!jsonChData.is_null())
1028 {
1029 std::string accModeStr =
1030 jsonChData[accessModeString].get<std::string>();
1031 channelData[chNum].chAccess.chVolatileData.accessMode =
1032 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1033 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
1034 jsonChData[userAuthDisabledString].get<bool>();
1035 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
1036 jsonChData[perMsgAuthDisabledString].get<bool>();
1037 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
1038 jsonChData[alertingDisabledString].get<bool>();
1039 std::string privStr =
1040 jsonChData[privLimitString].get<std::string>();
1041 channelData[chNum].chAccess.chVolatileData.privLimit =
1042 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1043 }
1044 else
1045 {
1046 log<level::ERR>(
1047 "Invalid/corrupted volatile channel access file",
1048 entry("FILE: %s", channelVolatileDataFilename));
1049 throw std::runtime_error(
1050 "Corrupted volatile channel access file");
1051 }
1052 }
1053 }
1054 catch (const Json::exception& e)
1055 {
1056 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1057 throw std::runtime_error("Corrupted volatile channel access file");
1058 }
1059 catch (const std::invalid_argument& e)
1060 {
1061 log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
1062 throw std::runtime_error("Corrupted volatile channel access file");
1063 }
1064
1065 // Update the timestamp
1066 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1067 return 0;
1068}
1069
1070int ChannelConfig::readChannelPersistData()
1071{
1072 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1073 channelLock{*channelMutex};
1074
1075 Json data = readJsonFile(channelNvDataFilename);
1076 if (data == nullptr)
1077 {
1078 log<level::DEBUG>("Error in opening IPMI Channel data file");
1079 return -EIO;
1080 }
1081
1082 try
1083 {
1084 // Fill in global structure
1085 for (auto it = data.begin(); it != data.end(); ++it)
1086 {
1087 std::string chKey = it.key();
1088 uint8_t chNum = std::stoi(chKey, nullptr, 10);
1089 if ((chNum < 0) || (chNum > maxIpmiChannels))
1090 {
1091 log<level::DEBUG>(
1092 "Invalid channel access entry in config file");
1093 throw std::out_of_range("Out of range - channel number");
1094 }
1095 Json jsonChData = it.value();
1096 if (!jsonChData.is_null())
1097 {
1098 std::string accModeStr =
1099 jsonChData[accessModeString].get<std::string>();
1100 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1101 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1102 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1103 jsonChData[userAuthDisabledString].get<bool>();
1104 channelData[chNum]
1105 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1106 jsonChData[perMsgAuthDisabledString].get<bool>();
1107 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1108 jsonChData[alertingDisabledString].get<bool>();
1109 std::string privStr =
1110 jsonChData[privLimitString].get<std::string>();
1111 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1112 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1113 }
1114 else
1115 {
1116 log<level::ERR>("Invalid/corrupted nv channel access file",
1117 entry("FILE:%s", channelNvDataFilename));
1118 throw std::runtime_error("Corrupted nv channel access file");
1119 }
1120 }
1121 }
1122 catch (const Json::exception& e)
1123 {
1124 log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
1125 throw std::runtime_error("Corrupted nv channel access file");
1126 }
1127 catch (const std::invalid_argument& e)
1128 {
1129 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1130 throw std::runtime_error("Corrupted nv channel access file");
1131 }
1132
1133 // Update the timestamp
1134 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1135 return 0;
1136}
1137
1138int ChannelConfig::writeChannelVolatileData()
1139{
1140 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1141 channelLock{*channelMutex};
1142 Json outData;
1143
1144 try
1145 {
1146 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1147 {
1148 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1149 {
1150 Json jsonObj;
1151 std::string chKey = std::to_string(chNum);
1152 std::string accModeStr = convertToAccessModeString(
1153 channelData[chNum].chAccess.chVolatileData.accessMode);
1154 jsonObj[accessModeString] = accModeStr;
1155 jsonObj[userAuthDisabledString] =
1156 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1157 jsonObj[perMsgAuthDisabledString] =
1158 channelData[chNum]
1159 .chAccess.chVolatileData.perMsgAuthDisabled;
1160 jsonObj[alertingDisabledString] =
1161 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1162 std::string privStr = convertToPrivLimitString(
1163 channelData[chNum].chAccess.chVolatileData.privLimit);
1164 jsonObj[privLimitString] = privStr;
1165
1166 outData[chKey] = jsonObj;
1167 }
1168 }
1169 }
1170 catch (const std::invalid_argument& e)
1171 {
1172 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1173 return -EINVAL;
1174 }
1175
1176 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1177 {
1178 log<level::DEBUG>("Error in write JSON data to file");
1179 return -EIO;
1180 }
1181
1182 // Update the timestamp
1183 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1184 return 0;
1185}
1186
1187int ChannelConfig::writeChannelPersistData()
1188{
1189 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1190 channelLock{*channelMutex};
1191 Json outData;
1192
1193 try
1194 {
1195 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1196 {
1197 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1198 {
1199 Json jsonObj;
1200 std::string chKey = std::to_string(chNum);
1201 std::string accModeStr = convertToAccessModeString(
1202 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1203 jsonObj[accessModeString] = accModeStr;
1204 jsonObj[userAuthDisabledString] =
1205 channelData[chNum]
1206 .chAccess.chNonVolatileData.userAuthDisabled;
1207 jsonObj[perMsgAuthDisabledString] =
1208 channelData[chNum]
1209 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1210 jsonObj[alertingDisabledString] =
1211 channelData[chNum]
1212 .chAccess.chNonVolatileData.alertingDisabled;
1213 std::string privStr = convertToPrivLimitString(
1214 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1215 jsonObj[privLimitString] = privStr;
1216
1217 outData[chKey] = jsonObj;
1218 }
1219 }
1220 }
1221 catch (const std::invalid_argument& e)
1222 {
1223 log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
1224 return -EINVAL;
1225 }
1226
1227 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1228 {
1229 log<level::DEBUG>("Error in write JSON data to file");
1230 return -EIO;
1231 }
1232
1233 // Update the timestamp
1234 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1235 return 0;
1236}
1237
1238int ChannelConfig::checkAndReloadNVData()
1239{
1240 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1241 int ret = 0;
1242 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1243 {
1244 try
1245 {
1246 ret = readChannelPersistData();
1247 }
1248 catch (const std::exception& e)
1249 {
1250 log<level::ERR>("Exception caught in readChannelPersistData.",
1251 entry("MSG=%s", e.what()));
1252 ret = -EIO;
1253 }
1254 }
1255 return ret;
1256}
1257
1258int ChannelConfig::checkAndReloadVolatileData()
1259{
1260 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1261 int ret = 0;
1262 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1263 {
1264 try
1265 {
1266 ret = readChannelVolatileData();
1267 }
1268 catch (const std::exception& e)
1269 {
1270 log<level::ERR>("Exception caught in readChannelVolatileData.",
1271 entry("MSG=%s", e.what()));
1272 ret = -EIO;
1273 }
1274 }
1275 return ret;
1276}
1277
AppaRao Puli9613ed72018-09-01 23:46:44 +05301278int ChannelConfig::setDbusProperty(sdbusplus::bus::bus& bus,
1279 const std::string& service,
1280 const std::string& objPath,
1281 const std::string& interface,
1282 const std::string& property,
1283 const DbusVariant& value)
1284{
1285 try
1286 {
1287 auto method =
1288 bus.new_method_call(service.c_str(), objPath.c_str(),
1289 "org.freedesktop.DBus.Properties", "Set");
1290
1291 method.append(interface, property, value);
1292
1293 auto reply = bus.call(method);
1294 }
1295 catch (const sdbusplus::exception::SdBusError& e)
1296 {
1297 log<level::DEBUG>("set-property failed",
1298 entry("SERVICE:%s", service.c_str()),
1299 entry("OBJPATH:%s", objPath.c_str()),
1300 entry("INTERFACE:%s", interface.c_str()),
1301 entry("PROP:%s", property.c_str()));
1302 return -EIO;
1303 }
1304
1305 return 0;
1306}
1307
1308int ChannelConfig::getDbusProperty(sdbusplus::bus::bus& bus,
1309 const std::string& service,
1310 const std::string& objPath,
1311 const std::string& interface,
1312 const std::string& property,
1313 DbusVariant& value)
1314{
1315 try
1316 {
1317 auto method =
1318 bus.new_method_call(service.c_str(), objPath.c_str(),
1319 "org.freedesktop.DBus.Properties", "Get");
1320
1321 method.append(interface, property);
1322
1323 auto reply = bus.call(method);
1324 reply.read(value);
1325 }
1326 catch (const sdbusplus::exception::SdBusError& e)
1327 {
1328 log<level::DEBUG>("get-property failed",
1329 entry("SERVICE:%s", service.c_str()),
1330 entry("OBJPATH:%s", objPath.c_str()),
1331 entry("INTERFACE:%s", interface.c_str()),
1332 entry("PROP:%s", property.c_str()));
1333 return -EIO;
1334 }
1335 return 0;
1336}
1337
1338int ChannelConfig::syncNetworkChannelConfig()
1339{
1340 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1341 channelLock{*channelMutex};
1342 bool isUpdated = false;
1343 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1344 {
1345 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1346 {
1347 std::string intfPrivStr;
1348 try
1349 {
1350 std::string intfName =
1351 convertToNetInterface(channelData[chNum].chName);
1352 std::string networkIntfObj =
1353 std::string(networkIntfObjectBasePath) + "/" + intfName;
1354 DbusVariant variant;
1355 if (0 != getDbusProperty(bus, networkIntfServiceName,
1356 networkIntfObj,
1357 networkChConfigIntfName,
1358 privilegePropertyString, variant))
1359 {
1360 log<level::DEBUG>("Network interface does not exist",
1361 entry("INTERFACE:%s", intfName.c_str()));
1362 continue;
1363 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001364 intfPrivStr = variant_ns::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301365 }
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001366 catch (const variant_ns::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301367 {
1368 log<level::DEBUG>(
1369 "exception: Network interface does not exist");
1370 continue;
1371 }
1372 catch (const sdbusplus::exception::SdBusError& e)
1373 {
1374 log<level::DEBUG>(
1375 "exception: Network interface does not exist");
1376 continue;
1377 }
1378
1379 uint8_t intfPriv =
1380 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1381 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1382 intfPriv)
1383 {
1384 isUpdated = true;
1385 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1386 intfPriv;
1387 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1388 }
1389 }
1390 }
1391
1392 if (isUpdated)
1393 {
1394 // Write persistent data to file
1395 if (writeChannelPersistData() != 0)
1396 {
1397 log<level::DEBUG>("Failed to update the persistent data file");
1398 return -EIO;
1399 }
1400 // Write Volatile data to file
1401 if (writeChannelVolatileData() != 0)
1402 {
1403 log<level::DEBUG>("Failed to update the channel volatile data");
1404 return -EIO;
1405 }
1406 }
1407
1408 return 0;
1409}
1410
AppaRao Puli071f3f22018-05-24 16:45:30 +05301411void ChannelConfig::initChannelPersistData()
1412{
1413 /* Always read the channel config */
1414 if (loadChannelConfig() != 0)
1415 {
1416 log<level::ERR>("Failed to read channel config file");
1417 throw std::ios_base::failure("Failed to load channel configuration");
1418 }
1419
1420 /* Populate the channel persist data */
1421 if (readChannelPersistData() != 0)
1422 {
1423 // Copy default NV data to RW location
1424 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1425 channelNvDataFilename);
1426
1427 // Load the channel access NV data
1428 if (readChannelPersistData() != 0)
1429 {
1430 log<level::ERR>("Failed to read channel access NV data");
1431 throw std::ios_base::failure(
1432 "Failed to read channel access NV configuration");
1433 }
1434 }
1435
1436 // First check the volatile data file
1437 // If not present, load the default values
1438 if (readChannelVolatileData() != 0)
1439 {
1440 // Copy default volatile data to temporary location
1441 // NV file(channelNvDataFilename) must have created by now.
1442 std::experimental::filesystem::copy_file(channelNvDataFilename,
1443 channelVolatileDataFilename);
1444
1445 // Load the channel access volatile data
1446 if (readChannelVolatileData() != 0)
1447 {
1448 log<level::ERR>("Failed to read channel access volatile data");
1449 throw std::ios_base::failure(
1450 "Failed to read channel access volatile configuration");
1451 }
1452 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301453
1454 // Synchronize the channel config(priv) with network channel
1455 // configuration(priv) over dbus
1456 if (syncNetworkChannelConfig() != 0)
1457 {
1458 log<level::ERR>(
1459 "Failed to synchronize data with network channel config over dbus");
1460 throw std::ios_base::failure(
1461 "Failed to synchronize data with network channel config over dbus");
1462 }
1463
1464 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301465 return;
1466}
1467
1468} // namespace ipmi