blob: bbc6ae5c2dea22ff2c19b5d8a9d5c317ae61550e [file] [log] [blame]
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001#include <stdio.h>
2#include <string.h>
3#include <stdint.h>
Hariharasubramanian R83951912016-01-20 07:06:36 -06004#include <arpa/inet.h>
tomjose26e17732016-03-03 08:52:51 -06005#include <string>
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05306#include <experimental/filesystem>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05007
Patrick Williams37af7332016-09-02 21:21:42 -05008#include "host-ipmid/ipmid-api.h"
Patrick Williams53a360e2016-08-12 22:01:02 -05009#include "ipmid.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053010#include "transporthandler.hpp"
11#include "utils.hpp"
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080012#include "net.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053013
14#include <phosphor-logging/log.hpp>
15#include <phosphor-logging/elog-errors.hpp>
16#include "xyz/openbmc_project/Common/error.hpp"
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050017
Hariharasubramanian R83951912016-01-20 07:06:36 -060018#define SYSTEMD_NETWORKD_DBUS 1
19
20#ifdef SYSTEMD_NETWORKD_DBUS
21#include <systemd/sd-bus.h>
Sergey Solomineb9b8142016-08-23 09:07:28 -050022#include <mapper.h>
Hariharasubramanian R83951912016-01-20 07:06:36 -060023#endif
24
Ratan Gupta1247e0b2018-03-07 10:47:25 +053025/** @struct SetChannelAccessRequest
26 *
27 * IPMI payload for Set Channel access command request.
28 */
29struct SetChannelAccessRequest
30{
31 uint8_t channelNumber; //!< Channel number.
32 uint8_t setting; //!< The setting values.
33 uint8_t privilegeLevelLimit; //!< The Privilege Level Limit
34} __attribute__((packed));
35
Adriana Kobylake08fbc62016-02-09 16:17:23 -060036const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
Ratan Gupta1247e0b2018-03-07 10:47:25 +053037constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
Adriana Kobylake08fbc62016-02-09 16:17:23 -060038
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080039std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
Hariharasubramanian R83951912016-01-20 07:06:36 -060040
Ratan Guptab8e99552017-07-27 07:07:48 +053041using namespace phosphor::logging;
42using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053043namespace fs = std::experimental::filesystem;
Hariharasubramanian R83951912016-01-20 07:06:36 -060044
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050045void register_netfn_transport_functions() __attribute__((constructor));
46
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080047struct ChannelConfig_t* getChannelConfig(int channel)
48{
49 auto item = channelConfig.find(channel);
50 if (item == channelConfig.end())
51 {
52 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
53 }
54
55 return channelConfig[channel].get();
56}
57
Ratan Guptab8e99552017-07-27 07:07:48 +053058// Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
Nan Li3d0df912016-10-18 19:51:41 +080059// Cache based on Set-In-Progress State
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080060ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
tomjose26e17732016-03-03 08:52:51 -060061{
tomjose26e17732016-03-03 08:52:51 -060062 ipmi_ret_t rc = IPMI_CC_OK;
Ratan Guptab8e99552017-07-27 07:07:48 +053063 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Ratan Gupta533d03b2017-07-30 10:39:22 +053064
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080065 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
66 // if ethdevice is an empty string they weren't expecting this channel.
67 if (ethdevice.empty())
68 {
69 // TODO: return error from getNetworkData()
70 return IPMI_CC_INVALID_FIELD_REQUEST;
71 }
72 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
73 auto channelConf = getChannelConfig(channel);
74
Ratan Guptab8e99552017-07-27 07:07:48 +053075 try
tomjose26e17732016-03-03 08:52:51 -060076 {
Ratan Guptab8e99552017-07-27 07:07:48 +053077 switch (lan_param)
tomjose26e17732016-03-03 08:52:51 -060078 {
Ratan Guptab8e99552017-07-27 07:07:48 +053079 case LAN_PARM_IP:
80 {
81 std::string ipaddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080082 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +053083 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053084 try
85 {
Ratan Guptadd646202017-11-21 17:46:59 +053086 auto ipObjectInfo = ipmi::getIPObject(
87 bus,
88 ipmi::network::IP_INTERFACE,
89 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080090 ethIP);
Ratan Guptadd646202017-11-21 17:46:59 +053091
92 auto properties = ipmi::getAllDbusProperties(
93 bus,
94 ipObjectInfo.second,
95 ipObjectInfo.first,
96 ipmi::network::IP_INTERFACE);
97
98 ipaddress = properties["Address"].get<std::string>();
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053099 }
100 // ignore the exception, as it is a valid condtion that
101 // system is not confiured with any ip.
102 catch (InternalFailure& e)
103 {
104 // nothing to do.
105 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530106 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800107 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530108 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800109 ipaddress = channelConf->ipaddr;
Ratan Guptab8e99552017-07-27 07:07:48 +0530110 }
111
112 inet_pton(AF_INET, ipaddress.c_str(),
113 reinterpret_cast<void*>(data));
114 }
115 break;
116
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530117 case LAN_PARM_IPSRC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530118 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530119 std::string networkInterfacePath;
120
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800121 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530122 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530123 try
124 {
125 ipmi::ObjectTree ancestorMap;
126 // if the system is having ip object,then
127 // get the IP object.
128 auto ipObject = ipmi::getDbusObject(
129 bus,
130 ipmi::network::IP_INTERFACE,
131 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800132 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(
139 ipmi::network::ETHERNET_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530140
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530141 ancestorMap = ipmi::getAllAncestors(
142 bus,
143 ipObject.first,
144 std::move(interfaces));
145 }
146 catch (InternalFailure& e)
147 {
148 // if unable to get the parent interface
149 // then commit the error and return.
150 log<level::ERR>("Unable to get the parent interface",
151 entry("PATH=%s", ipObject.first.c_str()),
152 entry("INTERFACE=%s",
153 ipmi::network::ETHERNET_INTERFACE));
154 break;
155
156 }
157 // for an ip object there would be single parent
158 // interface.
159 networkInterfacePath = ancestorMap.begin()->first;
160 }
161 catch (InternalFailure& e)
162 {
163 // if there is no ip configured on the system,then
164 // get the network interface object.
165 auto networkInterfaceObject = ipmi::getDbusObject(
166 bus,
167 ipmi::network::ETHERNET_INTERFACE,
168 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800169 ethdevice);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530170
171 networkInterfacePath = networkInterfaceObject.first;
172 }
173
174 auto variant = ipmi::getDbusProperty(
175 bus,
176 ipmi::network::SERVICE,
177 networkInterfacePath,
178 ipmi::network::ETHERNET_INTERFACE,
179 "DHCPEnabled");
180
181 auto dhcpEnabled = variant.get<bool>();
182 // As per IPMI spec 2=>DHCP, 1=STATIC
183 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP :
184 ipmi::network::IPOrigin::STATIC;
185
186 memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
187 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800188 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530189 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800190 memcpy(data, &(channelConf->ipsrc),
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530191 ipmi::network::IPSRC_SIZE_BYTE);
192 }
193 }
194 break;
195
196 case LAN_PARM_SUBNET:
197 {
198 unsigned long mask {};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800199 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530200 {
201 try
202 {
Ratan Guptadd646202017-11-21 17:46:59 +0530203 auto ipObjectInfo = ipmi::getIPObject(
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530204 bus,
205 ipmi::network::IP_INTERFACE,
206 ipmi::network::ROOT,
207 ipmi::network::IP_TYPE);
208
209 auto properties = ipmi::getAllDbusProperties(
210 bus,
211 ipObjectInfo.second,
212 ipObjectInfo.first,
213 ipmi::network::IP_INTERFACE);
214
215 auto prefix = properties["PrefixLength"].get<uint8_t>();
216 mask = ipmi::network::MASK_32_BIT;
217 mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
218 }
219 // ignore the exception, as it is a valid condtion that
220 // system is not confiured with any ip.
221 catch (InternalFailure& e)
222 {
223 // nothing to do
224 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530225 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
226 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800227 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530228 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800229 inet_pton(AF_INET, channelConf->netmask.c_str(),
Ratan Guptab8e99552017-07-27 07:07:48 +0530230 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530231 }
232
233 }
234 break;
235
236 case LAN_PARM_GATEWAY:
237 {
238 std::string gateway;
239
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800240 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530241 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530242 try
243 {
244 auto systemObject = ipmi::getDbusObject(
245 bus,
246 ipmi::network::SYSTEMCONFIG_INTERFACE,
247 ipmi::network::ROOT);
Ratan Guptab8e99552017-07-27 07:07:48 +0530248
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530249 auto systemProperties = ipmi::getAllDbusProperties(
250 bus,
251 systemObject.second,
252 systemObject.first,
253 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530254
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530255 gateway = systemProperties["DefaultGateway"].get<
256 std::string>();
257 }
258 // ignore the exception, as it is a valid condtion that
259 // system is not confiured with any ip.
260 catch (InternalFailure& e)
261 {
262 // nothing to do
263 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530264
265 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800266 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530267 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800268 gateway = channelConf->gateway;
Ratan Guptab8e99552017-07-27 07:07:48 +0530269 }
270
271 inet_pton(AF_INET, gateway.c_str(),
272 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530273 }
274 break;
275
276 case LAN_PARM_MAC:
277 {
278 std::string macAddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800279 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530280 {
281 auto macObjectInfo = ipmi::getDbusObject(
282 bus,
283 ipmi::network::MAC_INTERFACE,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800284 ipmi::network::ROOT,
285 ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530286
287 auto variant = ipmi::getDbusProperty(
288 bus,
289 macObjectInfo.second,
290 macObjectInfo.first,
291 ipmi::network::MAC_INTERFACE,
292 "MACAddress");
293
294 macAddress = variant.get<std::string>();
295
296 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800297 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530298 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800299 macAddress = channelConf->macAddress;
Ratan Guptab8e99552017-07-27 07:07:48 +0530300 }
301
302 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
303 (data),
304 (data + 1),
305 (data + 2),
306 (data + 3),
307 (data + 4),
308 (data + 5));
309 }
310 break;
311
Ratan Gupta533d03b2017-07-30 10:39:22 +0530312 case LAN_PARM_VLAN:
313 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530314 uint16_t vlanID {};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800315 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530316 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530317 try
Ratan Gupta533d03b2017-07-30 10:39:22 +0530318 {
Ratan Guptadd646202017-11-21 17:46:59 +0530319 auto ipObjectInfo = ipmi::getIPObject(
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530320 bus,
321 ipmi::network::IP_INTERFACE,
322 ipmi::network::ROOT,
323 ipmi::network::IP_TYPE);
324
325 vlanID = static_cast<uint16_t>(
326 ipmi::network::getVLAN(ipObjectInfo.first));
327
328 vlanID = htole16(vlanID);
329
330 if (vlanID)
331 {
332 //Enable the 16th bit
333 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
334 }
335 }
336 // ignore the exception, as it is a valid condtion that
337 // system is not confiured with any ip.
338 catch (InternalFailure& e)
339 {
340 // nothing to do
Ratan Gupta533d03b2017-07-30 10:39:22 +0530341 }
342
343 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
344 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800345 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530346 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800347 memcpy(data, &(channelConf->vlanID),
Ratan Gupta533d03b2017-07-30 10:39:22 +0530348 ipmi::network::VLAN_SIZE_BYTE);
349 }
350 }
351 break;
352
Ratan Guptab8e99552017-07-27 07:07:48 +0530353 default:
354 rc = IPMI_CC_PARM_OUT_OF_RANGE;
tomjose26e17732016-03-03 08:52:51 -0600355 }
356 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530357 catch (InternalFailure& e)
tomjose26e17732016-03-03 08:52:51 -0600358 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530359 commit<InternalFailure>();
360 rc = IPMI_CC_UNSPECIFIED_ERROR;
361 return rc;
tomjose26e17732016-03-03 08:52:51 -0600362 }
tomjose26e17732016-03-03 08:52:51 -0600363 return rc;
364}
365
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500366ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
367 ipmi_request_t request, ipmi_response_t response,
368 ipmi_data_len_t data_len, ipmi_context_t context)
369{
370 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
371 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800372 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500373 *data_len = 0;
374 return rc;
375}
376
Ratan Guptab8e99552017-07-27 07:07:48 +0530377struct set_lan_t
378{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500379 uint8_t channel;
380 uint8_t parameter;
381 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
Ratan Guptab8e99552017-07-27 07:07:48 +0530382} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500383
Ratan Guptab8e99552017-07-27 07:07:48 +0530384ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn,
385 ipmi_cmd_t cmd,
386 ipmi_request_t request,
387 ipmi_response_t response,
388 ipmi_data_len_t data_len,
389 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500390{
391 ipmi_ret_t rc = IPMI_CC_OK;
392 *data_len = 0;
Nan Li3d0df912016-10-18 19:51:41 +0800393
Ratan Guptab8e99552017-07-27 07:07:48 +0530394 char ipaddr[INET_ADDRSTRLEN];
395 char netmask[INET_ADDRSTRLEN];
396 char gateway[INET_ADDRSTRLEN];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500397
Ratan Guptab8e99552017-07-27 07:07:48 +0530398 auto reqptr = reinterpret_cast<const set_lan_t*>(request);
399 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500400
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800401 // channel number is the lower nibble
402 int channel = reqptr->channel & CHANNEL_MASK;
403 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
404 if (ethdevice.empty())
405 {
406 return IPMI_CC_INVALID_FIELD_REQUEST;
407 }
408 auto channelConf = getChannelConfig(channel);
409
Ratan Guptab8e99552017-07-27 07:07:48 +0530410 switch (reqptr->parameter)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500411 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530412 case LAN_PARM_IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600413 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530414 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
415 reqptr->data[0], reqptr->data[1],
416 reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500417
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800418 channelConf->ipaddr.assign(ipaddr);
Ratan Guptab8e99552017-07-27 07:07:48 +0530419 }
420 break;
421
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530422 case LAN_PARM_IPSRC:
423 {
424 uint8_t ipsrc{};
425 memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800426 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530427 }
428 break;
429
Ratan Guptab8e99552017-07-27 07:07:48 +0530430 case LAN_PARM_MAC:
431 {
432 char mac[SIZE_MAC];
433
434 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
435 reqptr->data[0],
436 reqptr->data[1],
437 reqptr->data[2],
438 reqptr->data[3],
439 reqptr->data[4],
440 reqptr->data[5]);
441
442 auto macObjectInfo = ipmi::getDbusObject(
443 bus,
444 ipmi::network::MAC_INTERFACE,
445 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800446 ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530447
448 ipmi::setDbusProperty(bus,
449 macObjectInfo.second,
450 macObjectInfo.first,
451 ipmi::network::MAC_INTERFACE,
452 "MACAddress",
453 std::string(mac));
454
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800455 channelConf->macAddress = mac;
Ratan Guptab8e99552017-07-27 07:07:48 +0530456 }
457 break;
458
459 case LAN_PARM_SUBNET:
460 {
461 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
462 reqptr->data[0], reqptr->data[1],
463 reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800464 channelConf->netmask.assign(netmask);
Ratan Guptab8e99552017-07-27 07:07:48 +0530465 }
466 break;
467
468 case LAN_PARM_GATEWAY:
469 {
470 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
471 reqptr->data[0], reqptr->data[1],
472 reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800473 channelConf->gateway.assign(gateway);
Ratan Guptab8e99552017-07-27 07:07:48 +0530474 }
475 break;
476
Ratan Gupta533d03b2017-07-30 10:39:22 +0530477 case LAN_PARM_VLAN:
478 {
479 uint16_t vlan {};
480 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
481 // We are not storing the enable bit
482 // We assume that ipmitool always send enable
483 // bit as 1.
484 vlan = le16toh(vlan);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800485 channelConf->vlanID = vlan;
Ratan Gupta533d03b2017-07-30 10:39:22 +0530486 }
487 break;
488
Ratan Guptab8e99552017-07-27 07:07:48 +0530489 case LAN_PARM_INPROGRESS:
490 {
491 if (reqptr->data[0] == SET_COMPLETE)
492 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800493 channelConf->lan_set_in_progress = SET_COMPLETE;
Ratan Guptab8e99552017-07-27 07:07:48 +0530494
495 log<level::INFO>("Network data from Cache",
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800496 entry("PREFIX=%s", channelConf->netmask.c_str()),
497 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
498 entry("GATEWAY=%s", channelConf->gateway.c_str()),
499 entry("VLAN=%d", channelConf->vlanID));
Ratan Guptab8e99552017-07-27 07:07:48 +0530500
501 log<level::INFO>("Use Set Channel Access command to apply");
Ratan Guptab8e99552017-07-27 07:07:48 +0530502 }
503 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
504 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800505 channelConf->lan_set_in_progress = SET_IN_PROGRESS;
Ratan Guptab8e99552017-07-27 07:07:48 +0530506 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530507 }
508 break;
509
510 default:
511 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530512 rc = IPMI_CC_PARM_NOT_SUPPORTED;
513 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530514 }
vishwa1eaea4f2016-02-26 11:57:40 -0600515
tomjose26e17732016-03-03 08:52:51 -0600516 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500517}
518
Ratan Guptab8e99552017-07-27 07:07:48 +0530519struct get_lan_t
520{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500521 uint8_t rev_channel;
522 uint8_t parameter;
523 uint8_t parameter_set;
524 uint8_t parameter_block;
Ratan Guptab8e99552017-07-27 07:07:48 +0530525} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500526
Ratan Guptab8e99552017-07-27 07:07:48 +0530527ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn,
528 ipmi_cmd_t cmd,
529 ipmi_request_t request,
530 ipmi_response_t response,
531 ipmi_data_len_t data_len,
532 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500533{
534 ipmi_ret_t rc = IPMI_CC_OK;
535 *data_len = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500536 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500537
538 get_lan_t *reqptr = (get_lan_t*) request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800539 // channel number is the lower nibble
540 int channel = reqptr->rev_channel & CHANNEL_MASK;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500541
542 if (reqptr->rev_channel & 0x80) // Revision is bit 7
543 {
544 // Only current revision was requested
545 *data_len = sizeof(current_revision);
546 memcpy(response, &current_revision, *data_len);
547 return IPMI_CC_OK;
548 }
549
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800550 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
551 if (ethdevice.empty())
552 {
553 return IPMI_CC_INVALID_FIELD_REQUEST;
554 }
555 auto channelConf = getChannelConfig(channel);
556
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600557 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500558 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800559 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500560 *data_len = sizeof(buf);
561 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500562 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600563 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500564 {
565 uint8_t buf[] = {current_revision,0x04};
566 *data_len = sizeof(buf);
567 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500568 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600569 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500570 {
571 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
572 *data_len = sizeof(buf);
573 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500574 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530575 else if ((reqptr->parameter == LAN_PARM_IP) ||
576 (reqptr->parameter == LAN_PARM_SUBNET) ||
577 (reqptr->parameter == LAN_PARM_GATEWAY) ||
578 (reqptr->parameter == LAN_PARM_MAC))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500579 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530580 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500581
tomjose26e17732016-03-03 08:52:51 -0600582 *data_len = sizeof(current_revision);
583 memcpy(buf, &current_revision, *data_len);
584
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800585 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600586 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530587 if (reqptr->parameter == LAN_PARM_MAC)
588 {
589 *data_len = sizeof(buf);
590 }
591 else
592 {
593 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
594 }
tomjose26e17732016-03-03 08:52:51 -0600595 memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600596 }
tomjose26e17732016-03-03 08:52:51 -0600597 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600598 {
tomjose26e17732016-03-03 08:52:51 -0600599 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600600 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500601 }
Ratan Gupta533d03b2017-07-30 10:39:22 +0530602 else if (reqptr->parameter == LAN_PARM_VLAN)
603 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530604 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {};
Ratan Gupta533d03b2017-07-30 10:39:22 +0530605
606 *data_len = sizeof(current_revision);
607 memcpy(buf, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800608 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530609 {
610 *data_len = sizeof(buf);
611 memcpy(response, &buf, *data_len);
612 }
613 }
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530614 else if (reqptr->parameter == LAN_PARM_IPSRC)
615 {
616 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
617 *data_len = sizeof(current_revision);
618 memcpy(buff, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800619 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530620 {
621 *data_len = sizeof(buff);
622 memcpy(response, &buff, *data_len);
623 }
624 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500625 else
626 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530627 log<level::ERR>("Unsupported parameter",
628 entry("PARAMETER=0x%x", reqptr->parameter));
vishwa1eaea4f2016-02-26 11:57:40 -0600629 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500630 }
631
632 return rc;
633}
634
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530635ipmi_ret_t ipmi_set_channel_access(ipmi_netfn_t netfn,
636 ipmi_cmd_t cmd,
637 ipmi_request_t request,
638 ipmi_response_t response,
639 ipmi_data_len_t data_len,
640 ipmi_context_t context)
641{
642 ipmi_ret_t rc = IPMI_CC_OK;
643
644 std::string ipaddress;
645 std::string gateway;
646 uint8_t prefix {};
647 uint32_t vlanID {};
648 std::string networkInterfacePath;
649 ipmi::DbusObjectInfo ipObject;
650 ipmi::DbusObjectInfo systemObject;
651
652 if (*data_len < sizeof(SetChannelAccessRequest))
653 {
654 return IPMI_CC_INVALID;
655 }
656
657 auto requestData = reinterpret_cast<const SetChannelAccessRequest*>
658 (request);
659 int channel = requestData->channelNumber & CHANNEL_MASK;
660
661 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
662 if (ethdevice.empty())
663 {
664 return IPMI_CC_INVALID_FIELD_REQUEST;
665 }
666 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
667 auto channelConf = getChannelConfig(channel);
668
669 // Todo: parse the request data if needed.
670 // Using Set Channel cmd to apply changes of Set Lan Cmd.
671 try
672 {
673 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
674
675 log<level::INFO>("Network data from Cache",
676 entry("PREFIX=%s", channelConf->netmask.c_str()),
677 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
678 entry("GATEWAY=%s", channelConf->gateway.c_str()),
679 entry("VLAN=%d", channelConf->vlanID),
680 entry("IPSRC=%d", channelConf->ipsrc));
681 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
682 {
683 //get the first twelve bits which is vlan id
684 //not interested in rest of the bits.
685 channelConf->vlanID = le32toh(channelConf->vlanID);
686 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
687 }
688
689 // if the asked ip src is DHCP then not interested in
690 // any given data except vlan.
691 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
692 {
693 // always get the system object
694 systemObject = ipmi::getDbusObject(
695 bus,
696 ipmi::network::SYSTEMCONFIG_INTERFACE,
697 ipmi::network::ROOT);
698
699 // the below code is to determine the mode of the interface
700 // as the handling is same, if the system is configured with
701 // DHCP or user has given all the data.
702 try
703 {
704 ipmi::ObjectTree ancestorMap;
705
706 ipmi::InterfaceList interfaces {
707 ipmi::network::ETHERNET_INTERFACE };
708
709 // if the system is having ip object,then
710 // get the IP object.
711 ipObject = ipmi::getDbusObject(bus,
712 ipmi::network::IP_INTERFACE,
713 ipmi::network::ROOT,
714 ethIp);
715
716 // Get the parent interface of the IP object.
717 try
718 {
719 ancestorMap = ipmi::getAllAncestors(bus,
720 ipObject.first,
721 std::move(interfaces));
722 }
723 catch (InternalFailure& e)
724 {
725 // if unable to get the parent interface
726 // then commit the error and return.
727 log<level::ERR>("Unable to get the parent interface",
728 entry("PATH=%s", ipObject.first.c_str()),
729 entry("INTERFACE=%s",
730 ipmi::network::ETHERNET_INTERFACE));
731 commit<InternalFailure>();
732 rc = IPMI_CC_UNSPECIFIED_ERROR;
733 channelConf->clear();
734 return rc;
735 }
736
737 networkInterfacePath = ancestorMap.begin()->first;
738 }
739 catch (InternalFailure& e)
740 {
741 // TODO Currently IPMI supports single interface,need to handle
742 // Multiple interface through
743 // https://github.com/openbmc/openbmc/issues/2138
744
745 // if there is no ip configured on the system,then
746 // get the network interface object.
747 auto networkInterfaceObject = ipmi::getDbusObject(
748 bus,
749 ipmi::network::ETHERNET_INTERFACE,
750 ipmi::network::ROOT,
751 ethdevice);
752
753 networkInterfacePath = std::move(networkInterfaceObject.first);
754 }
755
756 // get the configured mode on the system.
757 auto enableDHCP = ipmi::getDbusProperty(
758 bus,
759 ipmi::network::SERVICE,
760 networkInterfacePath,
761 ipmi::network::ETHERNET_INTERFACE,
762 "DHCPEnabled").get<bool>();
763
764 // if ip address source is not given then get the ip source mode
765 // from the system so that it can be applied later.
766 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
767 {
768 channelConf->ipsrc = (enableDHCP) ?
769 ipmi::network::IPOrigin::DHCP :
770 ipmi::network::IPOrigin::STATIC;
771 }
772
773 // check whether user has given all the data
774 // or the configured system interface is dhcp enabled,
775 // in both of the cases get the values from the cache.
776 if ((!channelConf->ipaddr.empty() &&
777 !channelConf->netmask.empty() &&
778 !channelConf->gateway.empty()) ||
779 (enableDHCP)) // configured system interface mode = DHCP
780 {
781 //convert mask into prefix
782 ipaddress = channelConf->ipaddr;
783 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
784 gateway = channelConf->gateway;
785 }
786 else // asked ip src = static and configured system src = static
787 // or partially given data.
788 {
789 // We have partial filled cache so get the remaining
790 // info from the system.
791
792 // Get the network data from the system as user has
793 // not given all the data then use the data fetched from the
794 // system but it is implementation dependent,IPMI spec doesn't
795 // force it.
796
797 // if system is not having any ip object don't throw error,
798 try
799 {
800 auto properties = ipmi::getAllDbusProperties(
801 bus,
802 ipObject.second,
803 ipObject.first,
804 ipmi::network::IP_INTERFACE);
805
806 ipaddress = channelConf->ipaddr.empty() ?
807 properties["Address"].get<std::string>() :
808 channelConf->ipaddr;
809
810 prefix = channelConf->netmask.empty() ?
811 properties["PrefixLength"].get<uint8_t>() :
812 ipmi::network::toPrefix(AF_INET,
813 channelConf->netmask);
814 }
815 catch (InternalFailure& e)
816 {
817 log<level::INFO>("Failed to get IP object which matches",
818 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
819 entry("MATCH=%s", ethIp));
820 }
821
822 auto systemProperties = ipmi::getAllDbusProperties(
823 bus,
824 systemObject.second,
825 systemObject.first,
826 ipmi::network::SYSTEMCONFIG_INTERFACE);
827
828 gateway = channelConf->gateway.empty() ?
829 systemProperties["DefaultGateway"].get<std::string>() :
830 channelConf->gateway;
831 }
832 }
833
834 // Currently network manager doesn't support purging of all the
835 // ip addresses and the vlan interfaces from the parent interface,
836 // TODO once the support is there, will make the change here.
837 // https://github.com/openbmc/openbmc/issues/2141.
838
839 // TODO Currently IPMI supports single interface,need to handle
840 // Multiple interface through
841 // https://github.com/openbmc/openbmc/issues/2138
842
843 // instead of deleting all the vlan interfaces and
844 // all the ipv4 address,we will call reset method.
845 //delete all the vlan interfaces
846
847 ipmi::deleteAllDbusObjects(bus,
848 ipmi::network::ROOT,
849 ipmi::network::VLAN_INTERFACE);
850
851 // set the interface mode to static
852 auto networkInterfaceObject = ipmi::getDbusObject(
853 bus,
854 ipmi::network::ETHERNET_INTERFACE,
855 ipmi::network::ROOT,
856 ethdevice);
857
858 // setting the physical interface mode to static.
859 ipmi::setDbusProperty(bus,
860 ipmi::network::SERVICE,
861 networkInterfaceObject.first,
862 ipmi::network::ETHERNET_INTERFACE,
863 "DHCPEnabled",
864 false);
865
866 networkInterfacePath = networkInterfaceObject.first;
867
868 //delete all the ipv4 addresses
869 ipmi::deleteAllDbusObjects(bus,
870 ipmi::network::ROOT,
871 ipmi::network::IP_INTERFACE,
872 ethIp);
873
874 if (vlanID)
875 {
876 ipmi::network::createVLAN(bus,
877 ipmi::network::SERVICE,
878 ipmi::network::ROOT,
879 ethdevice,
880 vlanID);
881
882 auto networkInterfaceObject = ipmi::getDbusObject(
883 bus,
884 ipmi::network::VLAN_INTERFACE,
885 ipmi::network::ROOT);
886
887 networkInterfacePath = networkInterfaceObject.first;
888 }
889
890 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
891 {
892 ipmi::setDbusProperty(bus,
893 ipmi::network::SERVICE,
894 networkInterfacePath,
895 ipmi::network::ETHERNET_INTERFACE,
896 "DHCPEnabled",
897 true);
898 }
899 else
900 {
901 //change the mode to static
902 ipmi::setDbusProperty(bus,
903 ipmi::network::SERVICE,
904 networkInterfacePath,
905 ipmi::network::ETHERNET_INTERFACE,
906 "DHCPEnabled",
907 false);
908
909 if (!ipaddress.empty())
910 {
911 ipmi::network::createIP(bus,
912 ipmi::network::SERVICE,
913 networkInterfacePath,
914 ipv4Protocol,
915 ipaddress,
916 prefix);
917 }
918
919 if (!gateway.empty())
920 {
921 ipmi::setDbusProperty(bus,
922 systemObject.second,
923 systemObject.first,
924 ipmi::network::SYSTEMCONFIG_INTERFACE,
925 "DefaultGateway",
926 std::string(gateway));
927 }
928 }
929
930 }
931 catch (InternalFailure& e)
932 {
933 log<level::ERR>("Failed to set network data",
934 entry("PREFIX=%d", prefix),
935 entry("ADDRESS=%s", ipaddress.c_str()),
936 entry("GATEWAY=%s", gateway.c_str()),
937 entry("VLANID=%d", vlanID),
938 entry("IPSRC=%d", channelConf->ipsrc));
939
940 commit<InternalFailure>();
941 rc = IPMI_CC_UNSPECIFIED_ERROR;
942 }
943
944 channelConf->clear();
945 return rc;
946}
947
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500948void register_netfn_transport_functions()
949{
Tom05732372016-09-06 17:21:23 +0530950 // <Wildcard Command>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500951 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530952 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard,
953 PRIVILEGE_USER);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500954
Tom05732372016-09-06 17:21:23 +0530955 // <Set LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500956 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
Tom05732372016-09-06 17:21:23 +0530957 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan,
958 PRIVILEGE_ADMIN);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500959
Tom05732372016-09-06 17:21:23 +0530960 // <Get LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500961 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
Tom05732372016-09-06 17:21:23 +0530962 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan,
963 PRIVILEGE_OPERATOR);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500964
965 return;
966}