blob: 43c88bba6f5841befa1b758e1a63ed68889c4fa4 [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
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700179 std::memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530180 }
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 Ventureb51bf9c2018-09-10 15:53:14 -0700183 std::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 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700214 std::memcpy(data, &mask,
215 ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530216 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800217 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530218 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800219 inet_pton(AF_INET, channelConf->netmask.c_str(),
Ratan Guptab8e99552017-07-27 07:07:48 +0530220 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530221 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530222 }
223 break;
224
225 case LAN_PARM_GATEWAY:
226 {
227 std::string gateway;
228
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800229 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530230 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530231 try
232 {
233 auto systemObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700234 bus, ipmi::network::SYSTEMCONFIG_INTERFACE,
235 ipmi::network::ROOT);
Ratan Guptab8e99552017-07-27 07:07:48 +0530236
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530237 auto systemProperties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 bus, systemObject.second, systemObject.first,
239 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530240
Patrick Venture0b02be92018-08-31 11:55:55 -0700241 gateway = systemProperties["DefaultGateway"]
242 .get<std::string>();
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530243 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500244 // ignore the exception, as it is a valid condition that
245 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530246 catch (InternalFailure& e)
247 {
248 // nothing to do
249 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530250 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800251 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530252 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800253 gateway = channelConf->gateway;
Ratan Guptab8e99552017-07-27 07:07:48 +0530254 }
255
256 inet_pton(AF_INET, gateway.c_str(),
257 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530258 }
259 break;
260
261 case LAN_PARM_MAC:
262 {
263 std::string macAddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800264 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530265 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700266 auto macObjectInfo =
267 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
268 ipmi::network::ROOT, ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530269
270 auto variant = ipmi::getDbusProperty(
Patrick Venture0b02be92018-08-31 11:55:55 -0700271 bus, macObjectInfo.second, macObjectInfo.first,
272 ipmi::network::MAC_INTERFACE, "MACAddress");
Ratan Guptab8e99552017-07-27 07:07:48 +0530273
274 macAddress = variant.get<std::string>();
Ratan Guptab8e99552017-07-27 07:07:48 +0530275 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800276 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530277 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800278 macAddress = channelConf->macAddress;
Ratan Guptab8e99552017-07-27 07:07:48 +0530279 }
280
281 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
Patrick Venture0b02be92018-08-31 11:55:55 -0700282 (data), (data + 1), (data + 2), (data + 3), (data + 4),
Ratan Guptab8e99552017-07-27 07:07:48 +0530283 (data + 5));
284 }
285 break;
286
Ratan Gupta533d03b2017-07-30 10:39:22 +0530287 case LAN_PARM_VLAN:
288 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700289 uint16_t vlanID{};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800290 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530291 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530292 try
Ratan Gupta533d03b2017-07-30 10:39:22 +0530293 {
Ratan Guptadd646202017-11-21 17:46:59 +0530294 auto ipObjectInfo = ipmi::getIPObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700295 bus, ipmi::network::IP_INTERFACE,
296 ipmi::network::ROOT, ipmi::network::IP_TYPE);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530297
298 vlanID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700299 ipmi::network::getVLAN(ipObjectInfo.first));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530300
301 vlanID = htole16(vlanID);
302
303 if (vlanID)
304 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700305 // Enable the 16th bit
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530306 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
307 }
308 }
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500309 // ignore the exception, as it is a valid condition that
310 // the system is not configured with any IP.
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530311 catch (InternalFailure& e)
312 {
313 // nothing to do
Ratan Gupta533d03b2017-07-30 10:39:22 +0530314 }
315
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700316 std::memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
Ratan Gupta533d03b2017-07-30 10:39:22 +0530317 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800318 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530319 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700320 std::memcpy(data, &(channelConf->vlanID),
321 ipmi::network::VLAN_SIZE_BYTE);
Ratan Gupta533d03b2017-07-30 10:39:22 +0530322 }
323 }
324 break;
325
Ratan Guptab8e99552017-07-27 07:07:48 +0530326 default:
327 rc = IPMI_CC_PARM_OUT_OF_RANGE;
tomjose26e17732016-03-03 08:52:51 -0600328 }
329 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530330 catch (InternalFailure& e)
tomjose26e17732016-03-03 08:52:51 -0600331 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530332 commit<InternalFailure>();
333 rc = IPMI_CC_UNSPECIFIED_ERROR;
334 return rc;
tomjose26e17732016-03-03 08:52:51 -0600335 }
tomjose26e17732016-03-03 08:52:51 -0600336 return rc;
337}
338
Tom Josepha30c8d32018-03-22 02:15:03 +0530339namespace cipher
340{
341
342std::vector<uint8_t> getCipherList()
343{
344 std::vector<uint8_t> cipherList;
345
346 std::ifstream jsonFile(configFile);
347 if (!jsonFile.is_open())
348 {
349 log<level::ERR>("Channel Cipher suites file not found");
350 elog<InternalFailure>();
351 }
352
353 auto data = Json::parse(jsonFile, nullptr, false);
354 if (data.is_discarded())
355 {
356 log<level::ERR>("Parsing channel cipher suites JSON failed");
357 elog<InternalFailure>();
358 }
359
360 // Byte 1 is reserved
361 cipherList.push_back(0x00);
362
363 for (const auto& record : data)
364 {
365 cipherList.push_back(record.value(cipher, 0));
366 }
367
368 return cipherList;
369}
370
Patrick Venture0b02be92018-08-31 11:55:55 -0700371} // namespace cipher
Tom Josepha30c8d32018-03-22 02:15:03 +0530372
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500373ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700374 ipmi_request_t request,
375 ipmi_response_t response,
376 ipmi_data_len_t data_len,
377 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500378{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500379 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800380 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500381 *data_len = 0;
382 return rc;
383}
384
Ratan Guptab8e99552017-07-27 07:07:48 +0530385struct set_lan_t
386{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500387 uint8_t channel;
388 uint8_t parameter;
389 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
Patrick Venture0b02be92018-08-31 11:55:55 -0700390} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500391
Patrick Venture0b02be92018-08-31 11:55:55 -0700392ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Ratan Guptab8e99552017-07-27 07:07:48 +0530393 ipmi_request_t request,
394 ipmi_response_t response,
395 ipmi_data_len_t data_len,
396 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500397{
398 ipmi_ret_t rc = IPMI_CC_OK;
399 *data_len = 0;
Nan Li3d0df912016-10-18 19:51:41 +0800400
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530401 using namespace std::chrono_literals;
402
403 // time to wait before applying the network changes.
404 constexpr auto networkTimeout = 10000000us; // 10 sec
405
Ratan Guptab8e99552017-07-27 07:07:48 +0530406 char ipaddr[INET_ADDRSTRLEN];
407 char netmask[INET_ADDRSTRLEN];
408 char gateway[INET_ADDRSTRLEN];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500409
Ratan Guptab8e99552017-07-27 07:07:48 +0530410 auto reqptr = reinterpret_cast<const set_lan_t*>(request);
411 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500412
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800413 // channel number is the lower nibble
414 int channel = reqptr->channel & CHANNEL_MASK;
415 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
416 if (ethdevice.empty())
417 {
418 return IPMI_CC_INVALID_FIELD_REQUEST;
419 }
420 auto channelConf = getChannelConfig(channel);
421
Ratan Guptab8e99552017-07-27 07:07:48 +0530422 switch (reqptr->parameter)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500423 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530424 case LAN_PARM_IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600425 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700426 std::snprintf(ipaddr, INET_ADDRSTRLEN,
427 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0],
428 reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500429
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800430 channelConf->ipaddr.assign(ipaddr);
Ratan Guptab8e99552017-07-27 07:07:48 +0530431 }
432 break;
433
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530434 case LAN_PARM_IPSRC:
435 {
436 uint8_t ipsrc{};
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700437 std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800438 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530439 }
440 break;
441
Ratan Guptab8e99552017-07-27 07:07:48 +0530442 case LAN_PARM_MAC:
443 {
444 char mac[SIZE_MAC];
445
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700446 std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
447 reqptr->data[0], reqptr->data[1], reqptr->data[2],
448 reqptr->data[3], reqptr->data[4], reqptr->data[5]);
Ratan Guptab8e99552017-07-27 07:07:48 +0530449
Patrick Venture0b02be92018-08-31 11:55:55 -0700450 auto macObjectInfo =
451 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
452 ipmi::network::ROOT, ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530453
Patrick Venture0b02be92018-08-31 11:55:55 -0700454 ipmi::setDbusProperty(
455 bus, macObjectInfo.second, macObjectInfo.first,
456 ipmi::network::MAC_INTERFACE, "MACAddress", std::string(mac));
Ratan Guptab8e99552017-07-27 07:07:48 +0530457
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800458 channelConf->macAddress = mac;
Ratan Guptab8e99552017-07-27 07:07:48 +0530459 }
460 break;
461
462 case LAN_PARM_SUBNET:
463 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700464 std::snprintf(netmask, INET_ADDRSTRLEN,
465 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0],
466 reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800467 channelConf->netmask.assign(netmask);
Ratan Guptab8e99552017-07-27 07:07:48 +0530468 }
469 break;
470
471 case LAN_PARM_GATEWAY:
472 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700473 std::snprintf(gateway, INET_ADDRSTRLEN,
474 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0],
475 reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800476 channelConf->gateway.assign(gateway);
Ratan Guptab8e99552017-07-27 07:07:48 +0530477 }
478 break;
479
Ratan Gupta533d03b2017-07-30 10:39:22 +0530480 case LAN_PARM_VLAN:
481 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700482 uint16_t vlan{};
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700483 std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
Ratan Gupta533d03b2017-07-30 10:39:22 +0530484 // We are not storing the enable bit
485 // We assume that ipmitool always send enable
486 // bit as 1.
487 vlan = le16toh(vlan);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800488 channelConf->vlanID = vlan;
Ratan Gupta533d03b2017-07-30 10:39:22 +0530489 }
490 break;
491
Ratan Guptab8e99552017-07-27 07:07:48 +0530492 case LAN_PARM_INPROGRESS:
493 {
494 if (reqptr->data[0] == SET_COMPLETE)
495 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800496 channelConf->lan_set_in_progress = SET_COMPLETE;
Ratan Guptab8e99552017-07-27 07:07:48 +0530497
Patrick Venture0b02be92018-08-31 11:55:55 -0700498 log<level::INFO>(
499 "Network data from Cache",
500 entry("PREFIX=%s", channelConf->netmask.c_str()),
501 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
502 entry("GATEWAY=%s", channelConf->gateway.c_str()),
503 entry("VLAN=%d", channelConf->vlanID));
Ratan Guptab8e99552017-07-27 07:07:48 +0530504
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530505 if (!networkTimer)
506 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700507 log<level::ERR>("Network timer is not instantiated");
508 return IPMI_CC_UNSPECIFIED_ERROR;
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530509 }
510
511 // start/restart the timer
512 networkTimer->startTimer(networkTimeout);
Ratan Guptab8e99552017-07-27 07:07:48 +0530513 }
514 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
515 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800516 channelConf->lan_set_in_progress = SET_IN_PROGRESS;
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530517 channelConf->flush = true;
Ratan Guptab8e99552017-07-27 07:07:48 +0530518 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530519 }
520 break;
521
522 default:
523 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530524 rc = IPMI_CC_PARM_NOT_SUPPORTED;
525 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530526 }
vishwa1eaea4f2016-02-26 11:57:40 -0600527
tomjose26e17732016-03-03 08:52:51 -0600528 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500529}
530
Ratan Guptab8e99552017-07-27 07:07:48 +0530531struct get_lan_t
532{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500533 uint8_t rev_channel;
534 uint8_t parameter;
535 uint8_t parameter_set;
536 uint8_t parameter_block;
Patrick Venture0b02be92018-08-31 11:55:55 -0700537} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500538
Patrick Venture0b02be92018-08-31 11:55:55 -0700539ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Ratan Guptab8e99552017-07-27 07:07:48 +0530540 ipmi_request_t request,
541 ipmi_response_t response,
542 ipmi_data_len_t data_len,
543 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500544{
545 ipmi_ret_t rc = IPMI_CC_OK;
546 *data_len = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500547 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500548
Patrick Venture0b02be92018-08-31 11:55:55 -0700549 get_lan_t* reqptr = (get_lan_t*)request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800550 // channel number is the lower nibble
551 int channel = reqptr->rev_channel & CHANNEL_MASK;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500552
553 if (reqptr->rev_channel & 0x80) // Revision is bit 7
554 {
555 // Only current revision was requested
556 *data_len = sizeof(current_revision);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700557 std::memcpy(response, &current_revision, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500558 return IPMI_CC_OK;
559 }
560
Tom Josepha30c8d32018-03-22 02:15:03 +0530561 static std::vector<uint8_t> cipherList;
562 static auto listInit = false;
563
564 if (!listInit)
565 {
566 try
567 {
568 cipherList = cipher::getCipherList();
569 listInit = true;
570 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700571 catch (const std::exception& e)
Tom Josepha30c8d32018-03-22 02:15:03 +0530572 {
573 return IPMI_CC_UNSPECIFIED_ERROR;
574 }
575 }
576
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800577 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
578 if (ethdevice.empty())
579 {
580 return IPMI_CC_INVALID_FIELD_REQUEST;
581 }
582 auto channelConf = getChannelConfig(channel);
583
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600584 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500585 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800586 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500587 *data_len = sizeof(buf);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700588 std::memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500589 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600590 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500591 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700592 uint8_t buf[] = {current_revision, 0x04};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500593 *data_len = sizeof(buf);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700594 std::memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500595 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600596 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500597 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700598 uint8_t buf[] = {current_revision, 0x04, 0x04, 0x04, 0x04, 0x04};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500599 *data_len = sizeof(buf);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700600 std::memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500601 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530602 else if ((reqptr->parameter == LAN_PARM_IP) ||
603 (reqptr->parameter == LAN_PARM_SUBNET) ||
604 (reqptr->parameter == LAN_PARM_GATEWAY) ||
605 (reqptr->parameter == LAN_PARM_MAC))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500606 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530607 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500608
tomjose26e17732016-03-03 08:52:51 -0600609 *data_len = sizeof(current_revision);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700610 std::memcpy(buf, &current_revision, *data_len);
tomjose26e17732016-03-03 08:52:51 -0600611
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800612 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600613 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530614 if (reqptr->parameter == LAN_PARM_MAC)
615 {
616 *data_len = sizeof(buf);
617 }
618 else
619 {
620 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
621 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700622 std::memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600623 }
tomjose26e17732016-03-03 08:52:51 -0600624 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600625 {
tomjose26e17732016-03-03 08:52:51 -0600626 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600627 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500628 }
Ratan Gupta533d03b2017-07-30 10:39:22 +0530629 else if (reqptr->parameter == LAN_PARM_VLAN)
630 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530631 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {};
Ratan Gupta533d03b2017-07-30 10:39:22 +0530632
633 *data_len = sizeof(current_revision);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700634 std::memcpy(buf, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800635 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530636 {
637 *data_len = sizeof(buf);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700638 std::memcpy(response, &buf, *data_len);
Ratan Gupta533d03b2017-07-30 10:39:22 +0530639 }
640 }
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530641 else if (reqptr->parameter == LAN_PARM_IPSRC)
642 {
643 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
644 *data_len = sizeof(current_revision);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700645 std::memcpy(buff, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800646 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530647 {
648 *data_len = sizeof(buff);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700649 std::memcpy(response, &buff, *data_len);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530650 }
651 }
Tom Josepha30c8d32018-03-22 02:15:03 +0530652 else if (reqptr->parameter == CIPHER_SUITE_COUNT)
653 {
654 *(static_cast<uint8_t*>(response)) = current_revision;
655 // Byte 1 is reserved byte and does not indicate a cipher suite ID, so
656 // no of cipher suite entry count is one less than the size of the
657 // vector
658 auto count = static_cast<uint8_t>(cipherList.size() - 1);
659 *(static_cast<uint8_t*>(response) + 1) = count;
660 *data_len = sizeof(current_revision) + sizeof(count);
661 }
662 else if (reqptr->parameter == CIPHER_SUITE_ENTRIES)
663 {
664 *(static_cast<uint8_t*>(response)) = current_revision;
665 // Byte 1 is reserved
Patrick Venture0b02be92018-08-31 11:55:55 -0700666 std::copy_n(cipherList.data(), cipherList.size(),
Tom Josepha30c8d32018-03-22 02:15:03 +0530667 static_cast<uint8_t*>(response) + 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700668 *data_len =
669 sizeof(current_revision) + static_cast<uint8_t>(cipherList.size());
Tom Josepha30c8d32018-03-22 02:15:03 +0530670 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500671 else
672 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530673 log<level::ERR>("Unsupported parameter",
674 entry("PARAMETER=0x%x", reqptr->parameter));
vishwa1eaea4f2016-02-26 11:57:40 -0600675 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500676 }
677
678 return rc;
679}
680
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530681void applyChanges(int channel)
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530682{
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530683 std::string ipaddress;
684 std::string gateway;
Patrick Venture0b02be92018-08-31 11:55:55 -0700685 uint8_t prefix{};
686 uint32_t vlanID{};
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530687 std::string networkInterfacePath;
688 ipmi::DbusObjectInfo ipObject;
689 ipmi::DbusObjectInfo systemObject;
690
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530691 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
692 if (ethdevice.empty())
693 {
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530694 log<level::ERR>("Unable to get the interface name",
695 entry("CHANNEL=%d", channel));
696 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530697 }
698 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
699 auto channelConf = getChannelConfig(channel);
700
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530701 try
702 {
703 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
704
705 log<level::INFO>("Network data from Cache",
706 entry("PREFIX=%s", channelConf->netmask.c_str()),
707 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
708 entry("GATEWAY=%s", channelConf->gateway.c_str()),
709 entry("VLAN=%d", channelConf->vlanID),
710 entry("IPSRC=%d", channelConf->ipsrc));
711 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
712 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700713 // get the first twelve bits which is vlan id
714 // not interested in rest of the bits.
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530715 channelConf->vlanID = le32toh(channelConf->vlanID);
716 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
717 }
718
719 // if the asked ip src is DHCP then not interested in
720 // any given data except vlan.
721 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
722 {
723 // always get the system object
Patrick Venture0b02be92018-08-31 11:55:55 -0700724 systemObject =
725 ipmi::getDbusObject(bus, ipmi::network::SYSTEMCONFIG_INTERFACE,
726 ipmi::network::ROOT);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530727
728 // the below code is to determine the mode of the interface
729 // as the handling is same, if the system is configured with
730 // DHCP or user has given all the data.
731 try
732 {
733 ipmi::ObjectTree ancestorMap;
734
Patrick Venture0b02be92018-08-31 11:55:55 -0700735 ipmi::InterfaceList interfaces{
736 ipmi::network::ETHERNET_INTERFACE};
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530737
738 // if the system is having ip object,then
739 // get the IP object.
Patrick Venture0b02be92018-08-31 11:55:55 -0700740 ipObject = ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE,
741 ipmi::network::ROOT, ethIp);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530742
743 // Get the parent interface of the IP object.
744 try
745 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700746 ancestorMap = ipmi::getAllAncestors(bus, ipObject.first,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530747 std::move(interfaces));
748 }
749 catch (InternalFailure& e)
750 {
751 // if unable to get the parent interface
752 // then commit the error and return.
753 log<level::ERR>("Unable to get the parent interface",
754 entry("PATH=%s", ipObject.first.c_str()),
755 entry("INTERFACE=%s",
756 ipmi::network::ETHERNET_INTERFACE));
757 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530758 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530759 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530760 }
761
762 networkInterfacePath = ancestorMap.begin()->first;
763 }
764 catch (InternalFailure& e)
765 {
766 // TODO Currently IPMI supports single interface,need to handle
767 // Multiple interface through
768 // https://github.com/openbmc/openbmc/issues/2138
769
770 // if there is no ip configured on the system,then
771 // get the network interface object.
Patrick Venture0b02be92018-08-31 11:55:55 -0700772 auto networkInterfaceObject =
773 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE,
774 ipmi::network::ROOT, ethdevice);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530775
776 networkInterfacePath = std::move(networkInterfaceObject.first);
777 }
778
779 // get the configured mode on the system.
Patrick Venture0b02be92018-08-31 11:55:55 -0700780 auto enableDHCP =
781 ipmi::getDbusProperty(
782 bus, ipmi::network::SERVICE, networkInterfacePath,
783 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled")
784 .get<bool>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530785
786 // if ip address source is not given then get the ip source mode
787 // from the system so that it can be applied later.
788 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
789 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700790 channelConf->ipsrc = (enableDHCP)
791 ? ipmi::network::IPOrigin::DHCP
792 : ipmi::network::IPOrigin::STATIC;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530793 }
794
795 // check whether user has given all the data
796 // or the configured system interface is dhcp enabled,
797 // in both of the cases get the values from the cache.
798 if ((!channelConf->ipaddr.empty() &&
799 !channelConf->netmask.empty() &&
800 !channelConf->gateway.empty()) ||
801 (enableDHCP)) // configured system interface mode = DHCP
802 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700803 // convert mask into prefix
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530804 ipaddress = channelConf->ipaddr;
805 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
806 gateway = channelConf->gateway;
807 }
808 else // asked ip src = static and configured system src = static
Patrick Venture0b02be92018-08-31 11:55:55 -0700809 // or partially given data.
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530810 {
811 // We have partial filled cache so get the remaining
812 // info from the system.
813
814 // Get the network data from the system as user has
815 // not given all the data then use the data fetched from the
816 // system but it is implementation dependent,IPMI spec doesn't
817 // force it.
818
819 // if system is not having any ip object don't throw error,
820 try
821 {
822 auto properties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700823 bus, ipObject.second, ipObject.first,
824 ipmi::network::IP_INTERFACE);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530825
Patrick Venture0b02be92018-08-31 11:55:55 -0700826 ipaddress = channelConf->ipaddr.empty()
827 ? properties["Address"].get<std::string>()
828 : channelConf->ipaddr;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530829
Patrick Venture0b02be92018-08-31 11:55:55 -0700830 prefix = channelConf->netmask.empty()
831 ? properties["PrefixLength"].get<uint8_t>()
832 : ipmi::network::toPrefix(
833 AF_INET, channelConf->netmask);
834 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530835 catch (InternalFailure& e)
836 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700837 log<level::INFO>(
838 "Failed to get IP object which matches",
839 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
840 entry("MATCH=%s", ethIp.c_str()));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530841 }
842
843 auto systemProperties = ipmi::getAllDbusProperties(
Patrick Venture0b02be92018-08-31 11:55:55 -0700844 bus, systemObject.second, systemObject.first,
845 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530846
Patrick Venture0b02be92018-08-31 11:55:55 -0700847 gateway =
848 channelConf->gateway.empty()
849 ? systemProperties["DefaultGateway"].get<std::string>()
850 : channelConf->gateway;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530851 }
852 }
853
854 // Currently network manager doesn't support purging of all the
855 // ip addresses and the vlan interfaces from the parent interface,
856 // TODO once the support is there, will make the change here.
857 // https://github.com/openbmc/openbmc/issues/2141.
858
859 // TODO Currently IPMI supports single interface,need to handle
860 // Multiple interface through
861 // https://github.com/openbmc/openbmc/issues/2138
862
863 // instead of deleting all the vlan interfaces and
864 // all the ipv4 address,we will call reset method.
Patrick Venture0b02be92018-08-31 11:55:55 -0700865 // delete all the vlan interfaces
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530866
Patrick Venture0b02be92018-08-31 11:55:55 -0700867 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530868 ipmi::network::VLAN_INTERFACE);
869
870 // set the interface mode to static
Patrick Venture0b02be92018-08-31 11:55:55 -0700871 auto networkInterfaceObject =
872 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE,
873 ipmi::network::ROOT, ethdevice);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530874
875 // setting the physical interface mode to static.
Patrick Venture0b02be92018-08-31 11:55:55 -0700876 ipmi::setDbusProperty(
877 bus, ipmi::network::SERVICE, networkInterfaceObject.first,
878 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530879
880 networkInterfacePath = networkInterfaceObject.first;
881
Patrick Venture0b02be92018-08-31 11:55:55 -0700882 // delete all the ipv4 addresses
883 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
884 ipmi::network::IP_INTERFACE, ethIp);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530885
886 if (vlanID)
887 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700888 ipmi::network::createVLAN(bus, ipmi::network::SERVICE,
889 ipmi::network::ROOT, ethdevice, vlanID);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530890
891 auto networkInterfaceObject = ipmi::getDbusObject(
Patrick Venture0b02be92018-08-31 11:55:55 -0700892 bus, ipmi::network::VLAN_INTERFACE, ipmi::network::ROOT);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530893
Patrick Venture0b02be92018-08-31 11:55:55 -0700894 networkInterfacePath = networkInterfaceObject.first;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530895 }
896
897 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
898 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700899 ipmi::setDbusProperty(
900 bus, ipmi::network::SERVICE, networkInterfacePath,
901 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", true);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530902 }
903 else
904 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700905 // change the mode to static
906 ipmi::setDbusProperty(
907 bus, ipmi::network::SERVICE, networkInterfacePath,
908 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530909
910 if (!ipaddress.empty())
911 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700912 ipmi::network::createIP(bus, ipmi::network::SERVICE,
913 networkInterfacePath, ipv4Protocol,
914 ipaddress, prefix);
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530915 }
916
917 if (!gateway.empty())
918 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700919 ipmi::setDbusProperty(bus, systemObject.second,
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530920 systemObject.first,
921 ipmi::network::SYSTEMCONFIG_INTERFACE,
Patrick Venture0b02be92018-08-31 11:55:55 -0700922 "DefaultGateway", std::string(gateway));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530923 }
924 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530925 }
926 catch (InternalFailure& e)
927 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700928 log<level::ERR>(
929 "Failed to set network data", entry("PREFIX=%d", prefix),
930 entry("ADDRESS=%s", ipaddress.c_str()),
931 entry("GATEWAY=%s", gateway.c_str()), entry("VLANID=%d", vlanID),
932 entry("IPSRC=%d", channelConf->ipsrc));
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530933
934 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530935 }
936
937 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530938}
939
940void commitNetworkChanges()
941{
Patrick Venture0b02be92018-08-31 11:55:55 -0700942 for (const auto& channel : channelConfig)
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530943 {
944 if (channel.second->flush)
945 {
946 applyChanges(channel.first);
947 }
948 }
949}
950
951void createNetworkTimer()
952{
953 if (!networkTimer)
954 {
955 std::function<void()> networkTimerCallback(
Patrick Venture0b02be92018-08-31 11:55:55 -0700956 std::bind(&commitNetworkChanges));
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530957
Patrick Venture0b02be92018-08-31 11:55:55 -0700958 networkTimer = std::make_unique<phosphor::ipmi::Timer>(
959 ipmid_get_sd_event_connection(), networkTimerCallback);
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530960 }
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530961}
962
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500963void register_netfn_transport_functions()
964{
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530965 // As this timer is only for transport handler
966 // so creating it here.
967 createNetworkTimer();
Tom05732372016-09-06 17:21:23 +0530968 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700969 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL,
970 ipmi_transport_wildcard, PRIVILEGE_USER);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500971
Tom05732372016-09-06 17:21:23 +0530972 // <Set LAN Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -0700973 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL,
974 ipmi_transport_set_lan, PRIVILEGE_ADMIN);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500975
Tom05732372016-09-06 17:21:23 +0530976 // <Get LAN Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -0700977 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL,
978 ipmi_transport_get_lan, PRIVILEGE_OPERATOR);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500979
980 return;
981}