blob: 5f4481890c39a538fb4560025be7ec9c1fa05725 [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"
Johnathan Manteyfd61fc32021-04-08 11:05:38 -070020#include "user_layer.hpp"
AppaRao Puli071f3f22018-05-24 16:45:30 +053021
Johnathan Mantey0a2abc82021-02-18 12:39:12 -080022#include <ifaddrs.h>
AppaRao Puli071f3f22018-05-24 16:45:30 +053023#include <sys/stat.h>
Johnathan Mantey0a2abc82021-02-18 12:39:12 -080024#include <sys/types.h>
AppaRao Puli071f3f22018-05-24 16:45:30 +053025#include <unistd.h>
26
27#include <boost/interprocess/sync/scoped_lock.hpp>
28#include <cerrno>
AppaRao Puli9613ed72018-09-01 23:46:44 +053029#include <exception>
AppaRao Puli071f3f22018-05-24 16:45:30 +053030#include <experimental/filesystem>
31#include <fstream>
32#include <phosphor-logging/log.hpp>
AppaRao Puli9613ed72018-09-01 23:46:44 +053033#include <sdbusplus/bus/match.hpp>
34#include <sdbusplus/server/object.hpp>
AppaRao Puli071f3f22018-05-24 16:45:30 +053035#include <unordered_map>
36
37namespace ipmi
38{
39
40using namespace phosphor::logging;
41
42static constexpr const char* channelAccessDefaultFilename =
43 "/usr/share/ipmi-providers/channel_access.json";
44static constexpr const char* channelConfigDefaultFilename =
45 "/usr/share/ipmi-providers/channel_config.json";
46static constexpr const char* channelNvDataFilename =
47 "/var/lib/ipmi/channel_access_nv.json";
48static constexpr const char* channelVolatileDataFilename =
49 "/run/ipmi/channel_access_volatile.json";
50
AppaRao Puli9613ed72018-09-01 23:46:44 +053051// TODO: Get the service name dynamically..
52static constexpr const char* networkIntfServiceName =
53 "xyz.openbmc_project.Network";
54static constexpr const char* networkIntfObjectBasePath =
55 "/xyz/openbmc_project/network";
56static constexpr const char* networkChConfigIntfName =
57 "xyz.openbmc_project.Channel.ChannelAccess";
58static constexpr const char* privilegePropertyString = "MaxPrivilege";
59static constexpr const char* dBusPropertiesInterface =
60 "org.freedesktop.DBus.Properties";
61static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
62
AppaRao Puli071f3f22018-05-24 16:45:30 +053063// STRING DEFINES: Should sync with key's in JSON
64static constexpr const char* nameString = "name";
65static constexpr const char* isValidString = "is_valid";
66static constexpr const char* activeSessionsString = "active_sessions";
Vernon Mauery58317122018-11-28 11:02:43 -080067static constexpr const char* maxTransferSizeString = "max_transfer_size";
AppaRao Puli071f3f22018-05-24 16:45:30 +053068static constexpr const char* channelInfoString = "channel_info";
69static constexpr const char* mediumTypeString = "medium_type";
70static constexpr const char* protocolTypeString = "protocol_type";
71static constexpr const char* sessionSupportedString = "session_supported";
72static constexpr const char* isIpmiString = "is_ipmi";
Johnathan Manteyfd61fc32021-04-08 11:05:38 -070073static constexpr const char* isManagementNIC = "is_management_nic";
AppaRao Puli071f3f22018-05-24 16:45:30 +053074static constexpr const char* authTypeSupportedString = "auth_type_supported";
75static constexpr const char* accessModeString = "access_mode";
76static constexpr const char* userAuthDisabledString = "user_auth_disabled";
77static constexpr const char* perMsgAuthDisabledString = "per_msg_auth_disabled";
78static constexpr const char* alertingDisabledString = "alerting_disabled";
79static constexpr const char* privLimitString = "priv_limit";
80static constexpr const char* authTypeEnabledString = "auth_type_enabled";
81
82// Default values
83static constexpr const char* defaultChannelName = "RESERVED";
84static constexpr const uint8_t defaultMediumType =
85 static_cast<uint8_t>(EChannelMediumType::reserved);
86static constexpr const uint8_t defaultProtocolType =
87 static_cast<uint8_t>(EChannelProtocolType::reserved);
88static constexpr const uint8_t defaultSessionSupported =
89 static_cast<uint8_t>(EChannelSessSupported::none);
90static constexpr const uint8_t defaultAuthType =
91 static_cast<uint8_t>(EAuthType::none);
92static constexpr const bool defaultIsIpmiState = false;
Vernon Mauery58317122018-11-28 11:02:43 -080093static constexpr size_t smallChannelSize = 64;
AppaRao Puli071f3f22018-05-24 16:45:30 +053094
Lei YU4b0ddb62019-01-25 16:43:50 +080095std::unique_ptr<sdbusplus::bus::match_t> chPropertiesSignal
96 __attribute__((init_priority(101)));
AppaRao Puli9613ed72018-09-01 23:46:44 +053097
AppaRao Puli071f3f22018-05-24 16:45:30 +053098// String mappings use in JSON config file
99static std::unordered_map<std::string, EChannelMediumType> mediumTypeMap = {
100 {"reserved", EChannelMediumType::reserved},
101 {"ipmb", EChannelMediumType::ipmb},
102 {"icmb-v1.0", EChannelMediumType::icmbV10},
103 {"icmb-v0.9", EChannelMediumType::icmbV09},
104 {"lan-802.3", EChannelMediumType::lan8032},
105 {"serial", EChannelMediumType::serial},
106 {"other-lan", EChannelMediumType::otherLan},
107 {"pci-smbus", EChannelMediumType::pciSmbus},
108 {"smbus-v1.0", EChannelMediumType::smbusV11},
109 {"smbus-v2.0", EChannelMediumType::smbusV20},
110 {"usb-1x", EChannelMediumType::usbV1x},
111 {"usb-2x", EChannelMediumType::usbV2x},
112 {"system-interface", EChannelMediumType::systemInterface},
113 {"oem", EChannelMediumType::oem},
114 {"unknown", EChannelMediumType::unknown}};
115
ssekarf4b2b092018-07-25 18:49:08 +0530116static std::unordered_map<EInterfaceIndex, std::string> interfaceMap = {
Richard Marian Thomaiyar43cb1282018-12-08 17:22:53 +0530117 {interfaceKCS, "SMS"},
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530118 {interfaceLAN1, "eth0"},
ssekarf4b2b092018-07-25 18:49:08 +0530119 {interfaceUnknown, "unknown"}};
120
AppaRao Puli071f3f22018-05-24 16:45:30 +0530121static std::unordered_map<std::string, EChannelProtocolType> protocolTypeMap = {
122 {"na", EChannelProtocolType::na},
123 {"ipmb-1.0", EChannelProtocolType::ipmbV10},
124 {"icmb-2.0", EChannelProtocolType::icmbV11},
125 {"reserved", EChannelProtocolType::reserved},
126 {"ipmi-smbus", EChannelProtocolType::ipmiSmbus},
127 {"kcs", EChannelProtocolType::kcs},
128 {"smic", EChannelProtocolType::smic},
129 {"bt-10", EChannelProtocolType::bt10},
130 {"bt-15", EChannelProtocolType::bt15},
131 {"tmode", EChannelProtocolType::tMode},
132 {"oem", EChannelProtocolType::oem}};
133
134static std::array<std::string, 4> accessModeList = {
135 "disabled", "pre-boot", "always_available", "shared"};
136
137static std::array<std::string, 4> sessionSupportList = {
138 "session-less", "single-session", "multi-session", "session-based"};
139
Sumanth Bhate4e633e2019-05-14 12:13:57 +0000140const std::array<std::string, PRIVILEGE_OEM + 1> privList = {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530141 "priv-reserved", "priv-callback", "priv-user",
142 "priv-operator", "priv-admin", "priv-oem"};
143
Richard Marian Thomaiyar55768e32019-03-02 22:54:37 +0530144std::string ChannelConfig::getChannelName(const uint8_t chNum)
Johnathan Mantey74a21022018-12-13 13:17:56 -0800145{
146 if (!isValidChannel(chNum))
147 {
148 log<level::ERR>("Invalid channel number.",
Richard Marian Thomaiyar619ed5f2020-01-17 12:17:47 +0530149 entry("CHANNEL_ID=%d", chNum));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800150 throw std::invalid_argument("Invalid channel number");
151 }
152
153 return channelData[chNum].chName;
154}
155
156int ChannelConfig::convertToChannelNumberFromChannelName(
157 const std::string& chName)
158{
159 for (const auto& it : channelData)
160 {
161 if (it.chName == chName)
162 {
163 return it.chID;
164 }
165 }
166 log<level::ERR>("Invalid channel name.",
Richard Marian Thomaiyar619ed5f2020-01-17 12:17:47 +0530167 entry("CHANNEL=%s", chName.c_str()));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800168 throw std::invalid_argument("Invalid channel name");
169
170 return -1;
171}
172
173std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530174{
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530175
176 constexpr size_t length = strlen(networkIntfObjectBasePath);
177 if (((length + 1) >= path.size()) ||
178 path.compare(0, length, networkIntfObjectBasePath))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530179 {
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530180 log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str()));
181 throw std::invalid_argument("Invalid object path");
AppaRao Puli9613ed72018-09-01 23:46:44 +0530182 }
Richard Marian Thomaiyarbbbc3952020-01-17 12:13:28 +0530183 std::string chName(path, length + 1);
Johnathan Mantey74a21022018-12-13 13:17:56 -0800184 return chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530185}
186
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800187void ChannelConfig::processChAccessPropChange(
188 const std::string& path, const DbusChObjProperties& chProperties)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530189{
190 // Get interface name from path. ex: '/xyz/openbmc_project/network/eth0'
Johnathan Mantey74a21022018-12-13 13:17:56 -0800191 std::string chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530192 try
193 {
Johnathan Mantey74a21022018-12-13 13:17:56 -0800194 chName = getChannelNameFromPath(path);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530195 }
196 catch (const std::invalid_argument& e)
197 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530198 log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530199 return;
200 }
201
202 // Get the MaxPrivilege property value from the signal
203 std::string intfPrivStr;
204 std::string propName;
205 for (const auto& prop : chProperties)
206 {
207 if (prop.first == privilegePropertyString)
208 {
209 propName = privilegePropertyString;
Vernon Maueryf442e112019-04-09 11:44:36 -0700210 intfPrivStr = std::get<std::string>(prop.second);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530211 break;
212 }
213 }
214
215 if (propName != privilegePropertyString)
216 {
217 log<level::ERR>("Unknown signal caught.");
218 return;
219 }
220
221 if (intfPrivStr.empty())
222 {
223 log<level::ERR>("Invalid privilege string.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530224 entry("INTF=%s", chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530225 return;
226 }
227
228 uint8_t intfPriv = 0;
Johnathan Mantey74a21022018-12-13 13:17:56 -0800229 int chNum;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530230 try
231 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800232 intfPriv = static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
Johnathan Mantey74a21022018-12-13 13:17:56 -0800233 chNum = convertToChannelNumberFromChannelName(chName);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530234 }
235 catch (const std::invalid_argument& e)
236 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530237 log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
AppaRao Puli9613ed72018-09-01 23:46:44 +0530238 return;
239 }
240
241 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800242 channelLock{*channelMutex};
AppaRao Puli9613ed72018-09-01 23:46:44 +0530243 // skip updating the values, if this property change originated from IPMI.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800244 if (signalFlag & (1 << chNum))
AppaRao Puli9613ed72018-09-01 23:46:44 +0530245 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800246 signalFlag &= ~(1 << chNum);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530247 log<level::DEBUG>("Request originated from IPMI so ignoring signal");
248 return;
249 }
250
251 // Update both volatile & Non-volatile, if there is mismatch.
252 // as property change other than IPMI, has to update both volatile &
253 // non-volatile data.
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800254 checkAndReloadVolatileData();
255 checkAndReloadNVData();
256 if (channelData[chNum].chAccess.chNonVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530257 {
258 // Update NV data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800259 channelData[chNum].chAccess.chNonVolatileData.privLimit = intfPriv;
260 if (writeChannelPersistData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530261 {
262 log<level::ERR>("Failed to update the persist data file");
263 return;
264 }
265
266 // Update Volatile data
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800267 if (channelData[chNum].chAccess.chVolatileData.privLimit != intfPriv)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530268 {
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800269 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
270 if (writeChannelVolatileData() != 0)
AppaRao Puli9613ed72018-09-01 23:46:44 +0530271 {
272 log<level::ERR>("Failed to update the volatile data file");
273 return;
274 }
275 }
276 }
277
278 return;
279}
280
AppaRao Puli071f3f22018-05-24 16:45:30 +0530281ChannelConfig& getChannelConfigObject()
282{
283 static ChannelConfig channelConfig;
284 return channelConfig;
285}
286
AppaRao Puli9613ed72018-09-01 23:46:44 +0530287ChannelConfig::~ChannelConfig()
288{
289 if (signalHndlrObjectState)
290 {
291 chPropertiesSignal.reset();
292 sigHndlrLock.unlock();
293 }
294}
295
AppaRao Puli071f3f22018-05-24 16:45:30 +0530296ChannelConfig::ChannelConfig() : bus(ipmid_get_sd_bus_connection())
297{
298 std::ofstream mutexCleanUpFile;
299 mutexCleanUpFile.open(ipmiChMutexCleanupLockFile,
300 std::ofstream::out | std::ofstream::app);
301 if (!mutexCleanUpFile.good())
302 {
303 log<level::DEBUG>("Unable to open mutex cleanup file");
304 return;
305 }
306 mutexCleanUpFile.close();
307 mutexCleanupLock =
308 boost::interprocess::file_lock(ipmiChMutexCleanupLockFile);
309 if (mutexCleanupLock.try_lock())
310 {
311 boost::interprocess::named_recursive_mutex::remove(ipmiChannelMutex);
312 channelMutex =
313 std::make_unique<boost::interprocess::named_recursive_mutex>(
314 boost::interprocess::open_or_create, ipmiChannelMutex);
315 mutexCleanupLock.lock_sharable();
316 }
317 else
318 {
319 mutexCleanupLock.lock_sharable();
320 channelMutex =
321 std::make_unique<boost::interprocess::named_recursive_mutex>(
322 boost::interprocess::open_or_create, ipmiChannelMutex);
323 }
324
325 initChannelPersistData();
AppaRao Puli9613ed72018-09-01 23:46:44 +0530326
327 sigHndlrLock = boost::interprocess::file_lock(channelNvDataFilename);
328 // Register it for single object and single process either netipimd /
329 // host-ipmid
330 if (chPropertiesSignal == nullptr && sigHndlrLock.try_lock())
331 {
332 log<level::DEBUG>("Registering channel signal handler.");
333 chPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
334 bus,
335 sdbusplus::bus::match::rules::path_namespace(
336 networkIntfObjectBasePath) +
337 sdbusplus::bus::match::rules::type::signal() +
338 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
339 sdbusplus::bus::match::rules::interface(
340 dBusPropertiesInterface) +
341 sdbusplus::bus::match::rules::argN(0, networkChConfigIntfName),
342 [&](sdbusplus::message::message& msg) {
343 DbusChObjProperties props;
344 std::string iface;
345 std::string path = msg.get_path();
346 msg.read(iface, props);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800347 processChAccessPropChange(path, props);
AppaRao Puli9613ed72018-09-01 23:46:44 +0530348 });
349 signalHndlrObjectState = true;
350 }
351}
352
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530353bool ChannelConfig::isValidChannel(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530354{
Meera-Kattac1789482021-05-18 09:53:26 +0000355 if (chNum >= maxIpmiChannels)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530356 {
357 log<level::DEBUG>("Invalid channel ID - Out of range");
358 return false;
359 }
360
361 if (channelData[chNum].isChValid == false)
362 {
363 log<level::DEBUG>("Channel is not valid");
AppaRao Puli071f3f22018-05-24 16:45:30 +0530364 }
365
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800366 return channelData[chNum].isChValid;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530367}
368
369EChannelSessSupported
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530370 ChannelConfig::getChannelSessionSupport(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530371{
372 EChannelSessSupported chSessSupport =
373 (EChannelSessSupported)channelData[chNum].chInfo.sessionSupported;
374 return chSessSupport;
375}
376
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530377bool ChannelConfig::isValidAuthType(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530378 const EAuthType& authType)
379{
380 if ((authType < EAuthType::md2) || (authType > EAuthType::oem))
381 {
382 log<level::DEBUG>("Invalid authentication type");
383 return false;
384 }
385
386 uint8_t authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
387 if (!(authTypeSupported & (1 << static_cast<uint8_t>(authType))))
388 {
389 log<level::DEBUG>("Authentication type is not supported.");
390 return false;
391 }
392
393 return true;
394}
395
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530396int ChannelConfig::getChannelActiveSessions(const uint8_t chNum)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530397{
398 // TODO: TEMPORARY FIX
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800399 // Channels active session count is managed separately
AppaRao Puli071f3f22018-05-24 16:45:30 +0530400 // by monitoring channel session which includes LAN and
401 // RAKP layer changes. This will be updated, once the
402 // authentication part is implemented.
403 return channelData[chNum].activeSessCount;
404}
405
Vernon Mauery58317122018-11-28 11:02:43 -0800406size_t ChannelConfig::getChannelMaxTransferSize(uint8_t chNum)
407{
408 return channelData[chNum].maxTransferSize;
409}
410
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000411Cc ChannelConfig::getChannelInfo(const uint8_t chNum, ChannelInfo& chInfo)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530412{
413 if (!isValidChannel(chNum))
414 {
415 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000416 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530417 }
418
419 std::copy_n(reinterpret_cast<uint8_t*>(&channelData[chNum].chInfo),
420 sizeof(channelData[chNum].chInfo),
421 reinterpret_cast<uint8_t*>(&chInfo));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000422 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530423}
424
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000425Cc ChannelConfig::getChannelAccessData(const uint8_t chNum,
426 ChannelAccess& chAccessData)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530427{
428 if (!isValidChannel(chNum))
429 {
430 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000431 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530432 }
433
434 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
435 {
436 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000437 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530438 }
439
440 if (checkAndReloadVolatileData() != 0)
441 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000442 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530443 }
444
445 std::copy_n(
446 reinterpret_cast<uint8_t*>(&channelData[chNum].chAccess.chVolatileData),
447 sizeof(channelData[chNum].chAccess.chVolatileData),
448 reinterpret_cast<uint8_t*>(&chAccessData));
449
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000450 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530451}
452
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000453Cc ChannelConfig::setChannelAccessData(const uint8_t chNum,
454 const ChannelAccess& chAccessData,
455 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530456{
457 if (!isValidChannel(chNum))
458 {
459 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000460 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530461 }
462
463 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
464 {
465 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000466 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530467 }
468
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000469 if ((setFlag & setAccessMode) &&
470 (!isValidAccessMode(chAccessData.accessMode)))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530471 {
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000472 log<level::DEBUG>("Invalid access mode specified");
473 return ccAccessModeNotSupportedForChannel;
474 }
475 if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
476 {
477 log<level::DEBUG>("Invalid privilege limit specified");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000478 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530479 }
480
481 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
482 channelLock{*channelMutex};
483
484 if (checkAndReloadVolatileData() != 0)
485 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000486 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530487 }
488
489 if (setFlag & setAccessMode)
490 {
491 channelData[chNum].chAccess.chVolatileData.accessMode =
492 chAccessData.accessMode;
493 }
494 if (setFlag & setUserAuthEnabled)
495 {
496 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
497 chAccessData.userAuthDisabled;
498 }
499 if (setFlag & setMsgAuthEnabled)
500 {
501 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
502 chAccessData.perMsgAuthDisabled;
503 }
504 if (setFlag & setAlertingEnabled)
505 {
506 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
507 chAccessData.alertingDisabled;
508 }
509 if (setFlag & setPrivLimit)
510 {
511 channelData[chNum].chAccess.chVolatileData.privLimit =
512 chAccessData.privLimit;
513 }
514
515 // Write Volatile data to file
516 if (writeChannelVolatileData() != 0)
517 {
518 log<level::DEBUG>("Failed to update the channel volatile data");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000519 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530520 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000521 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530522}
523
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000524Cc ChannelConfig::getChannelAccessPersistData(const uint8_t chNum,
525 ChannelAccess& chAccessData)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530526{
527 if (!isValidChannel(chNum))
528 {
529 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000530 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530531 }
532
533 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
534 {
535 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000536 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530537 }
538
539 if (checkAndReloadNVData() != 0)
540 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000541 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530542 }
543
544 std::copy_n(reinterpret_cast<uint8_t*>(
545 &channelData[chNum].chAccess.chNonVolatileData),
546 sizeof(channelData[chNum].chAccess.chNonVolatileData),
547 reinterpret_cast<uint8_t*>(&chAccessData));
548
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000549 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530550}
551
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000552Cc ChannelConfig::setChannelAccessPersistData(const uint8_t chNum,
553 const ChannelAccess& chAccessData,
554 const uint8_t setFlag)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530555{
556 if (!isValidChannel(chNum))
557 {
558 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000559 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530560 }
561
562 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
563 {
564 log<level::DEBUG>("Session-less channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000565 return ccActionNotSupportedForChannel;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530566 }
567
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000568 if ((setFlag & setAccessMode) &&
569 (!isValidAccessMode(chAccessData.accessMode)))
AppaRao Puli071f3f22018-05-24 16:45:30 +0530570 {
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000571 log<level::DEBUG>("Invalid access mode specified");
572 return ccAccessModeNotSupportedForChannel;
573 }
574 if ((setFlag & setPrivLimit) && (!isValidPrivLimit(chAccessData.privLimit)))
575 {
576 log<level::DEBUG>("Invalid privilege limit specified");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000577 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530578 }
579
580 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
581 channelLock{*channelMutex};
582
583 if (checkAndReloadNVData() != 0)
584 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000585 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530586 }
587
588 if (setFlag & setAccessMode)
589 {
590 channelData[chNum].chAccess.chNonVolatileData.accessMode =
591 chAccessData.accessMode;
592 }
593 if (setFlag & setUserAuthEnabled)
594 {
595 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
596 chAccessData.userAuthDisabled;
597 }
598 if (setFlag & setMsgAuthEnabled)
599 {
600 channelData[chNum].chAccess.chNonVolatileData.perMsgAuthDisabled =
601 chAccessData.perMsgAuthDisabled;
602 }
603 if (setFlag & setAlertingEnabled)
604 {
605 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
606 chAccessData.alertingDisabled;
607 }
608 if (setFlag & setPrivLimit)
609 {
AppaRao Puli9613ed72018-09-01 23:46:44 +0530610 // Send Update to network channel config interfaces over dbus
AppaRao Puli9613ed72018-09-01 23:46:44 +0530611 std::string privStr = convertToPrivLimitString(chAccessData.privLimit);
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530612 std::string networkIntfObj = std::string(networkIntfObjectBasePath) +
613 "/" + channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530614 try
615 {
Johnathan Manteyf92261d2018-12-10 15:49:34 -0800616 if (0 != setDbusProperty(networkIntfServiceName, networkIntfObj,
617 networkChConfigIntfName,
AppaRao Puli9613ed72018-09-01 23:46:44 +0530618 privilegePropertyString, privStr))
619 {
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +0530620 log<level::DEBUG>(
621 "Network interface does not exist",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530622 entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000623 return ccUnspecifiedError;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530624 }
625 }
626 catch (const sdbusplus::exception::SdBusError& e)
627 {
628 log<level::ERR>("Exception: Network interface does not exist");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000629 return ccInvalidFieldRequest;
AppaRao Puli9613ed72018-09-01 23:46:44 +0530630 }
631 signalFlag |= (1 << chNum);
AppaRao Puli071f3f22018-05-24 16:45:30 +0530632 channelData[chNum].chAccess.chNonVolatileData.privLimit =
633 chAccessData.privLimit;
634 }
635
636 // Write persistent data to file
637 if (writeChannelPersistData() != 0)
638 {
639 log<level::DEBUG>("Failed to update the presist data file");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000640 return ccUnspecifiedError;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530641 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000642 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530643}
644
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000645Cc ChannelConfig::getChannelAuthTypeSupported(const uint8_t chNum,
646 uint8_t& authTypeSupported)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530647{
648 if (!isValidChannel(chNum))
649 {
650 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000651 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530652 }
653
654 authTypeSupported = channelData[chNum].chInfo.authTypeSupported;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000655 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530656}
657
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000658Cc ChannelConfig::getChannelEnabledAuthType(const uint8_t chNum,
659 const uint8_t priv,
660 EAuthType& authType)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530661{
662 if (!isValidChannel(chNum))
663 {
664 log<level::DEBUG>("Invalid channel");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000665 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530666 }
667
668 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
669 {
670 log<level::DEBUG>("Sessionless channel doesn't have access data.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000671 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530672 }
673
674 if (!isValidPrivLimit(priv))
675 {
676 log<level::DEBUG>("Invalid privilege specified.");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000677 return ccInvalidFieldRequest;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530678 }
679
680 // TODO: Hardcoded for now. Need to implement.
681 authType = EAuthType::none;
682
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000683 return ccSuccess;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530684}
685
686std::time_t ChannelConfig::getUpdatedFileTime(const std::string& fileName)
687{
688 struct stat fileStat;
689 if (stat(fileName.c_str(), &fileStat) != 0)
690 {
691 log<level::DEBUG>("Error in getting last updated time stamp");
692 return -EIO;
693 }
694 return fileStat.st_mtime;
695}
696
697EChannelAccessMode
698 ChannelConfig::convertToAccessModeIndex(const std::string& mode)
699{
700 auto iter = std::find(accessModeList.begin(), accessModeList.end(), mode);
701 if (iter == accessModeList.end())
702 {
703 log<level::ERR>("Invalid access mode.",
704 entry("MODE_STR=%s", mode.c_str()));
705 throw std::invalid_argument("Invalid access mode.");
706 }
707
708 return static_cast<EChannelAccessMode>(
709 std::distance(accessModeList.begin(), iter));
710}
711
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530712std::string ChannelConfig::convertToAccessModeString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530713{
714 if (accessModeList.size() <= value)
715 {
716 log<level::ERR>("Invalid access mode.", entry("MODE_IDX=%d", value));
717 throw std::invalid_argument("Invalid access mode.");
718 }
719
720 return accessModeList.at(value);
721}
722
723CommandPrivilege
724 ChannelConfig::convertToPrivLimitIndex(const std::string& value)
725{
726 auto iter = std::find(privList.begin(), privList.end(), value);
727 if (iter == privList.end())
728 {
729 log<level::ERR>("Invalid privilege.",
730 entry("PRIV_STR=%s", value.c_str()));
731 throw std::invalid_argument("Invalid privilege.");
732 }
733
734 return static_cast<CommandPrivilege>(std::distance(privList.begin(), iter));
735}
736
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530737std::string ChannelConfig::convertToPrivLimitString(const uint8_t value)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530738{
739 if (privList.size() <= value)
740 {
741 log<level::ERR>("Invalid privilege.", entry("PRIV_IDX=%d", value));
742 throw std::invalid_argument("Invalid privilege.");
743 }
744
745 return privList.at(value);
746}
747
748EChannelSessSupported
749 ChannelConfig::convertToSessionSupportIndex(const std::string& value)
750{
751 auto iter =
752 std::find(sessionSupportList.begin(), sessionSupportList.end(), value);
753 if (iter == sessionSupportList.end())
754 {
755 log<level::ERR>("Invalid session supported.",
756 entry("SESS_STR=%s", value.c_str()));
757 throw std::invalid_argument("Invalid session supported.");
758 }
759
760 return static_cast<EChannelSessSupported>(
761 std::distance(sessionSupportList.begin(), iter));
762}
763
764EChannelMediumType
765 ChannelConfig::convertToMediumTypeIndex(const std::string& value)
766{
767 std::unordered_map<std::string, EChannelMediumType>::iterator it =
768 mediumTypeMap.find(value);
769 if (it == mediumTypeMap.end())
770 {
771 log<level::ERR>("Invalid medium type.",
772 entry("MEDIUM_STR=%s", value.c_str()));
773 throw std::invalid_argument("Invalid medium type.");
774 }
775
776 return static_cast<EChannelMediumType>(it->second);
777}
778
779EChannelProtocolType
780 ChannelConfig::convertToProtocolTypeIndex(const std::string& value)
781{
782 std::unordered_map<std::string, EChannelProtocolType>::iterator it =
783 protocolTypeMap.find(value);
784 if (it == protocolTypeMap.end())
785 {
786 log<level::ERR>("Invalid protocol type.",
787 entry("PROTO_STR=%s", value.c_str()));
788 throw std::invalid_argument("Invalid protocol type.");
789 }
790
791 return static_cast<EChannelProtocolType>(it->second);
792}
793
794Json ChannelConfig::readJsonFile(const std::string& configFile)
795{
796 std::ifstream jsonFile(configFile);
797 if (!jsonFile.good())
798 {
Richard Marian Thomaiyarc4196802019-06-03 19:27:48 +0530799 log<level::INFO>("JSON file not found",
800 entry("FILE_NAME=%s", configFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530801 return nullptr;
802 }
803
804 Json data = nullptr;
805 try
806 {
807 data = Json::parse(jsonFile, nullptr, false);
808 }
809 catch (Json::parse_error& e)
810 {
811 log<level::DEBUG>("Corrupted channel config.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530812 entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530813 throw std::runtime_error("Corrupted channel config file");
814 }
815
816 return data;
817}
818
819int ChannelConfig::writeJsonFile(const std::string& configFile,
820 const Json& jsonData)
821{
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530822 const std::string tmpFile = configFile + "_tmp";
823 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
824 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
825 if (fd < 0)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530826 {
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +0530827 log<level::ERR>("Error in creating json file",
828 entry("FILE_NAME = %s", tmpFile.c_str()));
829 return -EIO;
830 }
831 const auto& writeData = jsonData.dump();
832 if (write(fd, writeData.c_str(), writeData.size()) !=
833 static_cast<ssize_t>(writeData.size()))
834 {
835 close(fd);
836 log<level::ERR>("Error in writing configuration file",
837 entry("FILE_NAME = %s", tmpFile.c_str()));
838 return -EIO;
839 }
840 close(fd);
841
842 if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
843 {
844 log<level::ERR>("Error in renaming temporary data file",
845 entry("FILE_NAME = %s", tmpFile.c_str()));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530846 return -EIO;
847 }
848
AppaRao Puli071f3f22018-05-24 16:45:30 +0530849 return 0;
850}
851
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530852void ChannelConfig::setDefaultChannelConfig(const uint8_t chNum,
AppaRao Puli071f3f22018-05-24 16:45:30 +0530853 const std::string& chName)
854{
855 channelData[chNum].chName = chName;
856 channelData[chNum].chID = chNum;
857 channelData[chNum].isChValid = false;
858 channelData[chNum].activeSessCount = 0;
Johnathan Manteyfd61fc32021-04-08 11:05:38 -0700859 channelData[chNum].isManagementNIC = false;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530860
861 channelData[chNum].chInfo.mediumType = defaultMediumType;
862 channelData[chNum].chInfo.protocolType = defaultProtocolType;
863 channelData[chNum].chInfo.sessionSupported = defaultSessionSupported;
864 channelData[chNum].chInfo.isIpmi = defaultIsIpmiState;
865 channelData[chNum].chInfo.authTypeSupported = defaultAuthType;
866}
867
Johnathan Manteyfd61fc32021-04-08 11:05:38 -0700868uint8_t ChannelConfig::getManagementNICID()
869{
870 static bool idFound = false;
871 static uint8_t id = 0;
872
873 if (idFound)
874 {
875 return id;
876 }
877
878 for (uint8_t chIdx = 0; chIdx < maxIpmiChannels; chIdx++)
879 {
880 if (channelData[chIdx].isManagementNIC)
881 {
882 id = chIdx;
883 idFound = true;
884 break;
885 }
886 }
887
888 if (!idFound)
889 {
890 id = static_cast<uint8_t>(EChannelID::chanLan1);
891 idFound = true;
892 }
893 return id;
894}
895
AppaRao Puli071f3f22018-05-24 16:45:30 +0530896int ChannelConfig::loadChannelConfig()
897{
898 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
899 channelLock{*channelMutex};
900
901 Json data = readJsonFile(channelConfigDefaultFilename);
Johnathan Manteye5c4f1d2018-12-10 16:24:26 -0800902 if (data.empty())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530903 {
904 log<level::DEBUG>("Error in opening IPMI Channel data file");
905 return -EIO;
906 }
907
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800908 channelData.fill(ChannelProperties{});
909
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800910 // Collect the list of NIC interfaces connected to the BMC. Use this
911 // information to only add IPMI channels that have active NIC interfaces.
Snehalatha Venkatesh55f5d532021-07-13 11:06:36 +0000912 struct ifaddrs *ifaddr = nullptr, *ifa = nullptr;
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800913 if (int err = getifaddrs(&ifaddr); err < 0)
914 {
915 log<level::DEBUG>("Unable to acquire network interfaces");
916 return -EIO;
917 }
918
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800919 for (int chNum = 0; chNum < maxIpmiChannels; chNum++)
AppaRao Puli071f3f22018-05-24 16:45:30 +0530920 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800921 try
AppaRao Puli071f3f22018-05-24 16:45:30 +0530922 {
AppaRao Puli071f3f22018-05-24 16:45:30 +0530923 std::string chKey = std::to_string(chNum);
924 Json jsonChData = data[chKey].get<Json>();
925 if (jsonChData.is_null())
926 {
927 log<level::WARNING>(
928 "Channel not configured so loading default.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530929 entry("CHANNEL_NUM=%d", chNum));
AppaRao Puli071f3f22018-05-24 16:45:30 +0530930 // If user didn't want to configure specific channel (say
931 // reserved channel), then load that index with default values.
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800932 setDefaultChannelConfig(chNum, defaultChannelName);
933 continue;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530934 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800935 Json jsonChInfo = jsonChData[channelInfoString].get<Json>();
936 if (jsonChInfo.is_null())
AppaRao Puli071f3f22018-05-24 16:45:30 +0530937 {
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800938 log<level::ERR>("Invalid/corrupted channel config file");
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800939 freeifaddrs(ifaddr);
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800940 return -EBADMSG;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530941 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800942
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800943 bool channelFound = true;
944 // Confirm the LAN channel is present
945 if (jsonChInfo[mediumTypeString].get<std::string>() == "lan-802.3")
946 {
947 channelFound = false;
948 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
949 {
950 if (jsonChData[nameString].get<std::string>() ==
951 ifa->ifa_name)
952 {
953 channelFound = true;
954 break;
955 }
956 }
957 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800958 ChannelProperties& chData = channelData[chNum];
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800959 chData.chID = chNum;
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800960 chData.chName = jsonChData[nameString].get<std::string>();
961 chData.isChValid =
962 channelFound && jsonChData[isValidString].get<bool>();
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800963 chData.activeSessCount = jsonChData.value(activeSessionsString, 0);
964 chData.maxTransferSize =
965 jsonChData.value(maxTransferSizeString, smallChannelSize);
Johnathan Manteyfd61fc32021-04-08 11:05:38 -0700966 if (jsonChData.count(isManagementNIC) != 0)
967 {
968 chData.isManagementNIC =
969 jsonChData[isManagementNIC].get<bool>();
970 }
971
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800972 std::string medTypeStr =
973 jsonChInfo[mediumTypeString].get<std::string>();
974 chData.chInfo.mediumType =
975 static_cast<uint8_t>(convertToMediumTypeIndex(medTypeStr));
976 std::string protoTypeStr =
977 jsonChInfo[protocolTypeString].get<std::string>();
978 chData.chInfo.protocolType =
979 static_cast<uint8_t>(convertToProtocolTypeIndex(protoTypeStr));
980 std::string sessStr =
981 jsonChInfo[sessionSupportedString].get<std::string>();
982 chData.chInfo.sessionSupported =
983 static_cast<uint8_t>(convertToSessionSupportIndex(sessStr));
984 chData.chInfo.isIpmi = jsonChInfo[isIpmiString].get<bool>();
985 chData.chInfo.authTypeSupported = defaultAuthType;
AppaRao Puli071f3f22018-05-24 16:45:30 +0530986 }
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800987 catch (const Json::exception& e)
988 {
989 log<level::DEBUG>("Json Exception caught.",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530990 entry("MSG=%s", e.what()));
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800991 freeifaddrs(ifaddr);
992
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800993 return -EBADMSG;
994 }
995 catch (const std::invalid_argument& e)
996 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530997 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
Johnathan Mantey0a2abc82021-02-18 12:39:12 -0800998 freeifaddrs(ifaddr);
Johnathan Mantey4c0435a2018-12-11 13:17:55 -0800999 return -EBADMSG;
1000 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301001 }
Johnathan Mantey0a2abc82021-02-18 12:39:12 -08001002 freeifaddrs(ifaddr);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301003
1004 return 0;
1005}
1006
1007int ChannelConfig::readChannelVolatileData()
1008{
1009 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1010 channelLock{*channelMutex};
1011
1012 Json data = readJsonFile(channelVolatileDataFilename);
1013 if (data == nullptr)
1014 {
1015 log<level::DEBUG>("Error in opening IPMI Channel data file");
1016 return -EIO;
1017 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301018 try
1019 {
1020 // Fill in global structure
1021 for (auto it = data.begin(); it != data.end(); ++it)
1022 {
1023 std::string chKey = it.key();
1024 uint8_t chNum = std::stoi(chKey, nullptr, 10);
Meera-Kattac1789482021-05-18 09:53:26 +00001025 if (chNum >= maxIpmiChannels)
AppaRao Puli071f3f22018-05-24 16:45:30 +05301026 {
1027 log<level::DEBUG>(
1028 "Invalid channel access entry in config file");
1029 throw std::out_of_range("Out of range - channel number");
1030 }
1031 Json jsonChData = it.value();
1032 if (!jsonChData.is_null())
1033 {
1034 std::string accModeStr =
1035 jsonChData[accessModeString].get<std::string>();
1036 channelData[chNum].chAccess.chVolatileData.accessMode =
1037 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1038 channelData[chNum].chAccess.chVolatileData.userAuthDisabled =
1039 jsonChData[userAuthDisabledString].get<bool>();
1040 channelData[chNum].chAccess.chVolatileData.perMsgAuthDisabled =
1041 jsonChData[perMsgAuthDisabledString].get<bool>();
1042 channelData[chNum].chAccess.chVolatileData.alertingDisabled =
1043 jsonChData[alertingDisabledString].get<bool>();
1044 std::string privStr =
1045 jsonChData[privLimitString].get<std::string>();
1046 channelData[chNum].chAccess.chVolatileData.privLimit =
1047 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1048 }
1049 else
1050 {
1051 log<level::ERR>(
1052 "Invalid/corrupted volatile channel access file",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301053 entry("FILE=%s", channelVolatileDataFilename));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301054 throw std::runtime_error(
1055 "Corrupted volatile channel access file");
1056 }
1057 }
1058 }
1059 catch (const Json::exception& e)
1060 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301061 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301062 throw std::runtime_error("Corrupted volatile channel access file");
1063 }
1064 catch (const std::invalid_argument& e)
1065 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301066 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301067 throw std::runtime_error("Corrupted volatile channel access file");
1068 }
1069
1070 // Update the timestamp
1071 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1072 return 0;
1073}
1074
1075int ChannelConfig::readChannelPersistData()
1076{
1077 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1078 channelLock{*channelMutex};
1079
1080 Json data = readJsonFile(channelNvDataFilename);
1081 if (data == nullptr)
1082 {
1083 log<level::DEBUG>("Error in opening IPMI Channel data file");
1084 return -EIO;
1085 }
AppaRao Puli071f3f22018-05-24 16:45:30 +05301086 try
1087 {
1088 // Fill in global structure
1089 for (auto it = data.begin(); it != data.end(); ++it)
1090 {
1091 std::string chKey = it.key();
1092 uint8_t chNum = std::stoi(chKey, nullptr, 10);
Meera-Kattac1789482021-05-18 09:53:26 +00001093 if (chNum >= maxIpmiChannels)
AppaRao Puli071f3f22018-05-24 16:45:30 +05301094 {
1095 log<level::DEBUG>(
1096 "Invalid channel access entry in config file");
1097 throw std::out_of_range("Out of range - channel number");
1098 }
1099 Json jsonChData = it.value();
1100 if (!jsonChData.is_null())
1101 {
1102 std::string accModeStr =
1103 jsonChData[accessModeString].get<std::string>();
1104 channelData[chNum].chAccess.chNonVolatileData.accessMode =
1105 static_cast<uint8_t>(convertToAccessModeIndex(accModeStr));
1106 channelData[chNum].chAccess.chNonVolatileData.userAuthDisabled =
1107 jsonChData[userAuthDisabledString].get<bool>();
1108 channelData[chNum]
1109 .chAccess.chNonVolatileData.perMsgAuthDisabled =
1110 jsonChData[perMsgAuthDisabledString].get<bool>();
1111 channelData[chNum].chAccess.chNonVolatileData.alertingDisabled =
1112 jsonChData[alertingDisabledString].get<bool>();
1113 std::string privStr =
1114 jsonChData[privLimitString].get<std::string>();
1115 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1116 static_cast<uint8_t>(convertToPrivLimitIndex(privStr));
1117 }
1118 else
1119 {
1120 log<level::ERR>("Invalid/corrupted nv channel access file",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301121 entry("FILE=%s", channelNvDataFilename));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301122 throw std::runtime_error("Corrupted nv channel access file");
1123 }
1124 }
1125 }
1126 catch (const Json::exception& e)
1127 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301128 log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301129 throw std::runtime_error("Corrupted nv channel access file");
1130 }
1131 catch (const std::invalid_argument& e)
1132 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301133 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301134 throw std::runtime_error("Corrupted nv channel access file");
1135 }
1136
1137 // Update the timestamp
1138 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1139 return 0;
1140}
1141
1142int ChannelConfig::writeChannelVolatileData()
1143{
1144 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1145 channelLock{*channelMutex};
1146 Json outData;
1147
1148 try
1149 {
1150 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1151 {
1152 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1153 {
1154 Json jsonObj;
1155 std::string chKey = std::to_string(chNum);
1156 std::string accModeStr = convertToAccessModeString(
1157 channelData[chNum].chAccess.chVolatileData.accessMode);
1158 jsonObj[accessModeString] = accModeStr;
1159 jsonObj[userAuthDisabledString] =
1160 channelData[chNum].chAccess.chVolatileData.userAuthDisabled;
1161 jsonObj[perMsgAuthDisabledString] =
1162 channelData[chNum]
1163 .chAccess.chVolatileData.perMsgAuthDisabled;
1164 jsonObj[alertingDisabledString] =
1165 channelData[chNum].chAccess.chVolatileData.alertingDisabled;
1166 std::string privStr = convertToPrivLimitString(
1167 channelData[chNum].chAccess.chVolatileData.privLimit);
1168 jsonObj[privLimitString] = privStr;
1169
1170 outData[chKey] = jsonObj;
1171 }
1172 }
1173 }
1174 catch (const std::invalid_argument& e)
1175 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301176 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301177 return -EINVAL;
1178 }
1179
1180 if (writeJsonFile(channelVolatileDataFilename, outData) != 0)
1181 {
1182 log<level::DEBUG>("Error in write JSON data to file");
1183 return -EIO;
1184 }
1185
1186 // Update the timestamp
1187 voltFileLastUpdatedTime = getUpdatedFileTime(channelVolatileDataFilename);
1188 return 0;
1189}
1190
1191int ChannelConfig::writeChannelPersistData()
1192{
1193 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1194 channelLock{*channelMutex};
1195 Json outData;
1196
1197 try
1198 {
1199 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1200 {
1201 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1202 {
1203 Json jsonObj;
1204 std::string chKey = std::to_string(chNum);
1205 std::string accModeStr = convertToAccessModeString(
1206 channelData[chNum].chAccess.chNonVolatileData.accessMode);
1207 jsonObj[accessModeString] = accModeStr;
1208 jsonObj[userAuthDisabledString] =
1209 channelData[chNum]
1210 .chAccess.chNonVolatileData.userAuthDisabled;
1211 jsonObj[perMsgAuthDisabledString] =
1212 channelData[chNum]
1213 .chAccess.chNonVolatileData.perMsgAuthDisabled;
1214 jsonObj[alertingDisabledString] =
1215 channelData[chNum]
1216 .chAccess.chNonVolatileData.alertingDisabled;
1217 std::string privStr = convertToPrivLimitString(
1218 channelData[chNum].chAccess.chNonVolatileData.privLimit);
1219 jsonObj[privLimitString] = privStr;
1220
1221 outData[chKey] = jsonObj;
1222 }
1223 }
1224 }
1225 catch (const std::invalid_argument& e)
1226 {
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301227 log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
AppaRao Puli071f3f22018-05-24 16:45:30 +05301228 return -EINVAL;
1229 }
1230
1231 if (writeJsonFile(channelNvDataFilename, outData) != 0)
1232 {
1233 log<level::DEBUG>("Error in write JSON data to file");
1234 return -EIO;
1235 }
1236
1237 // Update the timestamp
1238 nvFileLastUpdatedTime = getUpdatedFileTime(channelNvDataFilename);
1239 return 0;
1240}
1241
1242int ChannelConfig::checkAndReloadNVData()
1243{
1244 std::time_t updateTime = getUpdatedFileTime(channelNvDataFilename);
1245 int ret = 0;
1246 if (updateTime != nvFileLastUpdatedTime || updateTime == -EIO)
1247 {
1248 try
1249 {
1250 ret = readChannelPersistData();
1251 }
1252 catch (const std::exception& e)
1253 {
1254 log<level::ERR>("Exception caught in readChannelPersistData.",
1255 entry("MSG=%s", e.what()));
1256 ret = -EIO;
1257 }
1258 }
1259 return ret;
1260}
1261
1262int ChannelConfig::checkAndReloadVolatileData()
1263{
1264 std::time_t updateTime = getUpdatedFileTime(channelVolatileDataFilename);
1265 int ret = 0;
1266 if (updateTime != voltFileLastUpdatedTime || updateTime == -EIO)
1267 {
1268 try
1269 {
1270 ret = readChannelVolatileData();
1271 }
1272 catch (const std::exception& e)
1273 {
1274 log<level::ERR>("Exception caught in readChannelVolatileData.",
1275 entry("MSG=%s", e.what()));
1276 ret = -EIO;
1277 }
1278 }
1279 return ret;
1280}
1281
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001282int ChannelConfig::setDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301283 const std::string& objPath,
1284 const std::string& interface,
1285 const std::string& property,
1286 const DbusVariant& value)
1287{
1288 try
1289 {
1290 auto method =
1291 bus.new_method_call(service.c_str(), objPath.c_str(),
1292 "org.freedesktop.DBus.Properties", "Set");
1293
1294 method.append(interface, property, value);
1295
1296 auto reply = bus.call(method);
1297 }
1298 catch (const sdbusplus::exception::SdBusError& e)
1299 {
1300 log<level::DEBUG>("set-property failed",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301301 entry("SERVICE=%s", service.c_str()),
1302 entry("OBJPATH=%s", objPath.c_str()),
1303 entry("INTERFACE=%s", interface.c_str()),
1304 entry("PROP=%s", property.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301305 return -EIO;
1306 }
1307
1308 return 0;
1309}
1310
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001311int ChannelConfig::getDbusProperty(const std::string& service,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301312 const std::string& objPath,
1313 const std::string& interface,
1314 const std::string& property,
1315 DbusVariant& value)
1316{
1317 try
1318 {
1319 auto method =
1320 bus.new_method_call(service.c_str(), objPath.c_str(),
1321 "org.freedesktop.DBus.Properties", "Get");
1322
1323 method.append(interface, property);
1324
1325 auto reply = bus.call(method);
1326 reply.read(value);
1327 }
1328 catch (const sdbusplus::exception::SdBusError& e)
1329 {
1330 log<level::DEBUG>("get-property failed",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301331 entry("SERVICE=%s", service.c_str()),
1332 entry("OBJPATH=%s", objPath.c_str()),
1333 entry("INTERFACE=%s", interface.c_str()),
1334 entry("PROP=%s", property.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301335 return -EIO;
1336 }
1337 return 0;
1338}
1339
1340int ChannelConfig::syncNetworkChannelConfig()
1341{
1342 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1343 channelLock{*channelMutex};
1344 bool isUpdated = false;
1345 for (uint8_t chNum = 0; chNum < maxIpmiChannels; chNum++)
1346 {
1347 if (getChannelSessionSupport(chNum) != EChannelSessSupported::none)
1348 {
1349 std::string intfPrivStr;
1350 try
1351 {
AppaRao Puli9613ed72018-09-01 23:46:44 +05301352 std::string networkIntfObj =
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301353 std::string(networkIntfObjectBasePath) + "/" +
1354 channelData[chNum].chName;
AppaRao Puli9613ed72018-09-01 23:46:44 +05301355 DbusVariant variant;
Johnathan Manteyf92261d2018-12-10 15:49:34 -08001356 if (0 != getDbusProperty(networkIntfServiceName, networkIntfObj,
AppaRao Puli9613ed72018-09-01 23:46:44 +05301357 networkChConfigIntfName,
1358 privilegePropertyString, variant))
1359 {
1360 log<level::DEBUG>("Network interface does not exist",
Ayushi Smriti05ad3412019-10-16 16:10:18 +05301361 entry("INTERFACE=%s",
Richard Marian Thomaiyar73906b92019-01-04 23:48:02 +05301362 channelData[chNum].chName.c_str()));
AppaRao Puli9613ed72018-09-01 23:46:44 +05301363 continue;
1364 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001365 intfPrivStr = std::get<std::string>(variant);
AppaRao Puli9613ed72018-09-01 23:46:44 +05301366 }
Vernon Maueryf442e112019-04-09 11:44:36 -07001367 catch (const std::bad_variant_access& e)
AppaRao Puli9613ed72018-09-01 23:46:44 +05301368 {
1369 log<level::DEBUG>(
1370 "exception: Network interface does not exist");
1371 continue;
1372 }
1373 catch (const sdbusplus::exception::SdBusError& e)
1374 {
1375 log<level::DEBUG>(
1376 "exception: Network interface does not exist");
1377 continue;
1378 }
1379
1380 uint8_t intfPriv =
1381 static_cast<uint8_t>(convertToPrivLimitIndex(intfPrivStr));
1382 if (channelData[chNum].chAccess.chNonVolatileData.privLimit !=
1383 intfPriv)
1384 {
1385 isUpdated = true;
1386 channelData[chNum].chAccess.chNonVolatileData.privLimit =
1387 intfPriv;
1388 channelData[chNum].chAccess.chVolatileData.privLimit = intfPriv;
1389 }
1390 }
1391 }
1392
1393 if (isUpdated)
1394 {
1395 // Write persistent data to file
1396 if (writeChannelPersistData() != 0)
1397 {
1398 log<level::DEBUG>("Failed to update the persistent data file");
1399 return -EIO;
1400 }
1401 // Write Volatile data to file
1402 if (writeChannelVolatileData() != 0)
1403 {
1404 log<level::DEBUG>("Failed to update the channel volatile data");
1405 return -EIO;
1406 }
1407 }
1408
1409 return 0;
1410}
1411
AppaRao Puli071f3f22018-05-24 16:45:30 +05301412void ChannelConfig::initChannelPersistData()
1413{
Richard Marian Thomaiyare91474c2019-09-01 23:02:47 +05301414 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1415 channelLock{*channelMutex};
1416
AppaRao Puli071f3f22018-05-24 16:45:30 +05301417 /* Always read the channel config */
1418 if (loadChannelConfig() != 0)
1419 {
1420 log<level::ERR>("Failed to read channel config file");
1421 throw std::ios_base::failure("Failed to load channel configuration");
1422 }
1423
1424 /* Populate the channel persist data */
1425 if (readChannelPersistData() != 0)
1426 {
1427 // Copy default NV data to RW location
1428 std::experimental::filesystem::copy_file(channelAccessDefaultFilename,
1429 channelNvDataFilename);
1430
1431 // Load the channel access NV data
1432 if (readChannelPersistData() != 0)
1433 {
1434 log<level::ERR>("Failed to read channel access NV data");
1435 throw std::ios_base::failure(
1436 "Failed to read channel access NV configuration");
1437 }
1438 }
1439
1440 // First check the volatile data file
1441 // If not present, load the default values
1442 if (readChannelVolatileData() != 0)
1443 {
1444 // Copy default volatile data to temporary location
1445 // NV file(channelNvDataFilename) must have created by now.
1446 std::experimental::filesystem::copy_file(channelNvDataFilename,
1447 channelVolatileDataFilename);
1448
1449 // Load the channel access volatile data
1450 if (readChannelVolatileData() != 0)
1451 {
1452 log<level::ERR>("Failed to read channel access volatile data");
1453 throw std::ios_base::failure(
1454 "Failed to read channel access volatile configuration");
1455 }
1456 }
AppaRao Puli9613ed72018-09-01 23:46:44 +05301457
1458 // Synchronize the channel config(priv) with network channel
1459 // configuration(priv) over dbus
1460 if (syncNetworkChannelConfig() != 0)
1461 {
1462 log<level::ERR>(
1463 "Failed to synchronize data with network channel config over dbus");
1464 throw std::ios_base::failure(
1465 "Failed to synchronize data with network channel config over dbus");
1466 }
1467
1468 log<level::DEBUG>("Successfully completed channel data initialization.");
AppaRao Puli071f3f22018-05-24 16:45:30 +05301469 return;
1470}
1471
1472} // namespace ipmi