blob: 1222d5a38178083f0435b383ac0bc6ac5fbc569f [file] [log] [blame]
Patrick Venture586d35b2018-09-07 19:56:18 -07001#include "transporthandler.hpp"
2
Patrick Venture3a5071a2018-09-12 13:27:42 -07003#include "app/channel.hpp"
4#include "ipmid.hpp"
5#include "net.hpp"
6#include "timer.hpp"
7#include "utils.hpp"
8
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070010#include <host-ipmid/ipmid-api.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070011
12#include <chrono>
13#include <fstream>
Patrick Venture3a5071a2018-09-12 13:27:42 -070014#include <phosphor-logging/elog-errors.hpp>
15#include <phosphor-logging/log.hpp>
tomjose26e17732016-03-03 08:52:51 -060016#include <string>
Patrick Venture3a5071a2018-09-12 13:27:42 -070017#include <xyz/openbmc_project/Common/error.hpp>
18
19#define SYSTEMD_NETWORKD_DBUS 1
20
21#ifdef SYSTEMD_NETWORKD_DBUS
22#include <mapper.h>
23#include <systemd/sd-bus.h>
24#endif
Patrick Venture586d35b2018-09-07 19:56:18 -070025
Vernon Mauery185b9f82018-07-20 10:52:36 -070026#if __has_include(<filesystem>)
27#include <filesystem>
28#elif __has_include(<experimental/filesystem>)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053029#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070030namespace std
31{
32// splice experimental::filesystem into std
33namespace filesystem = std::experimental::filesystem;
34} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070035#else
Patrick Venture0b02be92018-08-31 11:55:55 -070036#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070037#endif
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050038
Ratan Gupta7a7f0122018-03-07 12:31:05 +053039extern std::unique_ptr<phosphor::ipmi::Timer> networkTimer;
Ratan Gupta1247e0b2018-03-07 10:47:25 +053040
Patrick Venture0b02be92018-08-31 11:55:55 -070041const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx
Ratan Gupta1247e0b2018-03-07 10:47:25 +053042constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
Adriana Kobylake08fbc62016-02-09 16:17:23 -060043
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080044std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
Hariharasubramanian R83951912016-01-20 07:06:36 -060045
Ratan Guptab8e99552017-07-27 07:07:48 +053046using namespace phosphor::logging;
47using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta7a7f0122018-03-07 12:31:05 +053048
Vernon Mauery185b9f82018-07-20 10:52:36 -070049namespace fs = std::filesystem;
Hariharasubramanian R83951912016-01-20 07:06:36 -060050
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050051void register_netfn_transport_functions() __attribute__((constructor));
52
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080053struct ChannelConfig_t* getChannelConfig(int channel)
54{
55 auto item = channelConfig.find(channel);
56 if (item == channelConfig.end())
57 {
58 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
59 }
60
61 return channelConfig[channel].get();
62}
63
Patrick Venture0b02be92018-08-31 11:55:55 -070064// Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network
65// Manager or Cache based on Set-In-Progress State
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080066ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
tomjose26e17732016-03-03 08:52:51 -060067{
tomjose26e17732016-03-03 08:52:51 -060068 ipmi_ret_t rc = IPMI_CC_OK;
Ratan Guptab8e99552017-07-27 07:07:48 +053069 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Ratan Gupta533d03b2017-07-30 10:39:22 +053070
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080071 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
72 // if ethdevice is an empty string they weren't expecting this channel.
73 if (ethdevice.empty())
74 {
75 // TODO: return error from getNetworkData()
76 return IPMI_CC_INVALID_FIELD_REQUEST;
77 }
78 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
79 auto channelConf = getChannelConfig(channel);
80
Ratan Guptab8e99552017-07-27 07:07:48 +053081 try
tomjose26e17732016-03-03 08:52:51 -060082 {
Ratan Guptab8e99552017-07-27 07:07:48 +053083 switch (lan_param)
tomjose26e17732016-03-03 08:52:51 -060084 {
Ratan Guptab8e99552017-07-27 07:07:48 +053085 case LAN_PARM_IP:
86 {
87 std::string ipaddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080088 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +053089 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053090 try
91 {
Patrick Venture0b02be92018-08-31 11:55:55 -070092 auto ipObjectInfo =
93 ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE,
94 ipmi::network::ROOT, ethIP);
Ratan Guptadd646202017-11-21 17:46:59 +053095
96 auto properties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -070097 bus, ipObjectInfo.second, ipObjectInfo.first,
98 ipmi::network::IP_INTERFACE);
Ratan Guptadd646202017-11-21 17:46:59 +053099
100 ipaddress = properties["Address"].get<std::string>();
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530101 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500102 // ignore the exception, as it is a valid condition that
103 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530104 catch (InternalFailure& e)
105 {
106 // nothing to do.
107 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530108 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800109 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530110 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800111 ipaddress = channelConf->ipaddr;
Ratan Guptab8e99552017-07-27 07:07:48 +0530112 }
113
114 inet_pton(AF_INET, ipaddress.c_str(),
115 reinterpret_cast<void*>(data));
116 }
117 break;
118
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530119 case LAN_PARM_IPSRC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530120 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530121 std::string networkInterfacePath;
122
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800123 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530124 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530125 try
126 {
127 ipmi::ObjectTree ancestorMap;
128 // if the system is having ip object,then
129 // get the IP object.
130 auto ipObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700131 bus, ipmi::network::IP_INTERFACE,
132 ipmi::network::ROOT, ethIP);
Ratan Guptab8e99552017-07-27 07:07:48 +0530133
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530134 // Get the parent interface of the IP object.
135 try
136 {
137 ipmi::InterfaceList interfaces;
138 interfaces.emplace_back(
Patrick Venture0b02be92018-08-31 11:55:55 -0700139 ipmi::network::ETHERNET_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530140
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530141 ancestorMap = ipmi::getAllAncestors(
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 bus, ipObject.first, std::move(interfaces));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530143 }
144 catch (InternalFailure& e)
145 {
146 // if unable to get the parent interface
147 // then commit the error and return.
Patrick Venture0b02be92018-08-31 11:55:55 -0700148 log<level::ERR>(
149 "Unable to get the parent interface",
150 entry("PATH=%s", ipObject.first.c_str()),
151 entry("INTERFACE=%s",
152 ipmi::network::ETHERNET_INTERFACE));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530153 break;
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530154 }
155 // for an ip object there would be single parent
156 // interface.
157 networkInterfacePath = ancestorMap.begin()->first;
158 }
159 catch (InternalFailure& e)
160 {
161 // if there is no ip configured on the system,then
162 // get the network interface object.
163 auto networkInterfaceObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700164 bus, ipmi::network::ETHERNET_INTERFACE,
165 ipmi::network::ROOT, ethdevice);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530166
167 networkInterfacePath = networkInterfaceObject.first;
168 }
169
170 auto variant = ipmi::getDbusProperty(
Patrick Venture0b02be92018-08-31 11:55:55 -0700171 bus, ipmi::network::SERVICE, networkInterfacePath,
172 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled");
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530173
174 auto dhcpEnabled = variant.get<bool>();
175 // As per IPMI spec 2=>DHCP, 1=STATIC
Patrick Venture0b02be92018-08-31 11:55:55 -0700176 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP
177 : ipmi::network::IPOrigin::STATIC;
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530178
179 memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
180 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800181 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530182 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700183 memcpy(data, &(channelConf->ipsrc),
184 ipmi::network::IPSRC_SIZE_BYTE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530185 }
186 }
187 break;
188
189 case LAN_PARM_SUBNET:
190 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 unsigned long mask{};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800192 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530193 {
194 try
195 {
Ratan Guptadd646202017-11-21 17:46:59 +0530196 auto ipObjectInfo = ipmi::getIPObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700197 bus, ipmi::network::IP_INTERFACE,
198 ipmi::network::ROOT, ipmi::network::IP_TYPE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530199
200 auto properties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700201 bus, ipObjectInfo.second, ipObjectInfo.first,
202 ipmi::network::IP_INTERFACE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530203
204 auto prefix = properties["PrefixLength"].get<uint8_t>();
205 mask = ipmi::network::MASK_32_BIT;
206 mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
207 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500208 // ignore the exception, as it is a valid condition that
209 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530210 catch (InternalFailure& e)
211 {
212 // nothing to do
213 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530214 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
215 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800216 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530217 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800218 inet_pton(AF_INET, channelConf->netmask.c_str(),
Ratan Guptab8e99552017-07-27 07:07:48 +0530219 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530220 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530221 }
222 break;
223
224 case LAN_PARM_GATEWAY:
225 {
226 std::string gateway;
227
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800228 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530229 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530230 try
231 {
232 auto systemObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700233 bus, ipmi::network::SYSTEMCONFIG_INTERFACE,
234 ipmi::network::ROOT);
Ratan Guptab8e99552017-07-27 07:07:48 +0530235
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530236 auto systemProperties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 bus, systemObject.second, systemObject.first,
238 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530239
Patrick Venture0b02be92018-08-31 11:55:55 -0700240 gateway = systemProperties["DefaultGateway"]
241 .get<std::string>();
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530242 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500243 // ignore the exception, as it is a valid condition that
244 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530245 catch (InternalFailure& e)
246 {
247 // nothing to do
248 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530249 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800250 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530251 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800252 gateway = channelConf->gateway;
Ratan Guptab8e99552017-07-27 07:07:48 +0530253 }
254
255 inet_pton(AF_INET, gateway.c_str(),
256 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530257 }
258 break;
259
260 case LAN_PARM_MAC:
261 {
262 std::string macAddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800263 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530264 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700265 auto macObjectInfo =
266 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
267 ipmi::network::ROOT, ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530268
269 auto variant = ipmi::getDbusProperty(
Patrick Venture0b02be92018-08-31 11:55:55 -0700270 bus, macObjectInfo.second, macObjectInfo.first,
271 ipmi::network::MAC_INTERFACE, "MACAddress");
Ratan Guptab8e99552017-07-27 07:07:48 +0530272
273 macAddress = variant.get<std::string>();
Ratan Guptab8e99552017-07-27 07:07:48 +0530274 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800275 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530276 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800277 macAddress = channelConf->macAddress;
Ratan Guptab8e99552017-07-27 07:07:48 +0530278 }
279
280 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700281 (data), (data + 1), (data + 2), (data + 3), (data + 4),
Ratan Guptab8e99552017-07-27 07:07:48 +0530282 (data + 5));
283 }
284 break;
285
Ratan Gupta533d03b2017-07-30 10:39:22 +0530286 case LAN_PARM_VLAN:
287 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700288 uint16_t vlanID{};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800289 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530290 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530291 try
Ratan Gupta533d03b2017-07-30 10:39:22 +0530292 {
Ratan Guptadd646202017-11-21 17:46:59 +0530293 auto ipObjectInfo = ipmi::getIPObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700294 bus, ipmi::network::IP_INTERFACE,
295 ipmi::network::ROOT, ipmi::network::IP_TYPE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530296
297 vlanID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700298 ipmi::network::getVLAN(ipObjectInfo.first));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530299
300 vlanID = htole16(vlanID);
301
302 if (vlanID)
303 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700304 // Enable the 16th bit
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530305 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
306 }
307 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500308 // ignore the exception, as it is a valid condition that
309 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530310 catch (InternalFailure& e)
311 {
312 // nothing to do
Ratan Gupta533d03b2017-07-30 10:39:22 +0530313 }
314
315 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
316 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800317 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530318 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800319 memcpy(data, &(channelConf->vlanID),
Ratan Gupta533d03b2017-07-30 10:39:22 +0530320 ipmi::network::VLAN_SIZE_BYTE);
321 }
322 }
323 break;
324
Ratan Guptab8e99552017-07-27 07:07:48 +0530325 default:
326 rc = IPMI_CC_PARM_OUT_OF_RANGE;
tomjose26e17732016-03-03 08:52:51 -0600327 }
328 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530329 catch (InternalFailure& e)
tomjose26e17732016-03-03 08:52:51 -0600330 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530331 commit<InternalFailure>();
332 rc = IPMI_CC_UNSPECIFIED_ERROR;
333 return rc;
tomjose26e17732016-03-03 08:52:51 -0600334 }
tomjose26e17732016-03-03 08:52:51 -0600335 return rc;
336}
337
Tom Josepha30c8d32018-03-22 02:15:03 +0530338namespace cipher
339{
340
341std::vector<uint8_t> getCipherList()
342{
343 std::vector<uint8_t> cipherList;
344
345 std::ifstream jsonFile(configFile);
346 if (!jsonFile.is_open())
347 {
348 log<level::ERR>("Channel Cipher suites file not found");
349 elog<InternalFailure>();
350 }
351
352 auto data = Json::parse(jsonFile, nullptr, false);
353 if (data.is_discarded())
354 {
355 log<level::ERR>("Parsing channel cipher suites JSON failed");
356 elog<InternalFailure>();
357 }
358
359 // Byte 1 is reserved
360 cipherList.push_back(0x00);
361
362 for (const auto& record : data)
363 {
364 cipherList.push_back(record.value(cipher, 0));
365 }
366
367 return cipherList;
368}
369
Patrick Venture0b02be92018-08-31 11:55:55 -0700370} // namespace cipher
Tom Josepha30c8d32018-03-22 02:15:03 +0530371
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500372ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700373 ipmi_request_t request,
374 ipmi_response_t response,
375 ipmi_data_len_t data_len,
376 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500377{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500378 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800379 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500380 *data_len = 0;
381 return rc;
382}
383
Ratan Guptab8e99552017-07-27 07:07:48 +0530384struct set_lan_t
385{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500386 uint8_t channel;
387 uint8_t parameter;
388 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
Patrick Venture0b02be92018-08-31 11:55:55 -0700389} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500390
Patrick Venture0b02be92018-08-31 11:55:55 -0700391ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Ratan Guptab8e99552017-07-27 07:07:48 +0530392 ipmi_request_t request,
393 ipmi_response_t response,
394 ipmi_data_len_t data_len,
395 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500396{
397 ipmi_ret_t rc = IPMI_CC_OK;
398 *data_len = 0;
Nan Li3d0df912016-10-18 19:51:41 +0800399
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530400 using namespace std::chrono_literals;
401
402 // time to wait before applying the network changes.
403 constexpr auto networkTimeout = 10000000us; // 10 sec
404
Ratan Guptab8e99552017-07-27 07:07:48 +0530405 char ipaddr[INET_ADDRSTRLEN];
406 char netmask[INET_ADDRSTRLEN];
407 char gateway[INET_ADDRSTRLEN];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500408
Ratan Guptab8e99552017-07-27 07:07:48 +0530409 auto reqptr = reinterpret_cast<const set_lan_t*>(request);
410 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500411
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800412 // channel number is the lower nibble
413 int channel = reqptr->channel & CHANNEL_MASK;
414 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
415 if (ethdevice.empty())
416 {
417 return IPMI_CC_INVALID_FIELD_REQUEST;
418 }
419 auto channelConf = getChannelConfig(channel);
420
Ratan Guptab8e99552017-07-27 07:07:48 +0530421 switch (reqptr->parameter)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500422 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530423 case LAN_PARM_IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600424 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530425 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700426 reqptr->data[0], reqptr->data[1], reqptr->data[2],
427 reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500428
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800429 channelConf->ipaddr.assign(ipaddr);
Ratan Guptab8e99552017-07-27 07:07:48 +0530430 }
431 break;
432
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530433 case LAN_PARM_IPSRC:
434 {
435 uint8_t ipsrc{};
436 memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800437 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530438 }
439 break;
440
Ratan Guptab8e99552017-07-27 07:07:48 +0530441 case LAN_PARM_MAC:
442 {
443 char mac[SIZE_MAC];
444
445 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 reqptr->data[0], reqptr->data[1], reqptr->data[2],
447 reqptr->data[3], reqptr->data[4], reqptr->data[5]);
Ratan Guptab8e99552017-07-27 07:07:48 +0530448
Patrick Venture0b02be92018-08-31 11:55:55 -0700449 auto macObjectInfo =
450 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
451 ipmi::network::ROOT, ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530452
Patrick Venture0b02be92018-08-31 11:55:55 -0700453 ipmi::setDbusProperty(
454 bus, macObjectInfo.second, macObjectInfo.first,
455 ipmi::network::MAC_INTERFACE, "MACAddress", std::string(mac));
Ratan Guptab8e99552017-07-27 07:07:48 +0530456
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800457 channelConf->macAddress = mac;
Ratan Guptab8e99552017-07-27 07:07:48 +0530458 }
459 break;
460
461 case LAN_PARM_SUBNET:
462 {
463 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700464 reqptr->data[0], reqptr->data[1], reqptr->data[2],
465 reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800466 channelConf->netmask.assign(netmask);
Ratan Guptab8e99552017-07-27 07:07:48 +0530467 }
468 break;
469
470 case LAN_PARM_GATEWAY:
471 {
472 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700473 reqptr->data[0], reqptr->data[1], reqptr->data[2],
474 reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800475 channelConf->gateway.assign(gateway);
Ratan Guptab8e99552017-07-27 07:07:48 +0530476 }
477 break;
478
Ratan Gupta533d03b2017-07-30 10:39:22 +0530479 case LAN_PARM_VLAN:
480 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700481 uint16_t vlan{};
Ratan Gupta533d03b2017-07-30 10:39:22 +0530482 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
483 // We are not storing the enable bit
484 // We assume that ipmitool always send enable
485 // bit as 1.
486 vlan = le16toh(vlan);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800487 channelConf->vlanID = vlan;
Ratan Gupta533d03b2017-07-30 10:39:22 +0530488 }
489 break;
490
Ratan Guptab8e99552017-07-27 07:07:48 +0530491 case LAN_PARM_INPROGRESS:
492 {
493 if (reqptr->data[0] == SET_COMPLETE)
494 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800495 channelConf->lan_set_in_progress = SET_COMPLETE;
Ratan Guptab8e99552017-07-27 07:07:48 +0530496
Patrick Venture0b02be92018-08-31 11:55:55 -0700497 log<level::INFO>(
498 "Network data from Cache",
499 entry("PREFIX=%s", channelConf->netmask.c_str()),
500 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
501 entry("GATEWAY=%s", channelConf->gateway.c_str()),
502 entry("VLAN=%d", channelConf->vlanID));
Ratan Guptab8e99552017-07-27 07:07:48 +0530503
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530504 if (!networkTimer)
505 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700506 log<level::ERR>("Network timer is not instantiated");
507 return IPMI_CC_UNSPECIFIED_ERROR;
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530508 }
509
510 // start/restart the timer
511 networkTimer->startTimer(networkTimeout);
Ratan Guptab8e99552017-07-27 07:07:48 +0530512 }
513 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
514 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800515 channelConf->lan_set_in_progress = SET_IN_PROGRESS;
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530516 channelConf->flush = true;
Ratan Guptab8e99552017-07-27 07:07:48 +0530517 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530518 }
519 break;
520
521 default:
522 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530523 rc = IPMI_CC_PARM_NOT_SUPPORTED;
524 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530525 }
vishwa1eaea4f2016-02-26 11:57:40 -0600526
tomjose26e17732016-03-03 08:52:51 -0600527 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500528}
529
Ratan Guptab8e99552017-07-27 07:07:48 +0530530struct get_lan_t
531{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500532 uint8_t rev_channel;
533 uint8_t parameter;
534 uint8_t parameter_set;
535 uint8_t parameter_block;
Patrick Venture0b02be92018-08-31 11:55:55 -0700536} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500537
Patrick Venture0b02be92018-08-31 11:55:55 -0700538ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Ratan Guptab8e99552017-07-27 07:07:48 +0530539 ipmi_request_t request,
540 ipmi_response_t response,
541 ipmi_data_len_t data_len,
542 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500543{
544 ipmi_ret_t rc = IPMI_CC_OK;
545 *data_len = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500546 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500547
Patrick Venture0b02be92018-08-31 11:55:55 -0700548 get_lan_t* reqptr = (get_lan_t*)request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800549 // channel number is the lower nibble
550 int channel = reqptr->rev_channel & CHANNEL_MASK;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500551
552 if (reqptr->rev_channel & 0x80) // Revision is bit 7
553 {
554 // Only current revision was requested
555 *data_len = sizeof(current_revision);
556 memcpy(response, &current_revision, *data_len);
557 return IPMI_CC_OK;
558 }
559
Tom Josepha30c8d32018-03-22 02:15:03 +0530560 static std::vector<uint8_t> cipherList;
561 static auto listInit = false;
562
563 if (!listInit)
564 {
565 try
566 {
567 cipherList = cipher::getCipherList();
568 listInit = true;
569 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700570 catch (const std::exception& e)
Tom Josepha30c8d32018-03-22 02:15:03 +0530571 {
572 return IPMI_CC_UNSPECIFIED_ERROR;
573 }
574 }
575
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800576 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
577 if (ethdevice.empty())
578 {
579 return IPMI_CC_INVALID_FIELD_REQUEST;
580 }
581 auto channelConf = getChannelConfig(channel);
582
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600583 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500584 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800585 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500586 *data_len = sizeof(buf);
587 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500588 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600589 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500590 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700591 uint8_t buf[] = {current_revision, 0x04};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500592 *data_len = sizeof(buf);
593 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500594 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600595 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500596 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700597 uint8_t buf[] = {current_revision, 0x04, 0x04, 0x04, 0x04, 0x04};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500598 *data_len = sizeof(buf);
599 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500600 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530601 else if ((reqptr->parameter == LAN_PARM_IP) ||
602 (reqptr->parameter == LAN_PARM_SUBNET) ||
603 (reqptr->parameter == LAN_PARM_GATEWAY) ||
604 (reqptr->parameter == LAN_PARM_MAC))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500605 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530606 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500607
tomjose26e17732016-03-03 08:52:51 -0600608 *data_len = sizeof(current_revision);
609 memcpy(buf, &current_revision, *data_len);
610
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800611 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600612 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530613 if (reqptr->parameter == LAN_PARM_MAC)
614 {
615 *data_len = sizeof(buf);
616 }
617 else
618 {
619 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
620 }
tomjose26e17732016-03-03 08:52:51 -0600621 memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600622 }
tomjose26e17732016-03-03 08:52:51 -0600623 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600624 {
tomjose26e17732016-03-03 08:52:51 -0600625 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600626 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500627 }
Ratan Gupta533d03b2017-07-30 10:39:22 +0530628 else if (reqptr->parameter == LAN_PARM_VLAN)
629 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530630 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {};
Ratan Gupta533d03b2017-07-30 10:39:22 +0530631
632 *data_len = sizeof(current_revision);
633 memcpy(buf, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800634 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530635 {
636 *data_len = sizeof(buf);
637 memcpy(response, &buf, *data_len);
638 }
639 }
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530640 else if (reqptr->parameter == LAN_PARM_IPSRC)
641 {
642 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
643 *data_len = sizeof(current_revision);
644 memcpy(buff, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800645 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530646 {
647 *data_len = sizeof(buff);
648 memcpy(response, &buff, *data_len);
649 }
650 }
Tom Josepha30c8d32018-03-22 02:15:03 +0530651 else if (reqptr->parameter == CIPHER_SUITE_COUNT)
652 {
653 *(static_cast<uint8_t*>(response)) = current_revision;
654 // Byte 1 is reserved byte and does not indicate a cipher suite ID, so
655 // no of cipher suite entry count is one less than the size of the
656 // vector
657 auto count = static_cast<uint8_t>(cipherList.size() - 1);
658 *(static_cast<uint8_t*>(response) + 1) = count;
659 *data_len = sizeof(current_revision) + sizeof(count);
660 }
661 else if (reqptr->parameter == CIPHER_SUITE_ENTRIES)
662 {
663 *(static_cast<uint8_t*>(response)) = current_revision;
664 // Byte 1 is reserved
Patrick Venture0b02be92018-08-31 11:55:55 -0700665 std::copy_n(cipherList.data(), cipherList.size(),
Tom Josepha30c8d32018-03-22 02:15:03 +0530666 static_cast<uint8_t*>(response) + 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700667 *data_len =
668 sizeof(current_revision) + static_cast<uint8_t>(cipherList.size());
Tom Josepha30c8d32018-03-22 02:15:03 +0530669 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500670 else
671 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530672 log<level::ERR>("Unsupported parameter",
673 entry("PARAMETER=0x%x", reqptr->parameter));
vishwa1eaea4f2016-02-26 11:57:40 -0600674 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500675 }
676
677 return rc;
678}
679
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530680void applyChanges(int channel)
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530681{
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530682 std::string ipaddress;
683 std::string gateway;
Patrick Venture0b02be92018-08-31 11:55:55 -0700684 uint8_t prefix{};
685 uint32_t vlanID{};
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530686 std::string networkInterfacePath;
687 ipmi::DbusObjectInfo ipObject;
688 ipmi::DbusObjectInfo systemObject;
689
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530690 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
691 if (ethdevice.empty())
692 {
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530693 log<level::ERR>("Unable to get the interface name",
694 entry("CHANNEL=%d", channel));
695 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530696 }
697 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
698 auto channelConf = getChannelConfig(channel);
699
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530700 try
701 {
702 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
703
704 log<level::INFO>("Network data from Cache",
705 entry("PREFIX=%s", channelConf->netmask.c_str()),
706 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
707 entry("GATEWAY=%s", channelConf->gateway.c_str()),
708 entry("VLAN=%d", channelConf->vlanID),
709 entry("IPSRC=%d", channelConf->ipsrc));
710 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
711 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700712 // get the first twelve bits which is vlan id
713 // not interested in rest of the bits.
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530714 channelConf->vlanID = le32toh(channelConf->vlanID);
715 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
716 }
717
718 // if the asked ip src is DHCP then not interested in
719 // any given data except vlan.
720 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
721 {
722 // always get the system object
Patrick Venture0b02be92018-08-31 11:55:55 -0700723 systemObject =
724 ipmi::getDbusObject(bus, ipmi::network::SYSTEMCONFIG_INTERFACE,
725 ipmi::network::ROOT);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530726
727 // the below code is to determine the mode of the interface
728 // as the handling is same, if the system is configured with
729 // DHCP or user has given all the data.
730 try
731 {
732 ipmi::ObjectTree ancestorMap;
733
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 ipmi::InterfaceList interfaces{
735 ipmi::network::ETHERNET_INTERFACE};
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530736
737 // if the system is having ip object,then
738 // get the IP object.
Patrick Venture0b02be92018-08-31 11:55:55 -0700739 ipObject = ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE,
740 ipmi::network::ROOT, ethIp);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530741
742 // Get the parent interface of the IP object.
743 try
744 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700745 ancestorMap = ipmi::getAllAncestors(bus, ipObject.first,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530746 std::move(interfaces));
747 }
748 catch (InternalFailure& e)
749 {
750 // if unable to get the parent interface
751 // then commit the error and return.
752 log<level::ERR>("Unable to get the parent interface",
753 entry("PATH=%s", ipObject.first.c_str()),
754 entry("INTERFACE=%s",
755 ipmi::network::ETHERNET_INTERFACE));
756 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530757 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530758 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530759 }
760
761 networkInterfacePath = ancestorMap.begin()->first;
762 }
763 catch (InternalFailure& e)
764 {
765 // TODO Currently IPMI supports single interface,need to handle
766 // Multiple interface through
767 // https://github.com/openbmc/openbmc/issues/2138
768
769 // if there is no ip configured on the system,then
770 // get the network interface object.
Patrick Venture0b02be92018-08-31 11:55:55 -0700771 auto networkInterfaceObject =
772 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE,
773 ipmi::network::ROOT, ethdevice);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530774
775 networkInterfacePath = std::move(networkInterfaceObject.first);
776 }
777
778 // get the configured mode on the system.
Patrick Venture0b02be92018-08-31 11:55:55 -0700779 auto enableDHCP =
780 ipmi::getDbusProperty(
781 bus, ipmi::network::SERVICE, networkInterfacePath,
782 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled")
783 .get<bool>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530784
785 // if ip address source is not given then get the ip source mode
786 // from the system so that it can be applied later.
787 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
788 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700789 channelConf->ipsrc = (enableDHCP)
790 ? ipmi::network::IPOrigin::DHCP
791 : ipmi::network::IPOrigin::STATIC;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530792 }
793
794 // check whether user has given all the data
795 // or the configured system interface is dhcp enabled,
796 // in both of the cases get the values from the cache.
797 if ((!channelConf->ipaddr.empty() &&
798 !channelConf->netmask.empty() &&
799 !channelConf->gateway.empty()) ||
800 (enableDHCP)) // configured system interface mode = DHCP
801 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 // convert mask into prefix
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530803 ipaddress = channelConf->ipaddr;
804 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
805 gateway = channelConf->gateway;
806 }
807 else // asked ip src = static and configured system src = static
Patrick Venture0b02be92018-08-31 11:55:55 -0700808 // or partially given data.
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530809 {
810 // We have partial filled cache so get the remaining
811 // info from the system.
812
813 // Get the network data from the system as user has
814 // not given all the data then use the data fetched from the
815 // system but it is implementation dependent,IPMI spec doesn't
816 // force it.
817
818 // if system is not having any ip object don't throw error,
819 try
820 {
821 auto properties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700822 bus, ipObject.second, ipObject.first,
823 ipmi::network::IP_INTERFACE);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530824
Patrick Venture0b02be92018-08-31 11:55:55 -0700825 ipaddress = channelConf->ipaddr.empty()
826 ? properties["Address"].get<std::string>()
827 : channelConf->ipaddr;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530828
Patrick Venture0b02be92018-08-31 11:55:55 -0700829 prefix = channelConf->netmask.empty()
830 ? properties["PrefixLength"].get<uint8_t>()
831 : ipmi::network::toPrefix(
832 AF_INET, channelConf->netmask);
833 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530834 catch (InternalFailure& e)
835 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700836 log<level::INFO>(
837 "Failed to get IP object which matches",
838 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
839 entry("MATCH=%s", ethIp.c_str()));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530840 }
841
842 auto systemProperties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700843 bus, systemObject.second, systemObject.first,
844 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530845
Patrick Venture0b02be92018-08-31 11:55:55 -0700846 gateway =
847 channelConf->gateway.empty()
848 ? systemProperties["DefaultGateway"].get<std::string>()
849 : channelConf->gateway;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530850 }
851 }
852
853 // Currently network manager doesn't support purging of all the
854 // ip addresses and the vlan interfaces from the parent interface,
855 // TODO once the support is there, will make the change here.
856 // https://github.com/openbmc/openbmc/issues/2141.
857
858 // TODO Currently IPMI supports single interface,need to handle
859 // Multiple interface through
860 // https://github.com/openbmc/openbmc/issues/2138
861
862 // instead of deleting all the vlan interfaces and
863 // all the ipv4 address,we will call reset method.
Patrick Venture0b02be92018-08-31 11:55:55 -0700864 // delete all the vlan interfaces
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530865
Patrick Venture0b02be92018-08-31 11:55:55 -0700866 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530867 ipmi::network::VLAN_INTERFACE);
868
869 // set the interface mode to static
Patrick Venture0b02be92018-08-31 11:55:55 -0700870 auto networkInterfaceObject =
871 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE,
872 ipmi::network::ROOT, ethdevice);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530873
874 // setting the physical interface mode to static.
Patrick Venture0b02be92018-08-31 11:55:55 -0700875 ipmi::setDbusProperty(
876 bus, ipmi::network::SERVICE, networkInterfaceObject.first,
877 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530878
879 networkInterfacePath = networkInterfaceObject.first;
880
Patrick Venture0b02be92018-08-31 11:55:55 -0700881 // delete all the ipv4 addresses
882 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
883 ipmi::network::IP_INTERFACE, ethIp);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530884
885 if (vlanID)
886 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700887 ipmi::network::createVLAN(bus, ipmi::network::SERVICE,
888 ipmi::network::ROOT, ethdevice, vlanID);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530889
890 auto networkInterfaceObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700891 bus, ipmi::network::VLAN_INTERFACE, ipmi::network::ROOT);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530892
Patrick Venture0b02be92018-08-31 11:55:55 -0700893 networkInterfacePath = networkInterfaceObject.first;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530894 }
895
896 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
897 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700898 ipmi::setDbusProperty(
899 bus, ipmi::network::SERVICE, networkInterfacePath,
900 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", true);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530901 }
902 else
903 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700904 // change the mode to static
905 ipmi::setDbusProperty(
906 bus, ipmi::network::SERVICE, networkInterfacePath,
907 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530908
909 if (!ipaddress.empty())
910 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700911 ipmi::network::createIP(bus, ipmi::network::SERVICE,
912 networkInterfacePath, ipv4Protocol,
913 ipaddress, prefix);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530914 }
915
916 if (!gateway.empty())
917 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700918 ipmi::setDbusProperty(bus, systemObject.second,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530919 systemObject.first,
920 ipmi::network::SYSTEMCONFIG_INTERFACE,
Patrick Venture0b02be92018-08-31 11:55:55 -0700921 "DefaultGateway", std::string(gateway));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530922 }
923 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530924 }
925 catch (InternalFailure& e)
926 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700927 log<level::ERR>(
928 "Failed to set network data", entry("PREFIX=%d", prefix),
929 entry("ADDRESS=%s", ipaddress.c_str()),
930 entry("GATEWAY=%s", gateway.c_str()), entry("VLANID=%d", vlanID),
931 entry("IPSRC=%d", channelConf->ipsrc));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530932
933 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530934 }
935
936 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530937}
938
939void commitNetworkChanges()
940{
Patrick Venture0b02be92018-08-31 11:55:55 -0700941 for (const auto& channel : channelConfig)
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530942 {
943 if (channel.second->flush)
944 {
945 applyChanges(channel.first);
946 }
947 }
948}
949
950void createNetworkTimer()
951{
952 if (!networkTimer)
953 {
954 std::function<void()> networkTimerCallback(
Patrick Venture0b02be92018-08-31 11:55:55 -0700955 std::bind(&commitNetworkChanges));
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530956
Patrick Venture0b02be92018-08-31 11:55:55 -0700957 networkTimer = std::make_unique<phosphor::ipmi::Timer>(
958 ipmid_get_sd_event_connection(), networkTimerCallback);
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530959 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530960}
961
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500962void register_netfn_transport_functions()
963{
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530964 // As this timer is only for transport handler
965 // so creating it here.
966 createNetworkTimer();
Tom05732372016-09-06 17:21:23 +0530967 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700968 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL,
969 ipmi_transport_wildcard, PRIVILEGE_USER);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500970
Tom05732372016-09-06 17:21:23 +0530971 // <Set LAN Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -0700972 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL,
973 ipmi_transport_set_lan, PRIVILEGE_ADMIN);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500974
Tom05732372016-09-06 17:21:23 +0530975 // <Get LAN Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -0700976 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL,
977 ipmi_transport_get_lan, PRIVILEGE_OPERATOR);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500978
979 return;
980}