blob: 8bf0d4370ebaf3ccf4c4975a6e44fd2b9a98bfaf [file] [log] [blame]
Ratan Gupta7a7f0122018-03-07 12:31:05 +05301#include <chrono>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05002#include <stdio.h>
3#include <string.h>
4#include <stdint.h>
Hariharasubramanian R83951912016-01-20 07:06:36 -06005#include <arpa/inet.h>
tomjose26e17732016-03-03 08:52:51 -06006#include <string>
Ratan Guptacc6cdbf2017-09-01 23:06:25 +05307#include <experimental/filesystem>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05008
Patrick Williams37af7332016-09-02 21:21:42 -05009#include "host-ipmid/ipmid-api.h"
Patrick Williams53a360e2016-08-12 22:01:02 -050010#include "ipmid.hpp"
Ratan Gupta7a7f0122018-03-07 12:31:05 +053011#include "timer.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053012#include "transporthandler.hpp"
13#include "utils.hpp"
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080014#include "net.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053015
16#include <phosphor-logging/log.hpp>
17#include <phosphor-logging/elog-errors.hpp>
18#include "xyz/openbmc_project/Common/error.hpp"
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050019
Hariharasubramanian R83951912016-01-20 07:06:36 -060020#define SYSTEMD_NETWORKD_DBUS 1
21
22#ifdef SYSTEMD_NETWORKD_DBUS
23#include <systemd/sd-bus.h>
Sergey Solomineb9b8142016-08-23 09:07:28 -050024#include <mapper.h>
Hariharasubramanian R83951912016-01-20 07:06:36 -060025#endif
26
Ratan Gupta7a7f0122018-03-07 12:31:05 +053027extern std::unique_ptr<phosphor::ipmi::Timer> networkTimer;
Ratan Gupta1247e0b2018-03-07 10:47:25 +053028
Adriana Kobylake08fbc62016-02-09 16:17:23 -060029const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
Ratan Gupta1247e0b2018-03-07 10:47:25 +053030constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
Adriana Kobylake08fbc62016-02-09 16:17:23 -060031
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080032std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
Hariharasubramanian R83951912016-01-20 07:06:36 -060033
Ratan Guptab8e99552017-07-27 07:07:48 +053034using namespace phosphor::logging;
35using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta7a7f0122018-03-07 12:31:05 +053036
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053037namespace fs = std::experimental::filesystem;
Hariharasubramanian R83951912016-01-20 07:06:36 -060038
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050039void register_netfn_transport_functions() __attribute__((constructor));
40
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080041struct ChannelConfig_t* getChannelConfig(int channel)
42{
43 auto item = channelConfig.find(channel);
44 if (item == channelConfig.end())
45 {
46 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
47 }
48
49 return channelConfig[channel].get();
50}
51
Ratan Guptab8e99552017-07-27 07:07:48 +053052// Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
Nan Li3d0df912016-10-18 19:51:41 +080053// Cache based on Set-In-Progress State
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080054ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
tomjose26e17732016-03-03 08:52:51 -060055{
tomjose26e17732016-03-03 08:52:51 -060056 ipmi_ret_t rc = IPMI_CC_OK;
Ratan Guptab8e99552017-07-27 07:07:48 +053057 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Ratan Gupta533d03b2017-07-30 10:39:22 +053058
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080059 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
60 // if ethdevice is an empty string they weren't expecting this channel.
61 if (ethdevice.empty())
62 {
63 // TODO: return error from getNetworkData()
64 return IPMI_CC_INVALID_FIELD_REQUEST;
65 }
66 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
67 auto channelConf = getChannelConfig(channel);
68
Ratan Guptab8e99552017-07-27 07:07:48 +053069 try
tomjose26e17732016-03-03 08:52:51 -060070 {
Ratan Guptab8e99552017-07-27 07:07:48 +053071 switch (lan_param)
tomjose26e17732016-03-03 08:52:51 -060072 {
Ratan Guptab8e99552017-07-27 07:07:48 +053073 case LAN_PARM_IP:
74 {
75 std::string ipaddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080076 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +053077 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053078 try
79 {
Ratan Guptadd646202017-11-21 17:46:59 +053080 auto ipObjectInfo = ipmi::getIPObject(
81 bus,
82 ipmi::network::IP_INTERFACE,
83 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080084 ethIP);
Ratan Guptadd646202017-11-21 17:46:59 +053085
86 auto properties = ipmi::getAllDbusProperties(
87 bus,
88 ipObjectInfo.second,
89 ipObjectInfo.first,
90 ipmi::network::IP_INTERFACE);
91
92 ipaddress = properties["Address"].get<std::string>();
Ratan Guptacc6cdbf2017-09-01 23:06:25 +053093 }
94 // ignore the exception, as it is a valid condtion that
95 // system is not confiured with any ip.
96 catch (InternalFailure& e)
97 {
98 // nothing to do.
99 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530100 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800101 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530102 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800103 ipaddress = channelConf->ipaddr;
Ratan Guptab8e99552017-07-27 07:07:48 +0530104 }
105
106 inet_pton(AF_INET, ipaddress.c_str(),
107 reinterpret_cast<void*>(data));
108 }
109 break;
110
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530111 case LAN_PARM_IPSRC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530112 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530113 std::string networkInterfacePath;
114
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800115 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530116 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530117 try
118 {
119 ipmi::ObjectTree ancestorMap;
120 // if the system is having ip object,then
121 // get the IP object.
122 auto ipObject = ipmi::getDbusObject(
123 bus,
124 ipmi::network::IP_INTERFACE,
125 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800126 ethIP);
Ratan Guptab8e99552017-07-27 07:07:48 +0530127
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530128 // Get the parent interface of the IP object.
129 try
130 {
131 ipmi::InterfaceList interfaces;
132 interfaces.emplace_back(
133 ipmi::network::ETHERNET_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530134
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530135 ancestorMap = ipmi::getAllAncestors(
136 bus,
137 ipObject.first,
138 std::move(interfaces));
139 }
140 catch (InternalFailure& e)
141 {
142 // if unable to get the parent interface
143 // then commit the error and return.
144 log<level::ERR>("Unable to get the parent interface",
145 entry("PATH=%s", ipObject.first.c_str()),
146 entry("INTERFACE=%s",
147 ipmi::network::ETHERNET_INTERFACE));
148 break;
149
150 }
151 // for an ip object there would be single parent
152 // interface.
153 networkInterfacePath = ancestorMap.begin()->first;
154 }
155 catch (InternalFailure& e)
156 {
157 // if there is no ip configured on the system,then
158 // get the network interface object.
159 auto networkInterfaceObject = ipmi::getDbusObject(
160 bus,
161 ipmi::network::ETHERNET_INTERFACE,
162 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800163 ethdevice);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530164
165 networkInterfacePath = networkInterfaceObject.first;
166 }
167
168 auto variant = ipmi::getDbusProperty(
169 bus,
170 ipmi::network::SERVICE,
171 networkInterfacePath,
172 ipmi::network::ETHERNET_INTERFACE,
173 "DHCPEnabled");
174
175 auto dhcpEnabled = variant.get<bool>();
176 // As per IPMI spec 2=>DHCP, 1=STATIC
177 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP :
178 ipmi::network::IPOrigin::STATIC;
179
180 memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
181 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800182 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530183 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800184 memcpy(data, &(channelConf->ipsrc),
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530185 ipmi::network::IPSRC_SIZE_BYTE);
186 }
187 }
188 break;
189
190 case LAN_PARM_SUBNET:
191 {
192 unsigned long mask {};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800193 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530194 {
195 try
196 {
Ratan Guptadd646202017-11-21 17:46:59 +0530197 auto ipObjectInfo = ipmi::getIPObject(
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530198 bus,
199 ipmi::network::IP_INTERFACE,
200 ipmi::network::ROOT,
201 ipmi::network::IP_TYPE);
202
203 auto properties = ipmi::getAllDbusProperties(
204 bus,
205 ipObjectInfo.second,
206 ipObjectInfo.first,
207 ipmi::network::IP_INTERFACE);
208
209 auto prefix = properties["PrefixLength"].get<uint8_t>();
210 mask = ipmi::network::MASK_32_BIT;
211 mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
212 }
213 // ignore the exception, as it is a valid condtion that
214 // system is not confiured with any ip.
215 catch (InternalFailure& e)
216 {
217 // nothing to do
218 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530219 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
220 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800221 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530222 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800223 inet_pton(AF_INET, channelConf->netmask.c_str(),
Ratan Guptab8e99552017-07-27 07:07:48 +0530224 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530225 }
226
227 }
228 break;
229
230 case LAN_PARM_GATEWAY:
231 {
232 std::string gateway;
233
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800234 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530235 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530236 try
237 {
238 auto systemObject = ipmi::getDbusObject(
239 bus,
240 ipmi::network::SYSTEMCONFIG_INTERFACE,
241 ipmi::network::ROOT);
Ratan Guptab8e99552017-07-27 07:07:48 +0530242
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530243 auto systemProperties = ipmi::getAllDbusProperties(
244 bus,
245 systemObject.second,
246 systemObject.first,
247 ipmi::network::SYSTEMCONFIG_INTERFACE);
Ratan Guptab8e99552017-07-27 07:07:48 +0530248
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530249 gateway = systemProperties["DefaultGateway"].get<
250 std::string>();
251 }
252 // ignore the exception, as it is a valid condtion that
253 // system is not confiured with any ip.
254 catch (InternalFailure& e)
255 {
256 // nothing to do
257 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530258
259 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800260 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530261 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800262 gateway = channelConf->gateway;
Ratan Guptab8e99552017-07-27 07:07:48 +0530263 }
264
265 inet_pton(AF_INET, gateway.c_str(),
266 reinterpret_cast<void*>(data));
Ratan Guptab8e99552017-07-27 07:07:48 +0530267 }
268 break;
269
270 case LAN_PARM_MAC:
271 {
272 std::string macAddress;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800273 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Guptab8e99552017-07-27 07:07:48 +0530274 {
275 auto macObjectInfo = ipmi::getDbusObject(
276 bus,
277 ipmi::network::MAC_INTERFACE,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800278 ipmi::network::ROOT,
279 ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530280
281 auto variant = ipmi::getDbusProperty(
282 bus,
283 macObjectInfo.second,
284 macObjectInfo.first,
285 ipmi::network::MAC_INTERFACE,
286 "MACAddress");
287
288 macAddress = variant.get<std::string>();
289
290 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800291 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Guptab8e99552017-07-27 07:07:48 +0530292 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800293 macAddress = channelConf->macAddress;
Ratan Guptab8e99552017-07-27 07:07:48 +0530294 }
295
296 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
297 (data),
298 (data + 1),
299 (data + 2),
300 (data + 3),
301 (data + 4),
302 (data + 5));
303 }
304 break;
305
Ratan Gupta533d03b2017-07-30 10:39:22 +0530306 case LAN_PARM_VLAN:
307 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530308 uint16_t vlanID {};
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800309 if (channelConf->lan_set_in_progress == SET_COMPLETE)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530310 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530311 try
Ratan Gupta533d03b2017-07-30 10:39:22 +0530312 {
Ratan Guptadd646202017-11-21 17:46:59 +0530313 auto ipObjectInfo = ipmi::getIPObject(
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530314 bus,
315 ipmi::network::IP_INTERFACE,
316 ipmi::network::ROOT,
317 ipmi::network::IP_TYPE);
318
319 vlanID = static_cast<uint16_t>(
320 ipmi::network::getVLAN(ipObjectInfo.first));
321
322 vlanID = htole16(vlanID);
323
324 if (vlanID)
325 {
326 //Enable the 16th bit
327 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
328 }
329 }
330 // ignore the exception, as it is a valid condtion that
331 // system is not confiured with any ip.
332 catch (InternalFailure& e)
333 {
334 // nothing to do
Ratan Gupta533d03b2017-07-30 10:39:22 +0530335 }
336
337 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
338 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800339 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530340 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800341 memcpy(data, &(channelConf->vlanID),
Ratan Gupta533d03b2017-07-30 10:39:22 +0530342 ipmi::network::VLAN_SIZE_BYTE);
343 }
344 }
345 break;
346
Ratan Guptab8e99552017-07-27 07:07:48 +0530347 default:
348 rc = IPMI_CC_PARM_OUT_OF_RANGE;
tomjose26e17732016-03-03 08:52:51 -0600349 }
350 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530351 catch (InternalFailure& e)
tomjose26e17732016-03-03 08:52:51 -0600352 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530353 commit<InternalFailure>();
354 rc = IPMI_CC_UNSPECIFIED_ERROR;
355 return rc;
tomjose26e17732016-03-03 08:52:51 -0600356 }
tomjose26e17732016-03-03 08:52:51 -0600357 return rc;
358}
359
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500360ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
361 ipmi_request_t request, ipmi_response_t response,
362 ipmi_data_len_t data_len, ipmi_context_t context)
363{
364 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
365 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800366 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500367 *data_len = 0;
368 return rc;
369}
370
Ratan Guptab8e99552017-07-27 07:07:48 +0530371struct set_lan_t
372{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500373 uint8_t channel;
374 uint8_t parameter;
375 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
Ratan Guptab8e99552017-07-27 07:07:48 +0530376} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500377
Ratan Guptab8e99552017-07-27 07:07:48 +0530378ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn,
379 ipmi_cmd_t cmd,
380 ipmi_request_t request,
381 ipmi_response_t response,
382 ipmi_data_len_t data_len,
383 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500384{
385 ipmi_ret_t rc = IPMI_CC_OK;
386 *data_len = 0;
Nan Li3d0df912016-10-18 19:51:41 +0800387
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530388 using namespace std::chrono_literals;
389
390 // time to wait before applying the network changes.
391 constexpr auto networkTimeout = 10000000us; // 10 sec
392
Ratan Guptab8e99552017-07-27 07:07:48 +0530393 char ipaddr[INET_ADDRSTRLEN];
394 char netmask[INET_ADDRSTRLEN];
395 char gateway[INET_ADDRSTRLEN];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500396
Ratan Guptab8e99552017-07-27 07:07:48 +0530397 auto reqptr = reinterpret_cast<const set_lan_t*>(request);
398 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500399
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800400 // channel number is the lower nibble
401 int channel = reqptr->channel & CHANNEL_MASK;
402 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
403 if (ethdevice.empty())
404 {
405 return IPMI_CC_INVALID_FIELD_REQUEST;
406 }
407 auto channelConf = getChannelConfig(channel);
408
Ratan Guptab8e99552017-07-27 07:07:48 +0530409 switch (reqptr->parameter)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500410 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530411 case LAN_PARM_IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600412 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530413 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
414 reqptr->data[0], reqptr->data[1],
415 reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500416
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800417 channelConf->ipaddr.assign(ipaddr);
Ratan Guptab8e99552017-07-27 07:07:48 +0530418 }
419 break;
420
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530421 case LAN_PARM_IPSRC:
422 {
423 uint8_t ipsrc{};
424 memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800425 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530426 }
427 break;
428
Ratan Guptab8e99552017-07-27 07:07:48 +0530429 case LAN_PARM_MAC:
430 {
431 char mac[SIZE_MAC];
432
433 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
434 reqptr->data[0],
435 reqptr->data[1],
436 reqptr->data[2],
437 reqptr->data[3],
438 reqptr->data[4],
439 reqptr->data[5]);
440
441 auto macObjectInfo = ipmi::getDbusObject(
442 bus,
443 ipmi::network::MAC_INTERFACE,
444 ipmi::network::ROOT,
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800445 ethdevice);
Ratan Guptab8e99552017-07-27 07:07:48 +0530446
447 ipmi::setDbusProperty(bus,
448 macObjectInfo.second,
449 macObjectInfo.first,
450 ipmi::network::MAC_INTERFACE,
451 "MACAddress",
452 std::string(mac));
453
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800454 channelConf->macAddress = mac;
Ratan Guptab8e99552017-07-27 07:07:48 +0530455 }
456 break;
457
458 case LAN_PARM_SUBNET:
459 {
460 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
461 reqptr->data[0], reqptr->data[1],
462 reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800463 channelConf->netmask.assign(netmask);
Ratan Guptab8e99552017-07-27 07:07:48 +0530464 }
465 break;
466
467 case LAN_PARM_GATEWAY:
468 {
469 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
470 reqptr->data[0], reqptr->data[1],
471 reqptr->data[2], reqptr->data[3]);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800472 channelConf->gateway.assign(gateway);
Ratan Guptab8e99552017-07-27 07:07:48 +0530473 }
474 break;
475
Ratan Gupta533d03b2017-07-30 10:39:22 +0530476 case LAN_PARM_VLAN:
477 {
478 uint16_t vlan {};
479 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
480 // We are not storing the enable bit
481 // We assume that ipmitool always send enable
482 // bit as 1.
483 vlan = le16toh(vlan);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800484 channelConf->vlanID = vlan;
Ratan Gupta533d03b2017-07-30 10:39:22 +0530485 }
486 break;
487
Ratan Guptab8e99552017-07-27 07:07:48 +0530488 case LAN_PARM_INPROGRESS:
489 {
490 if (reqptr->data[0] == SET_COMPLETE)
491 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800492 channelConf->lan_set_in_progress = SET_COMPLETE;
Ratan Guptab8e99552017-07-27 07:07:48 +0530493
494 log<level::INFO>("Network data from Cache",
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800495 entry("PREFIX=%s", channelConf->netmask.c_str()),
496 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
497 entry("GATEWAY=%s", channelConf->gateway.c_str()),
498 entry("VLAN=%d", channelConf->vlanID));
Ratan Guptab8e99552017-07-27 07:07:48 +0530499
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530500 if (!networkTimer)
501 {
502 log<level::ERR>("Network timer is not instantiated");
503 return IPMI_CC_UNSPECIFIED_ERROR;
504 }
505
506 // start/restart the timer
507 networkTimer->startTimer(networkTimeout);
Ratan Guptab8e99552017-07-27 07:07:48 +0530508 }
509 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
510 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800511 channelConf->lan_set_in_progress = SET_IN_PROGRESS;
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530512 channelConf->flush = true;
Ratan Guptab8e99552017-07-27 07:07:48 +0530513 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530514 }
515 break;
516
517 default:
518 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530519 rc = IPMI_CC_PARM_NOT_SUPPORTED;
520 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530521 }
vishwa1eaea4f2016-02-26 11:57:40 -0600522
tomjose26e17732016-03-03 08:52:51 -0600523 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500524}
525
Ratan Guptab8e99552017-07-27 07:07:48 +0530526struct get_lan_t
527{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500528 uint8_t rev_channel;
529 uint8_t parameter;
530 uint8_t parameter_set;
531 uint8_t parameter_block;
Ratan Guptab8e99552017-07-27 07:07:48 +0530532} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500533
Ratan Guptab8e99552017-07-27 07:07:48 +0530534ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn,
535 ipmi_cmd_t cmd,
536 ipmi_request_t request,
537 ipmi_response_t response,
538 ipmi_data_len_t data_len,
539 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500540{
541 ipmi_ret_t rc = IPMI_CC_OK;
542 *data_len = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500543 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500544
545 get_lan_t *reqptr = (get_lan_t*) request;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800546 // channel number is the lower nibble
547 int channel = reqptr->rev_channel & CHANNEL_MASK;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500548
549 if (reqptr->rev_channel & 0x80) // Revision is bit 7
550 {
551 // Only current revision was requested
552 *data_len = sizeof(current_revision);
553 memcpy(response, &current_revision, *data_len);
554 return IPMI_CC_OK;
555 }
556
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800557 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
558 if (ethdevice.empty())
559 {
560 return IPMI_CC_INVALID_FIELD_REQUEST;
561 }
562 auto channelConf = getChannelConfig(channel);
563
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600564 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500565 {
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800566 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500567 *data_len = sizeof(buf);
568 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500569 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600570 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500571 {
572 uint8_t buf[] = {current_revision,0x04};
573 *data_len = sizeof(buf);
574 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500575 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600576 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500577 {
578 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
579 *data_len = sizeof(buf);
580 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500581 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530582 else if ((reqptr->parameter == LAN_PARM_IP) ||
583 (reqptr->parameter == LAN_PARM_SUBNET) ||
584 (reqptr->parameter == LAN_PARM_GATEWAY) ||
585 (reqptr->parameter == LAN_PARM_MAC))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500586 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530587 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500588
tomjose26e17732016-03-03 08:52:51 -0600589 *data_len = sizeof(current_revision);
590 memcpy(buf, &current_revision, *data_len);
591
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800592 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600593 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530594 if (reqptr->parameter == LAN_PARM_MAC)
595 {
596 *data_len = sizeof(buf);
597 }
598 else
599 {
600 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
601 }
tomjose26e17732016-03-03 08:52:51 -0600602 memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600603 }
tomjose26e17732016-03-03 08:52:51 -0600604 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600605 {
tomjose26e17732016-03-03 08:52:51 -0600606 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600607 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500608 }
Ratan Gupta533d03b2017-07-30 10:39:22 +0530609 else if (reqptr->parameter == LAN_PARM_VLAN)
610 {
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530611 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {};
Ratan Gupta533d03b2017-07-30 10:39:22 +0530612
613 *data_len = sizeof(current_revision);
614 memcpy(buf, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800615 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
Ratan Gupta533d03b2017-07-30 10:39:22 +0530616 {
617 *data_len = sizeof(buf);
618 memcpy(response, &buf, *data_len);
619 }
620 }
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530621 else if (reqptr->parameter == LAN_PARM_IPSRC)
622 {
623 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
624 *data_len = sizeof(current_revision);
625 memcpy(buff, &current_revision, *data_len);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800626 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530627 {
628 *data_len = sizeof(buff);
629 memcpy(response, &buff, *data_len);
630 }
631 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500632 else
633 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530634 log<level::ERR>("Unsupported parameter",
635 entry("PARAMETER=0x%x", reqptr->parameter));
vishwa1eaea4f2016-02-26 11:57:40 -0600636 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500637 }
638
639 return rc;
640}
641
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530642void applyChanges(int channel)
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530643{
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530644 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
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530652 auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
653 if (ethdevice.empty())
654 {
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530655 log<level::ERR>("Unable to get the interface name",
656 entry("CHANNEL=%d", channel));
657 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530658 }
659 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
660 auto channelConf = getChannelConfig(channel);
661
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530662 try
663 {
664 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
665
666 log<level::INFO>("Network data from Cache",
667 entry("PREFIX=%s", channelConf->netmask.c_str()),
668 entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
669 entry("GATEWAY=%s", channelConf->gateway.c_str()),
670 entry("VLAN=%d", channelConf->vlanID),
671 entry("IPSRC=%d", channelConf->ipsrc));
672 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
673 {
674 //get the first twelve bits which is vlan id
675 //not interested in rest of the bits.
676 channelConf->vlanID = le32toh(channelConf->vlanID);
677 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
678 }
679
680 // if the asked ip src is DHCP then not interested in
681 // any given data except vlan.
682 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
683 {
684 // always get the system object
685 systemObject = ipmi::getDbusObject(
686 bus,
687 ipmi::network::SYSTEMCONFIG_INTERFACE,
688 ipmi::network::ROOT);
689
690 // the below code is to determine the mode of the interface
691 // as the handling is same, if the system is configured with
692 // DHCP or user has given all the data.
693 try
694 {
695 ipmi::ObjectTree ancestorMap;
696
697 ipmi::InterfaceList interfaces {
698 ipmi::network::ETHERNET_INTERFACE };
699
700 // if the system is having ip object,then
701 // get the IP object.
702 ipObject = ipmi::getDbusObject(bus,
703 ipmi::network::IP_INTERFACE,
704 ipmi::network::ROOT,
705 ethIp);
706
707 // Get the parent interface of the IP object.
708 try
709 {
710 ancestorMap = ipmi::getAllAncestors(bus,
711 ipObject.first,
712 std::move(interfaces));
713 }
714 catch (InternalFailure& e)
715 {
716 // if unable to get the parent interface
717 // then commit the error and return.
718 log<level::ERR>("Unable to get the parent interface",
719 entry("PATH=%s", ipObject.first.c_str()),
720 entry("INTERFACE=%s",
721 ipmi::network::ETHERNET_INTERFACE));
722 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530723 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530724 return;
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530725 }
726
727 networkInterfacePath = ancestorMap.begin()->first;
728 }
729 catch (InternalFailure& e)
730 {
731 // TODO Currently IPMI supports single interface,need to handle
732 // Multiple interface through
733 // https://github.com/openbmc/openbmc/issues/2138
734
735 // if there is no ip configured on the system,then
736 // get the network interface object.
737 auto networkInterfaceObject = ipmi::getDbusObject(
738 bus,
739 ipmi::network::ETHERNET_INTERFACE,
740 ipmi::network::ROOT,
741 ethdevice);
742
743 networkInterfacePath = std::move(networkInterfaceObject.first);
744 }
745
746 // get the configured mode on the system.
747 auto enableDHCP = ipmi::getDbusProperty(
748 bus,
749 ipmi::network::SERVICE,
750 networkInterfacePath,
751 ipmi::network::ETHERNET_INTERFACE,
752 "DHCPEnabled").get<bool>();
753
754 // if ip address source is not given then get the ip source mode
755 // from the system so that it can be applied later.
756 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
757 {
758 channelConf->ipsrc = (enableDHCP) ?
759 ipmi::network::IPOrigin::DHCP :
760 ipmi::network::IPOrigin::STATIC;
761 }
762
763 // check whether user has given all the data
764 // or the configured system interface is dhcp enabled,
765 // in both of the cases get the values from the cache.
766 if ((!channelConf->ipaddr.empty() &&
767 !channelConf->netmask.empty() &&
768 !channelConf->gateway.empty()) ||
769 (enableDHCP)) // configured system interface mode = DHCP
770 {
771 //convert mask into prefix
772 ipaddress = channelConf->ipaddr;
773 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
774 gateway = channelConf->gateway;
775 }
776 else // asked ip src = static and configured system src = static
777 // or partially given data.
778 {
779 // We have partial filled cache so get the remaining
780 // info from the system.
781
782 // Get the network data from the system as user has
783 // not given all the data then use the data fetched from the
784 // system but it is implementation dependent,IPMI spec doesn't
785 // force it.
786
787 // if system is not having any ip object don't throw error,
788 try
789 {
790 auto properties = ipmi::getAllDbusProperties(
791 bus,
792 ipObject.second,
793 ipObject.first,
794 ipmi::network::IP_INTERFACE);
795
796 ipaddress = channelConf->ipaddr.empty() ?
797 properties["Address"].get<std::string>() :
798 channelConf->ipaddr;
799
800 prefix = channelConf->netmask.empty() ?
801 properties["PrefixLength"].get<uint8_t>() :
802 ipmi::network::toPrefix(AF_INET,
803 channelConf->netmask);
804 }
805 catch (InternalFailure& e)
806 {
807 log<level::INFO>("Failed to get IP object which matches",
808 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
809 entry("MATCH=%s", ethIp));
810 }
811
812 auto systemProperties = ipmi::getAllDbusProperties(
813 bus,
814 systemObject.second,
815 systemObject.first,
816 ipmi::network::SYSTEMCONFIG_INTERFACE);
817
818 gateway = channelConf->gateway.empty() ?
819 systemProperties["DefaultGateway"].get<std::string>() :
820 channelConf->gateway;
821 }
822 }
823
824 // Currently network manager doesn't support purging of all the
825 // ip addresses and the vlan interfaces from the parent interface,
826 // TODO once the support is there, will make the change here.
827 // https://github.com/openbmc/openbmc/issues/2141.
828
829 // TODO Currently IPMI supports single interface,need to handle
830 // Multiple interface through
831 // https://github.com/openbmc/openbmc/issues/2138
832
833 // instead of deleting all the vlan interfaces and
834 // all the ipv4 address,we will call reset method.
835 //delete all the vlan interfaces
836
837 ipmi::deleteAllDbusObjects(bus,
838 ipmi::network::ROOT,
839 ipmi::network::VLAN_INTERFACE);
840
841 // set the interface mode to static
842 auto networkInterfaceObject = ipmi::getDbusObject(
843 bus,
844 ipmi::network::ETHERNET_INTERFACE,
845 ipmi::network::ROOT,
846 ethdevice);
847
848 // setting the physical interface mode to static.
849 ipmi::setDbusProperty(bus,
850 ipmi::network::SERVICE,
851 networkInterfaceObject.first,
852 ipmi::network::ETHERNET_INTERFACE,
853 "DHCPEnabled",
854 false);
855
856 networkInterfacePath = networkInterfaceObject.first;
857
858 //delete all the ipv4 addresses
859 ipmi::deleteAllDbusObjects(bus,
860 ipmi::network::ROOT,
861 ipmi::network::IP_INTERFACE,
862 ethIp);
863
864 if (vlanID)
865 {
866 ipmi::network::createVLAN(bus,
867 ipmi::network::SERVICE,
868 ipmi::network::ROOT,
869 ethdevice,
870 vlanID);
871
872 auto networkInterfaceObject = ipmi::getDbusObject(
873 bus,
874 ipmi::network::VLAN_INTERFACE,
875 ipmi::network::ROOT);
876
877 networkInterfacePath = networkInterfaceObject.first;
878 }
879
880 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
881 {
882 ipmi::setDbusProperty(bus,
883 ipmi::network::SERVICE,
884 networkInterfacePath,
885 ipmi::network::ETHERNET_INTERFACE,
886 "DHCPEnabled",
887 true);
888 }
889 else
890 {
891 //change the mode to static
892 ipmi::setDbusProperty(bus,
893 ipmi::network::SERVICE,
894 networkInterfacePath,
895 ipmi::network::ETHERNET_INTERFACE,
896 "DHCPEnabled",
897 false);
898
899 if (!ipaddress.empty())
900 {
901 ipmi::network::createIP(bus,
902 ipmi::network::SERVICE,
903 networkInterfacePath,
904 ipv4Protocol,
905 ipaddress,
906 prefix);
907 }
908
909 if (!gateway.empty())
910 {
911 ipmi::setDbusProperty(bus,
912 systemObject.second,
913 systemObject.first,
914 ipmi::network::SYSTEMCONFIG_INTERFACE,
915 "DefaultGateway",
916 std::string(gateway));
917 }
918 }
919
920 }
921 catch (InternalFailure& e)
922 {
923 log<level::ERR>("Failed to set network data",
924 entry("PREFIX=%d", prefix),
925 entry("ADDRESS=%s", ipaddress.c_str()),
926 entry("GATEWAY=%s", gateway.c_str()),
927 entry("VLANID=%d", vlanID),
928 entry("IPSRC=%d", channelConf->ipsrc));
929
930 commit<InternalFailure>();
Ratan Gupta1247e0b2018-03-07 10:47:25 +0530931 }
932
933 channelConf->clear();
Ratan Gupta7a7f0122018-03-07 12:31:05 +0530934}
935
936void commitNetworkChanges()
937{
938 for (const auto &channel : channelConfig)
939 {
940 if (channel.second->flush)
941 {
942 applyChanges(channel.first);
943 }
944 }
945}
946
947void createNetworkTimer()
948{
949 if (!networkTimer)
950 {
951 std::function<void()> networkTimerCallback(
952 std::bind(&commitNetworkChanges));
953
954 networkTimer =
955 std::make_unique<phosphor::ipmi::Timer>(
956 ipmid_get_sd_event_connection(),
957 networkTimerCallback);
958 }
959
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>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500968 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530969 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard,
970 PRIVILEGE_USER);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500971
Tom05732372016-09-06 17:21:23 +0530972 // <Set LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500973 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
Tom05732372016-09-06 17:21:23 +0530974 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan,
975 PRIVILEGE_ADMIN);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500976
Tom05732372016-09-06 17:21:23 +0530977 // <Get LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500978 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
Tom05732372016-09-06 17:21:23 +0530979 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan,
980 PRIVILEGE_OPERATOR);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500981
982 return;
983}