blob: 3b4cf07a22ba55bd814af67db0d63aaf23d7d812 [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
7#include "ipmid-api.h"
8#include "ipmid.H"
9#include "transporthandler.h"
10
Hariharasubramanian R83951912016-01-20 07:06:36 -060011#define SYSTEMD_NETWORKD_DBUS 1
12
13#ifdef SYSTEMD_NETWORKD_DBUS
14#include <systemd/sd-bus.h>
15#endif
16
17// OpenBMC System Manager dbus framework
18const char *app = "org.openbmc.NetworkManager";
19const char *obj = "/org/openbmc/NetworkManager/Interface";
20const char *ifc = "org.openbmc.NetworkManager";
21
tomjose26e17732016-03-03 08:52:51 -060022const char *nwinterface = "eth0";
23
Adriana Kobylake08fbc62016-02-09 16:17:23 -060024const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
Adriana Kobylake08fbc62016-02-09 16:17:23 -060025
tomjose26e17732016-03-03 08:52:51 -060026char new_ipaddr [INET_ADDRSTRLEN] = "";
27char new_netmask [INET_ADDRSTRLEN] = "";
28char new_gateway [INET_ADDRSTRLEN] = "";
Hariharasubramanian R83951912016-01-20 07:06:36 -060029
tomjose26e17732016-03-03 08:52:51 -060030const uint8_t SET_COMPLETE = 0;
31const uint8_t SET_IN_PROGRESS = 1;
32const uint8_t SET_COMMIT_WRITE = 2; //Optional
33const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved
34
35// Status of Set-In-Progress Parameter (# 0)
36uint8_t lan_set_in_progress = SET_COMPLETE;
37
38
Hariharasubramanian R83951912016-01-20 07:06:36 -060039
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050040void register_netfn_transport_functions() __attribute__((constructor));
41
tomjose26e17732016-03-03 08:52:51 -060042// Helper Function to get IP Address/NetMask/Gateway from Network Manager or Cache
43// based on Set-In-Progress State
44ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t * data)
45{
46 sd_bus *bus = ipmid_get_sd_bus_connection();
47 sd_bus_message *reply = NULL;
48 sd_bus_error error = SD_BUS_ERROR_NULL;
49 int family;
50 unsigned char prefixlen;
51 char* ipaddr = NULL;
52 unsigned long mask = 0xFFFFFFFF;
53 char* gateway = NULL;
54 int r = 0;
55 ipmi_ret_t rc = IPMI_CC_OK;
56
57 r = sd_bus_call_method(bus, app, obj, ifc, "GetAddress4", &error,
58 &reply, "s", nwinterface);
59 if(r < 0)
60 {
61 fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
62 rc = IPMI_CC_UNSPECIFIED_ERROR;
63 goto cleanup;
64 }
65
66 r = sd_bus_message_read(reply, "iyss", &family, &prefixlen, &ipaddr, &gateway);
67 if(r < 0)
68 {
69 fprintf(stderr, "Failed to get a response: %s\n", strerror(-rc));
70 rc = IPMI_CC_RESPONSE_ERROR;
71 goto cleanup;
72 }
73
74 printf("N/W data from HW %s:%d:%s:%s\n", family==AF_INET?"IPv4":"IPv6", prefixlen, ipaddr,gateway);
75 printf("N/W data from Cache: %s:%s:%s\n", new_ipaddr, new_netmask, new_gateway);
76
77 if(lan_param == LAN_PARM_IP)
78 {
79 if(lan_set_in_progress == SET_COMPLETE)
80 {
81 std::string ipaddrstr(ipaddr);
82 inet_pton(AF_INET, ipaddrstr.c_str(),(void *)data);
83 }
84 else if(lan_set_in_progress == SET_IN_PROGRESS)
85 {
86 inet_pton(AF_INET, new_ipaddr, (void *)data);
87 }
88 }
89 else if(lan_param == LAN_PARM_SUBNET)
90 {
91 if(lan_set_in_progress == SET_COMPLETE)
92 {
93 mask = htonl(mask<<(32-prefixlen));
94 memcpy(data, &mask, 4);
95 }
96 else if(lan_set_in_progress == SET_IN_PROGRESS)
97 {
98 inet_pton(AF_INET, new_netmask, (void *)data);
99 }
100 }
101 else if(lan_param == LAN_PARM_GATEWAY)
102 {
103 if(lan_set_in_progress == SET_COMPLETE)
104 {
105 std::string gatewaystr(gateway);
106 inet_pton(AF_INET, gatewaystr.c_str(), (void *)data);
107 }
108 else if(lan_set_in_progress == SET_IN_PROGRESS)
109 {
110 inet_pton(AF_INET, new_gateway,(void *)data);
111 }
112 }
113 else
114 {
115 rc = IPMI_CC_PARM_OUT_OF_RANGE;
116 }
117
118cleanup:
119 sd_bus_error_free(&error);
120 reply = sd_bus_message_unref(reply);
121
122 return rc;
123}
124
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500125ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
126 ipmi_request_t request, ipmi_response_t response,
127 ipmi_data_len_t data_len, ipmi_context_t context)
128{
129 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
130 // Status code.
131 ipmi_ret_t rc = IPMI_CC_OK;
132 *data_len = 0;
133 return rc;
134}
135
136struct set_lan_t {
137 uint8_t channel;
138 uint8_t parameter;
139 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
140} __attribute__ ((packed));
141
142ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
143 ipmi_request_t request, ipmi_response_t response,
144 ipmi_data_len_t data_len, ipmi_context_t context)
145{
146 ipmi_ret_t rc = IPMI_CC_OK;
147 *data_len = 0;
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600148 sd_bus *bus = ipmid_get_sd_bus_connection();
vishwa1eaea4f2016-02-26 11:57:40 -0600149 sd_bus_message *reply = NULL;
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600150 sd_bus_error error = SD_BUS_ERROR_NULL;
151 int r = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500152
153 printf("IPMI SET_LAN\n");
154
155 set_lan_t *reqptr = (set_lan_t*) request;
156
157 // TODO Use dbus interface once available. For now use cmd line.
158 // TODO Add the rest of the parameters like setting auth type
159 // TODO Add error handling
160
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600161 if (reqptr->parameter == LAN_PARM_IP)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500162 {
tomjose26e17732016-03-03 08:52:51 -0600163 snprintf(new_ipaddr, INET_ADDRSTRLEN, "%d.%d.%d.%d",
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600164 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500165 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600166 else if (reqptr->parameter == LAN_PARM_MAC)
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -0600167 {
tomjose26e17732016-03-03 08:52:51 -0600168 char mac[SIZE_MAC];
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -0600169
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600170 snprintf(mac, SIZE_MAC, "%02x:%02x:%02x:%02x:%02x:%02x",
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -0600171 reqptr->data[0],
172 reqptr->data[1],
173 reqptr->data[2],
174 reqptr->data[3],
175 reqptr->data[4],
176 reqptr->data[5]);
177
tomjose26e17732016-03-03 08:52:51 -0600178 r = sd_bus_call_method(bus, app, obj, ifc, "SetHwAddress", &error,
179 &reply, "ss", nwinterface, mac);
180 if(r < 0)
181 {
182 fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
183 rc = IPMI_CC_UNSPECIFIED_ERROR;
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -0600184 }
185 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600186 else if (reqptr->parameter == LAN_PARM_SUBNET)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500187 {
tomjose26e17732016-03-03 08:52:51 -0600188 snprintf(new_netmask, INET_ADDRSTRLEN, "%d.%d.%d.%d",
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600189 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500190 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600191 else if (reqptr->parameter == LAN_PARM_GATEWAY)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500192 {
tomjose26e17732016-03-03 08:52:51 -0600193 snprintf(new_gateway, INET_ADDRSTRLEN, "%d.%d.%d.%d",
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600194 reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Hariharasubramanian R83951912016-01-20 07:06:36 -0600195 }
tomjose26e17732016-03-03 08:52:51 -0600196 else if (reqptr->parameter == LAN_PARM_INPROGRESS)
Hariharasubramanian R83951912016-01-20 07:06:36 -0600197 {
tomjose26e17732016-03-03 08:52:51 -0600198 if(reqptr->data[0] == SET_COMPLETE) // Set Complete
Hariharasubramanian R83951912016-01-20 07:06:36 -0600199 {
tomjose26e17732016-03-03 08:52:51 -0600200 lan_set_in_progress = SET_COMPLETE;
201 // Apply the IP settings once IP Address, Netmask and Gateway is set
202 if (!strcmp(new_ipaddr, "") || !strcmp (new_netmask, "") || !strcmp (new_gateway, ""))
203 {
204 printf("ERROR: Incomplete LAN Parameters\n");
205 }
206 else
207 {
Hariharasubramanian R83951912016-01-20 07:06:36 -0600208
tomjose26e17732016-03-03 08:52:51 -0600209 r = sd_bus_call_method(bus, // On the System Bus
210 app, // Service to contact
211 obj, // Object path
212 ifc, // Interface name
213 "SetAddress4", // Method to be called
214 &error, // object to return error
215 &reply, // Response message on success
216 "ssss", // input message (Interface, IP Address, Netmask, Gateway)
217 nwinterface, // eth0
218 new_ipaddr,
219 new_netmask,
220 new_gateway);
221 if(r < 0)
222 {
223 fprintf(stderr, "Failed to set network data %s:%s:%s %s\n", new_ipaddr, new_netmask, new_gateway, error.message);
224 rc = IPMI_CC_UNSPECIFIED_ERROR;
225 }
226 memset(new_ipaddr, 0, INET_ADDRSTRLEN);
227 memset(new_netmask, 0, INET_ADDRSTRLEN);
228 memset(new_gateway, 0, INET_ADDRSTRLEN);
229 }
Hariharasubramanian R83951912016-01-20 07:06:36 -0600230 }
tomjose26e17732016-03-03 08:52:51 -0600231 else if(reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
Hariharasubramanian R83951912016-01-20 07:06:36 -0600232 {
tomjose26e17732016-03-03 08:52:51 -0600233 lan_set_in_progress = SET_IN_PROGRESS;
vishwa1eaea4f2016-02-26 11:57:40 -0600234 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500235 }
236 else
237 {
238 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
vishwa1eaea4f2016-02-26 11:57:40 -0600239 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500240 }
241
vishwa1eaea4f2016-02-26 11:57:40 -0600242 sd_bus_error_free(&error);
243 reply = sd_bus_message_unref(reply);
244
tomjose26e17732016-03-03 08:52:51 -0600245 return rc;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500246}
247
248struct get_lan_t {
249 uint8_t rev_channel;
250 uint8_t parameter;
251 uint8_t parameter_set;
252 uint8_t parameter_block;
253} __attribute__ ((packed));
254
255ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
256 ipmi_request_t request, ipmi_response_t response,
257 ipmi_data_len_t data_len, ipmi_context_t context)
258{
259 ipmi_ret_t rc = IPMI_CC_OK;
260 *data_len = 0;
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600261 sd_bus *bus = ipmid_get_sd_bus_connection();
vishwa1eaea4f2016-02-26 11:57:40 -0600262 sd_bus_message *reply = NULL;
Adriana Kobylak9355f612016-02-08 17:30:37 -0600263 sd_bus_error error = SD_BUS_ERROR_NULL;
264 int r = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500265 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
tomjose26e17732016-03-03 08:52:51 -0600266 int i = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500267
268 printf("IPMI GET_LAN\n");
269
270 get_lan_t *reqptr = (get_lan_t*) request;
271
272 if (reqptr->rev_channel & 0x80) // Revision is bit 7
273 {
274 // Only current revision was requested
275 *data_len = sizeof(current_revision);
276 memcpy(response, &current_revision, *data_len);
277 return IPMI_CC_OK;
278 }
279
280 // TODO Use dbus interface once available. For now use ip cmd.
281 // TODO Add the rest of the parameters, like gateway
282
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600283 if (reqptr->parameter == LAN_PARM_INPROGRESS)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500284 {
tomjose26e17732016-03-03 08:52:51 -0600285 uint8_t buf[] = {current_revision, lan_set_in_progress};
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500286 *data_len = sizeof(buf);
287 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500288 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600289 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500290 {
291 uint8_t buf[] = {current_revision,0x04};
292 *data_len = sizeof(buf);
293 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500294 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600295 else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500296 {
297 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
298 *data_len = sizeof(buf);
299 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500300 }
tomjose26e17732016-03-03 08:52:51 -0600301 else if ((reqptr->parameter == LAN_PARM_IP) || (reqptr->parameter == LAN_PARM_SUBNET) || (reqptr->parameter == LAN_PARM_GATEWAY))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500302 {
tomjose26e17732016-03-03 08:52:51 -0600303 uint8_t buf[5];
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500304
tomjose26e17732016-03-03 08:52:51 -0600305 *data_len = sizeof(current_revision);
306 memcpy(buf, &current_revision, *data_len);
307
308 if(getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
vishwa1eaea4f2016-02-26 11:57:40 -0600309 {
tomjose26e17732016-03-03 08:52:51 -0600310 *data_len = sizeof(buf);
311 memcpy(response, &buf, *data_len);
Adriana Kobylak342df102016-02-10 13:48:16 -0600312 }
tomjose26e17732016-03-03 08:52:51 -0600313 else
Hariharasubramanian R83951912016-01-20 07:06:36 -0600314 {
tomjose26e17732016-03-03 08:52:51 -0600315 rc = IPMI_CC_UNSPECIFIED_ERROR;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600316 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500317 }
Adriana Kobylake08fbc62016-02-09 16:17:23 -0600318 else if (reqptr->parameter == LAN_PARM_MAC)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500319 {
320 //string to parse: link/ether xx:xx:xx:xx:xx:xx
tomjose26e17732016-03-03 08:52:51 -0600321 uint8_t buf[7];
Adriana Kobylak9355f612016-02-08 17:30:37 -0600322 char *eaddr1 = NULL;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500323
tomjose26e17732016-03-03 08:52:51 -0600324 r = sd_bus_call_method(bus, app, obj, ifc, "GetHwAddress", &error,
325 &reply, "s", nwinterface);
326 if(r < 0)
vishwa1eaea4f2016-02-26 11:57:40 -0600327 {
tomjose26e17732016-03-03 08:52:51 -0600328 fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
329 rc = IPMI_CC_UNSPECIFIED_ERROR;
330 goto cleanup;
Hariharasubramanian R83951912016-01-20 07:06:36 -0600331 }
tomjose26e17732016-03-03 08:52:51 -0600332
Adriana Kobylak9355f612016-02-08 17:30:37 -0600333 r = sd_bus_message_read(reply, "s", &eaddr1);
vishwa1eaea4f2016-02-26 11:57:40 -0600334 if (r < 0)
335 {
Adriana Kobylak9355f612016-02-08 17:30:37 -0600336 fprintf(stderr, "Failed to get a response: %s", strerror(-r));
tomjose26e17732016-03-03 08:52:51 -0600337 rc = IPMI_CC_UNSPECIFIED_ERROR;
338 goto cleanup;
Adriana Kobylak9355f612016-02-08 17:30:37 -0600339 }
340 if (eaddr1 == NULL)
341 {
342 fprintf(stderr, "Failed to get a valid response: %s", strerror(-r));
tomjose26e17732016-03-03 08:52:51 -0600343 rc = IPMI_CC_UNSPECIFIED_ERROR;
344 goto cleanup;
Adriana Kobylak9355f612016-02-08 17:30:37 -0600345 }
Hariharasubramanian R83951912016-01-20 07:06:36 -0600346
347 memcpy((void*)&buf[0], &current_revision, 1);
Adriana Kobylak9355f612016-02-08 17:30:37 -0600348
349 char *tokptr = NULL;
350 char* digit = strtok_r(eaddr1, ":", &tokptr);
351 if (digit == NULL)
352 {
353 fprintf(stderr, "Unexpected MAC format: %s", eaddr1);
vishwa1eaea4f2016-02-26 11:57:40 -0600354 rc = IPMI_CC_RESPONSE_ERROR;
tomjose26e17732016-03-03 08:52:51 -0600355 goto cleanup;
Adriana Kobylak9355f612016-02-08 17:30:37 -0600356 }
357
358 i=0;
359 while (digit != NULL)
360 {
361 int resp_byte = strtoul(digit, NULL, 16);
362 memcpy((void*)&buf[i+1], &resp_byte, 1);
363 i++;
364 digit = strtok_r(NULL, ":", &tokptr);
365 }
Hariharasubramanian R83951912016-01-20 07:06:36 -0600366
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500367 *data_len = sizeof(buf);
368 memcpy(response, &buf, *data_len);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500369 }
370 else
371 {
372 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
vishwa1eaea4f2016-02-26 11:57:40 -0600373 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500374 }
375
tomjose26e17732016-03-03 08:52:51 -0600376cleanup:
vishwa1eaea4f2016-02-26 11:57:40 -0600377 sd_bus_error_free(&error);
378 reply = sd_bus_message_unref(reply);
379
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500380 return rc;
381}
382
383void register_netfn_transport_functions()
384{
385 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
386 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard);
387
388 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
389 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan);
390
391 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
392 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan);
393
394 return;
395}