blob: 30526b38391603147a000f12feab290605d1a29a [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>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05006
Patrick Williams37af7332016-09-02 21:21:42 -05007#include "host-ipmid/ipmid-api.h"
Patrick Williams53a360e2016-08-12 22:01:02 -05008#include "ipmid.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +05309#include "transporthandler.hpp"
10#include "utils.hpp"
11
12#include <phosphor-logging/log.hpp>
13#include <phosphor-logging/elog-errors.hpp>
14#include "xyz/openbmc_project/Common/error.hpp"
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050015
Hariharasubramanian R83951912016-01-20 07:06:36 -060016#define SYSTEMD_NETWORKD_DBUS 1
17
18#ifdef SYSTEMD_NETWORKD_DBUS
19#include <systemd/sd-bus.h>
Sergey Solomineb9b8142016-08-23 09:07:28 -050020#include <mapper.h>
Hariharasubramanian R83951912016-01-20 07:06:36 -060021#endif
22
23// OpenBMC System Manager dbus framework
Hariharasubramanian R83951912016-01-20 07:06:36 -060024const char *obj = "/org/openbmc/NetworkManager/Interface";
25const char *ifc = "org.openbmc.NetworkManager";
26
tomjose26e17732016-03-03 08:52:51 -060027const char *nwinterface = "eth0";
28
Adriana Kobylake08fbc62016-02-09 16:17:23 -060029const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
Adriana Kobylake08fbc62016-02-09 16:17:23 -060030
Ratan Guptab8e99552017-07-27 07:07:48 +053031struct ChannelConfig_t channelConfig;
Hariharasubramanian R83951912016-01-20 07:06:36 -060032
tomjose26e17732016-03-03 08:52:51 -060033const uint8_t SET_COMPLETE = 0;
34const uint8_t SET_IN_PROGRESS = 1;
35const uint8_t SET_COMMIT_WRITE = 2; //Optional
36const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved
37
38// Status of Set-In-Progress Parameter (# 0)
39uint8_t lan_set_in_progress = SET_COMPLETE;
40
Ratan Guptab8e99552017-07-27 07:07:48 +053041using namespace phosphor::logging;
42using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Hariharasubramanian R83951912016-01-20 07:06:36 -060043
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050044void register_netfn_transport_functions() __attribute__((constructor));
45
Ratan Guptab8e99552017-07-27 07:07:48 +053046// Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
Nan Li3d0df912016-10-18 19:51:41 +080047// Cache based on Set-In-Progress State
Ratan Guptab8e99552017-07-27 07:07:48 +053048ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data)
tomjose26e17732016-03-03 08:52:51 -060049{
tomjose26e17732016-03-03 08:52:51 -060050 ipmi_ret_t rc = IPMI_CC_OK;
Ratan Guptab8e99552017-07-27 07:07:48 +053051 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Ratan Gupta533d03b2017-07-30 10:39:22 +053052
Ratan Guptab8e99552017-07-27 07:07:48 +053053 try
tomjose26e17732016-03-03 08:52:51 -060054 {
Ratan Guptab8e99552017-07-27 07:07:48 +053055 switch (lan_param)
tomjose26e17732016-03-03 08:52:51 -060056 {
Ratan Guptab8e99552017-07-27 07:07:48 +053057 case LAN_PARM_IP:
58 {
59 std::string ipaddress;
60 if (lan_set_in_progress == SET_COMPLETE)
61 {
62 auto ipObjectInfo = ipmi::getDbusObject(
63 bus,
64 ipmi::network::IP_INTERFACE,
65 ipmi::network::ROOT,
66 ipmi::network::IP_TYPE);
67
68 auto properties = ipmi::getAllDbusProperties(
69 bus,
70 ipObjectInfo.second,
71 ipObjectInfo.first,
72 ipmi::network::IP_INTERFACE);
73
74 ipaddress = properties["Address"].get<std::string>();
75 }
76 else if (lan_set_in_progress == SET_IN_PROGRESS)
77 {
78 ipaddress = channelConfig.ipaddr;
79 }
80
81 inet_pton(AF_INET, ipaddress.c_str(),
82 reinterpret_cast<void*>(data));
83 }
84 break;
85
86 case LAN_PARM_SUBNET:
87 {
88 if (lan_set_in_progress == SET_COMPLETE)
89 {
90 auto ipObjectInfo = ipmi::getDbusObject(
91 bus,
92 ipmi::network::IP_INTERFACE,
93 ipmi::network::ROOT,
94 ipmi::network::IP_TYPE);
95
96 auto properties = ipmi::getAllDbusProperties(
97 bus,
98 ipObjectInfo.second,
99 ipObjectInfo.first,
100 ipmi::network::IP_INTERFACE);
101
102 auto prefix = properties["PrefixLength"].get<uint8_t>();
103 unsigned long mask = ipmi::network::MASK_32_BIT;
104 mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
105 memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
106 }
107 else if (lan_set_in_progress == SET_IN_PROGRESS)
108 {
109 inet_pton(AF_INET, channelConfig.netmask.c_str(),
110 reinterpret_cast<void*>(data));
111
112 }
113
114 }
115 break;
116
117 case LAN_PARM_GATEWAY:
118 {
119 std::string gateway;
120
121 if (lan_set_in_progress == SET_COMPLETE)
122 {
123 auto systemObject = ipmi::getDbusObject(
124 bus,
125 ipmi::network::SYSTEMCONFIG_INTERFACE,
126 ipmi::network::ROOT);
127
128 auto systemProperties = ipmi::getAllDbusProperties(
129 bus,
130 systemObject.second,
131 systemObject.first,
132 ipmi::network::SYSTEMCONFIG_INTERFACE);
133
134 gateway = systemProperties["DefaultGateway"].get<
135 std::string>();
136
137 }
138 else if (lan_set_in_progress == SET_IN_PROGRESS)
139 {
140 gateway = channelConfig.gateway;
141 }
142
143 inet_pton(AF_INET, gateway.c_str(),
144 reinterpret_cast<void*>(data));
145
146 }
147 break;
148
149 case LAN_PARM_MAC:
150 {
151 std::string macAddress;
152 if (lan_set_in_progress == SET_COMPLETE)
153 {
154 auto macObjectInfo = ipmi::getDbusObject(
155 bus,
156 ipmi::network::MAC_INTERFACE,
157 ipmi::network::ROOT);
158
159 auto variant = ipmi::getDbusProperty(
160 bus,
161 macObjectInfo.second,
162 macObjectInfo.first,
163 ipmi::network::MAC_INTERFACE,
164 "MACAddress");
165
166 macAddress = variant.get<std::string>();
167
168 }
169 else if (lan_set_in_progress == SET_IN_PROGRESS)
170 {
171 macAddress = channelConfig.macAddress;
172 }
173
174 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
175 (data),
176 (data + 1),
177 (data + 2),
178 (data + 3),
179 (data + 4),
180 (data + 5));
181 }
182 break;
183
Ratan Gupta533d03b2017-07-30 10:39:22 +0530184 case LAN_PARM_VLAN:
185 {
186 if (lan_set_in_progress == SET_COMPLETE)
187 {
188 auto ipObjectInfo = ipmi::getDbusObject(
189 bus,
190 ipmi::network::IP_INTERFACE,
191 ipmi::network::ROOT,
192 ipmi::network::IP_TYPE);
193
194 auto vlanID = static_cast<uint16_t>(
195 ipmi::network::getVLAN(ipObjectInfo.first));
196
197 vlanID = htole16(vlanID);
198
199 if (vlanID)
200 {
201 //Enable the 16th bit
202 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
203 }
204
205 memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
206 }
207 else if (lan_set_in_progress == SET_IN_PROGRESS)
208 {
209 memcpy(data, &(channelConfig.vlanID),
210 ipmi::network::VLAN_SIZE_BYTE);
211 }
212 }
213 break;
214
Ratan Guptab8e99552017-07-27 07:07:48 +0530215 default:
216 rc = IPMI_CC_PARM_OUT_OF_RANGE;
tomjose26e17732016-03-03 08:52:51 -0600217 }
218 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530219 catch (InternalFailure& e)
tomjose26e17732016-03-03 08:52:51 -0600220 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530221 commit<InternalFailure>();
222 rc = IPMI_CC_UNSPECIFIED_ERROR;
223 return rc;
tomjose26e17732016-03-03 08:52:51 -0600224 }
tomjose26e17732016-03-03 08:52:51 -0600225 return rc;
226}
227
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500228ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
229 ipmi_request_t request, ipmi_response_t response,
230 ipmi_data_len_t data_len, ipmi_context_t context)
231{
232 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
233 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800234 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500235 *data_len = 0;
236 return rc;
237}
238
Ratan Guptab8e99552017-07-27 07:07:48 +0530239struct set_lan_t
240{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500241 uint8_t channel;
242 uint8_t parameter;
243 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
Ratan Guptab8e99552017-07-27 07:07:48 +0530244} __attribute__((packed));
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500245
Ratan Guptab8e99552017-07-27 07:07:48 +0530246ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn,
247 ipmi_cmd_t cmd,
248 ipmi_request_t request,
249 ipmi_response_t response,
250 ipmi_data_len_t data_len,
251 ipmi_context_t context)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500252{
253 ipmi_ret_t rc = IPMI_CC_OK;
254 *data_len = 0;
Nan Li3d0df912016-10-18 19:51:41 +0800255
Ratan Guptab8e99552017-07-27 07:07:48 +0530256 char ipaddr[INET_ADDRSTRLEN];
257 char netmask[INET_ADDRSTRLEN];
258 char gateway[INET_ADDRSTRLEN];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500259
Ratan Guptab8e99552017-07-27 07:07:48 +0530260 auto reqptr = reinterpret_cast<const set_lan_t*>(request);
261 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500262
Ratan Guptab8e99552017-07-27 07:07:48 +0530263 switch (reqptr->parameter)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500264 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530265 case LAN_PARM_IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600266 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530267 snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
268 reqptr->data[0], reqptr->data[1],
269 reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500270
Ratan Guptab8e99552017-07-27 07:07:48 +0530271 channelConfig.ipaddr.assign(ipaddr);
272
273 }
274 break;
275
276 case LAN_PARM_MAC:
277 {
278 char mac[SIZE_MAC];
279
280 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
281 reqptr->data[0],
282 reqptr->data[1],
283 reqptr->data[2],
284 reqptr->data[3],
285 reqptr->data[4],
286 reqptr->data[5]);
287
288 auto macObjectInfo = ipmi::getDbusObject(
289 bus,
290 ipmi::network::MAC_INTERFACE,
291 ipmi::network::ROOT,
292 ipmi::network::INTERFACE);
293
294 ipmi::setDbusProperty(bus,
295 macObjectInfo.second,
296 macObjectInfo.first,
297 ipmi::network::MAC_INTERFACE,
298 "MACAddress",
299 std::string(mac));
300
301 channelConfig.macAddress = mac;
302
303 }
304 break;
305
306 case LAN_PARM_SUBNET:
307 {
308 snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
309 reqptr->data[0], reqptr->data[1],
310 reqptr->data[2], reqptr->data[3]);
311 channelConfig.netmask.assign(netmask);
312 }
313 break;
314
315 case LAN_PARM_GATEWAY:
316 {
317 snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
318 reqptr->data[0], reqptr->data[1],
319 reqptr->data[2], reqptr->data[3]);
320 channelConfig.gateway.assign(gateway);
321
322 }
323 break;
324
Ratan Gupta533d03b2017-07-30 10:39:22 +0530325 case LAN_PARM_VLAN:
326 {
327 uint16_t vlan {};
328 memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
329 // We are not storing the enable bit
330 // We assume that ipmitool always send enable
331 // bit as 1.
332 vlan = le16toh(vlan);
333 channelConfig.vlanID = vlan;
334 }
335 break;
336
Ratan Guptab8e99552017-07-27 07:07:48 +0530337 case LAN_PARM_INPROGRESS:
338 {
339 if (reqptr->data[0] == SET_COMPLETE)
340 {
341 lan_set_in_progress = SET_COMPLETE;
342
343 log<level::INFO>("Network data from Cache",
344 entry("PREFIX=%s", channelConfig.netmask.c_str()),
345 entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
Ratan Gupta533d03b2017-07-30 10:39:22 +0530346 entry("GATEWAY=%s", channelConfig.gateway.c_str()),
347 entry("VLAN=%d", channelConfig.vlanID));
Ratan Guptab8e99552017-07-27 07:07:48 +0530348
349 log<level::INFO>("Use Set Channel Access command to apply");
350
351 }
352 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
353 {
354 lan_set_in_progress = SET_IN_PROGRESS;
355 }
356
357 }
358 break;
359
360 default:
361 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530362 rc = IPMI_CC_PARM_NOT_SUPPORTED;
363 }
364
365 }
vishwa1eaea4f2016-02-26 11:57:40 -0600366
tomjose26e17732016-03-03 08:52:51 -0600367 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500368}
369
Ratan Guptab8e99552017-07-27 07:07:48 +0530370struct get_lan_t
371{
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500372 uint8_t rev_channel;
373 uint8_t parameter;
374 uint8_t parameter_set;
375 uint8_t parameter_block;
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_get_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;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500387 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500388
389 get_lan_t *reqptr = (get_lan_t*) request;
390
391 if (reqptr->rev_channel & 0x80) // Revision is bit 7
392 {
393 // Only current revision was requested
394 *data_len = sizeof(current_revision);
395 memcpy(response, &current_revision, *data_len);
396 return IPMI_CC_OK;
397 }
398
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600399 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500400 {
tomjose26e17732016-03-03 08:52:51 -0600401 uint8_t buf[] = {current_revision, lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500402 *data_len = sizeof(buf);
403 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500404 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600405 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500406 {
407 uint8_t buf[] = {current_revision,0x04};
408 *data_len = sizeof(buf);
409 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500410 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600411 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500412 {
413 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
414 *data_len = sizeof(buf);
415 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500416 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530417 else if ((reqptr->parameter == LAN_PARM_IP) ||
418 (reqptr->parameter == LAN_PARM_SUBNET) ||
419 (reqptr->parameter == LAN_PARM_GATEWAY) ||
420 (reqptr->parameter == LAN_PARM_MAC))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500421 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530422 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500423
tomjose26e17732016-03-03 08:52:51 -0600424 *data_len = sizeof(current_revision);
425 memcpy(buf, &current_revision, *data_len);
426
Ratan Guptab8e99552017-07-27 07:07:48 +0530427 if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600428 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530429 if (reqptr->parameter == LAN_PARM_MAC)
430 {
431 *data_len = sizeof(buf);
432 }
433 else
434 {
435 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
436 }
tomjose26e17732016-03-03 08:52:51 -0600437 memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600438 }
tomjose26e17732016-03-03 08:52:51 -0600439 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600440 {
tomjose26e17732016-03-03 08:52:51 -0600441 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600442 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500443 }
Ratan Gupta533d03b2017-07-30 10:39:22 +0530444 else if (reqptr->parameter == LAN_PARM_VLAN)
445 {
446 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1];
447
448 *data_len = sizeof(current_revision);
449 memcpy(buf, &current_revision, *data_len);
450 if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
451 {
452 *data_len = sizeof(buf);
453 memcpy(response, &buf, *data_len);
454 }
455 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500456 else
457 {
Ratan Guptab8e99552017-07-27 07:07:48 +0530458 log<level::ERR>("Unsupported parameter",
459 entry("PARAMETER=0x%x", reqptr->parameter));
vishwa1eaea4f2016-02-26 11:57:40 -0600460 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500461 }
462
463 return rc;
464}
465
466void register_netfn_transport_functions()
467{
Tom05732372016-09-06 17:21:23 +0530468 // <Wildcard Command>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500469 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530470 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard,
471 PRIVILEGE_USER);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500472
Tom05732372016-09-06 17:21:23 +0530473 // <Set LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500474 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
Tom05732372016-09-06 17:21:23 +0530475 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan,
476 PRIVILEGE_ADMIN);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500477
Tom05732372016-09-06 17:21:23 +0530478 // <Get LAN Configuration Parameters>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500479 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
Tom05732372016-09-06 17:21:23 +0530480 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan,
481 PRIVILEGE_OPERATOR);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500482
483 return;
484}