blob: 2df5ebfb22d2ded0e279ac26e24bf8da34a1d06e [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>
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05005
6#include "ipmid-api.h"
7#include "ipmid.H"
8#include "transporthandler.h"
9
Hariharasubramanian R83951912016-01-20 07:06:36 -060010#define SYSTEMD_NETWORKD_DBUS 1
11
12#ifdef SYSTEMD_NETWORKD_DBUS
13#include <systemd/sd-bus.h>
14#endif
15
16// OpenBMC System Manager dbus framework
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -060017extern sd_bus *bus;
Hariharasubramanian R83951912016-01-20 07:06:36 -060018const char *app = "org.openbmc.NetworkManager";
19const char *obj = "/org/openbmc/NetworkManager/Interface";
20const char *ifc = "org.openbmc.NetworkManager";
21
22char cur_ipaddr [16] = "";
23char cur_netmask [16] = "";
24char cur_gateway [16] = "";
25
26char new_ipaddr [16] = "";
27char new_netmask [16] = "";
28char new_gateway [16] = "";
29
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050030void register_netfn_transport_functions() __attribute__((constructor));
31
32ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
33 ipmi_request_t request, ipmi_response_t response,
34 ipmi_data_len_t data_len, ipmi_context_t context)
35{
36 printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
37 // Status code.
38 ipmi_ret_t rc = IPMI_CC_OK;
39 *data_len = 0;
40 return rc;
41}
42
43struct set_lan_t {
44 uint8_t channel;
45 uint8_t parameter;
46 uint8_t data[8]; // Per IPMI spec, not expecting more than this size
47} __attribute__ ((packed));
48
49ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
50 ipmi_request_t request, ipmi_response_t response,
51 ipmi_data_len_t data_len, ipmi_context_t context)
52{
53 ipmi_ret_t rc = IPMI_CC_OK;
54 *data_len = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050055
56 printf("IPMI SET_LAN\n");
57
58 set_lan_t *reqptr = (set_lan_t*) request;
59
60 // TODO Use dbus interface once available. For now use cmd line.
61 // TODO Add the rest of the parameters like setting auth type
62 // TODO Add error handling
63
64 if (reqptr->parameter == 3) // IP
65 {
Hariharasubramanian R83951912016-01-20 07:06:36 -060066 sprintf(new_ipaddr, "%d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050067 }
Adriana Kobylakd54a9dd2016-02-03 17:25:54 -060068 else if (reqptr->parameter == 5) // MAC
69 {
70 char mac[18];
71 sd_bus_message *reply = NULL, *m = NULL;
72 sd_bus_error error = SD_BUS_ERROR_NULL;
73 int r = 0;
74
75 sprintf(mac, "%x:%x:%x:%x:%x:%x",
76 reqptr->data[0],
77 reqptr->data[1],
78 reqptr->data[2],
79 reqptr->data[3],
80 reqptr->data[4],
81 reqptr->data[5]);
82
83 r = sd_bus_message_new_method_call(bus,&m,app,obj,ifc,"SetHwAddress");
84 if (r < 0) {
85 fprintf(stderr, "Failed to add method object: %s\n", strerror(-r));
86 return -1;
87 }
88 r = sd_bus_message_append(m, "s", mac);
89 if (r < 0) {
90 fprintf(stderr, "Failed to append message data: %s\n", strerror(-r));
91 return -1;
92 }
93 r = sd_bus_call(bus, m, 0, &error, &reply);
94 if (r < 0) {
95 fprintf(stderr, "Failed to call method: %s\n", strerror(-r));
96 return -1;
97 }
98 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -050099 else if (reqptr->parameter == 6) // Subnet
100 {
Hariharasubramanian R83951912016-01-20 07:06:36 -0600101 sprintf(new_netmask, "%d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500102 }
103 else if (reqptr->parameter == 12) // Gateway
104 {
Hariharasubramanian R83951912016-01-20 07:06:36 -0600105 sprintf(new_gateway, "%d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
106 }
107 else if (reqptr->parameter == 0) // Apply config
108 {
109 int rc = 0;
110 sd_bus_message *req = NULL;
111 sd_bus_message *res = NULL;
112 sd_bus *bus = NULL;
113 sd_bus_error err = SD_BUS_ERROR_NULL;
114
115 if (!strcmp(new_ipaddr, "") || !strcmp (new_netmask, "") || !strcmp (new_gateway, ""))
116 {
117 fprintf(stderr,"ERROR: Incomplete LAN Parameters\n");
118 return -1;
119 }
120
121 rc = sd_bus_open_system(&bus);
122 if(rc < 0)
123 {
124 fprintf(stderr,"ERROR: Getting a SYSTEM bus hook\n");
125 return -1;
126 }
127
128 if (strcmp(cur_ipaddr, ""))
129 {
130 sd_bus_error_free(&err);
131 sd_bus_message_unref(req);
132 sd_bus_message_unref(res);
133
134 rc = sd_bus_call_method(bus, // On the System Bus
135 app, // Service to contact
136 obj, // Object path
137 ifc, // Interface name
138 "DelAddress4", // Method to be called
139 &err, // object to return error
140 &res, // Response message on success
141 "ssss", // input message (dev,ip,nm,gw)
142 "eth0",
143 cur_ipaddr,
144 cur_netmask,
145 cur_gateway);
146 }
147
148 if(rc < 0)
149 {
150 fprintf(stderr, "Failed to remove existing IP %s: %s\n", cur_ipaddr, err.message);
151 return -1;
152 }
153
154 sd_bus_error_free(&err);
155 sd_bus_message_unref(req);
156 sd_bus_message_unref(res);
157
158 rc = sd_bus_call_method(bus, // On the System Bus
159 app, // Service to contact
160 obj, // Object path
161 ifc, // Interface name
162 "AddAddress4", // Method to be called
163 &err, // object to return error
164 &res, // Response message on success
165 "ssss", // input message (dev,ip,nm,gw)
166 "eth0",
167 new_ipaddr,
168 new_netmask,
169 new_gateway);
170 if(rc < 0)
171 {
172 fprintf(stderr, "Failed to set IP %s: %s\n", new_ipaddr, err.message);
173 return -1;
174 }
175
176 strcpy (cur_ipaddr, new_ipaddr);
177 strcpy (cur_netmask, new_netmask);
178 strcpy (cur_gateway, new_gateway);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500179 }
180 else
181 {
182 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
183 return IPMI_CC_PARM_NOT_SUPPORTED;
184 }
185
186 return rc;
187}
188
189struct get_lan_t {
190 uint8_t rev_channel;
191 uint8_t parameter;
192 uint8_t parameter_set;
193 uint8_t parameter_block;
194} __attribute__ ((packed));
195
196ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
197 ipmi_request_t request, ipmi_response_t response,
198 ipmi_data_len_t data_len, ipmi_context_t context)
199{
200 ipmi_ret_t rc = IPMI_CC_OK;
201 *data_len = 0;
Adriana Kobylak9355f612016-02-08 17:30:37 -0600202 sd_bus_message *reply = NULL, *m = NULL;
203 sd_bus_error error = SD_BUS_ERROR_NULL;
204 int r = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500205 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
Hariharasubramanian R83951912016-01-20 07:06:36 -0600206
207 int family;
208 unsigned char prefixlen;
209 unsigned char scope;
210 unsigned int flags;
211 char saddr [128];
212 char gateway [128];
213 uint8_t buf[11];
Adriana Kobylak9355f612016-02-08 17:30:37 -0600214 int i = 0;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500215
216 printf("IPMI GET_LAN\n");
217
218 get_lan_t *reqptr = (get_lan_t*) request;
219
220 if (reqptr->rev_channel & 0x80) // Revision is bit 7
221 {
222 // Only current revision was requested
223 *data_len = sizeof(current_revision);
224 memcpy(response, &current_revision, *data_len);
225 return IPMI_CC_OK;
226 }
227
228 // TODO Use dbus interface once available. For now use ip cmd.
229 // TODO Add the rest of the parameters, like gateway
230
231 if (reqptr->parameter == 0) // In progress
232 {
233 uint8_t buf[] = {current_revision,0};
234 *data_len = sizeof(buf);
235 memcpy(response, &buf, *data_len);
236 return IPMI_CC_OK;
237 }
238 else if (reqptr->parameter == 1) // Authentication support
239 {
240 uint8_t buf[] = {current_revision,0x04};
241 *data_len = sizeof(buf);
242 memcpy(response, &buf, *data_len);
243 return IPMI_CC_OK;
244 }
245 else if (reqptr->parameter == 2) // Authentication enables
246 {
247 uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
248 *data_len = sizeof(buf);
249 memcpy(response, &buf, *data_len);
250 return IPMI_CC_OK;
251 }
252 else if (reqptr->parameter == 3) // IP
253 {
Hariharasubramanian R83951912016-01-20 07:06:36 -0600254 const char* device = "eth0";
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500255
Hariharasubramanian R83951912016-01-20 07:06:36 -0600256 sd_bus_message *res = NULL;
257 sd_bus *bus = NULL;
258 sd_bus_error err = SD_BUS_ERROR_NULL;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500259
Hariharasubramanian R83951912016-01-20 07:06:36 -0600260 rc = sd_bus_open_system(&bus);
261 if(rc < 0)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500262 {
Hariharasubramanian R83951912016-01-20 07:06:36 -0600263 fprintf(stderr,"ERROR: Getting a SYSTEM bus hook\n");
264 return -1;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500265 }
266
Hariharasubramanian R83951912016-01-20 07:06:36 -0600267 rc = sd_bus_call_method(bus, // On the System Bus
268 app, // Service to contact
269 obj, // Object path
270 ifc, // Interface name
271 "GetAddress4", // Method to be called
272 &err, // object to return error
273 &res, // Response message on success
274 "s", // input message (dev,ip,nm,gw)
275 "eth0");
276 if(rc < 0)
277 {
278 fprintf(stderr, "Failed to Get IP on interface : %s\n", device);
279 return -1;
280 }
281
282 /* rc = sd_bus_message_read(res, "a(iyyus)s", ...); */
283 rc = sd_bus_message_enter_container (res, 'a', "(iyyus)");
284 if(rc < 0)
285 {
286 fprintf(stderr, "Failed to parse response message:[%s]\n", strerror(-rc));
287 return -1;
288 }
289
290 while ((rc = sd_bus_message_read(res, "(iyyus)", &family, &prefixlen, &scope, &flags, &saddr)) > 0) {
291 printf("%s:%d:%d:%d:%s\n", family==AF_INET?"IPv4":"IPv6", prefixlen, scope, flags, saddr);
292 }
293
294 rc = sd_bus_message_read (res, "s", &gateway);
295 if(rc < 0)
296 {
297 fprintf(stderr, "Failed to parse gateway from response message:[%s]\n", strerror(-rc));
298 return -1;
299 }
300
301 memcpy((void*)&buf[0], &current_revision, 1);
302 sscanf (saddr, "%c.%c.%c.%c", &buf[1], &buf[2], &buf[3], &buf[4]);
303 buf[5] = family;
304 buf[6] = prefixlen;
305 sscanf (gateway, "%c.%c.%c.%c", &buf[7], &buf[8], &buf[9], &buf[10]);
306
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500307 *data_len = sizeof(buf);
308 memcpy(response, &buf, *data_len);
Hariharasubramanian R83951912016-01-20 07:06:36 -0600309
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500310 return IPMI_CC_OK;
311 }
312 else if (reqptr->parameter == 5) // MAC
313 {
314 //string to parse: link/ether xx:xx:xx:xx:xx:xx
315
Hariharasubramanian R83951912016-01-20 07:06:36 -0600316 const char* device = "eth0";
Hariharasubramanian R83951912016-01-20 07:06:36 -0600317 uint8_t buf[7];
Adriana Kobylak9355f612016-02-08 17:30:37 -0600318 char *eaddr1 = NULL;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500319
Adriana Kobylak9355f612016-02-08 17:30:37 -0600320 r = sd_bus_message_new_method_call(bus,&m,app,obj,ifc,"GetHwAddress");
321 if (r < 0) {
322 fprintf(stderr, "Failed to add method object: %s\n", strerror(-r));
Hariharasubramanian R83951912016-01-20 07:06:36 -0600323 return -1;
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500324 }
Adriana Kobylak9355f612016-02-08 17:30:37 -0600325 r = sd_bus_message_append(m, "s", device);
326 if (r < 0) {
327 fprintf(stderr, "Failed to append message data: %s\n", strerror(-r));
Hariharasubramanian R83951912016-01-20 07:06:36 -0600328 return -1;
329 }
Adriana Kobylak9355f612016-02-08 17:30:37 -0600330 r = sd_bus_call(bus, m, 0, &error, &reply);
331 if (r < 0) {
332 fprintf(stderr, "Failed to call method: %s\n", strerror(-r));
Hariharasubramanian R83951912016-01-20 07:06:36 -0600333 return -1;
334 }
Adriana Kobylak9355f612016-02-08 17:30:37 -0600335 r = sd_bus_message_read(reply, "s", &eaddr1);
336 if (r < 0) {
337 fprintf(stderr, "Failed to get a response: %s", strerror(-r));
338 return IPMI_CC_RESPONSE_ERROR;
339 }
340 if (eaddr1 == NULL)
341 {
342 fprintf(stderr, "Failed to get a valid response: %s", strerror(-r));
343 return IPMI_CC_RESPONSE_ERROR;
344 }
Hariharasubramanian R83951912016-01-20 07:06:36 -0600345
346 memcpy((void*)&buf[0], &current_revision, 1);
Adriana Kobylak9355f612016-02-08 17:30:37 -0600347
348 char *tokptr = NULL;
349 char* digit = strtok_r(eaddr1, ":", &tokptr);
350 if (digit == NULL)
351 {
352 fprintf(stderr, "Unexpected MAC format: %s", eaddr1);
353 return IPMI_CC_RESPONSE_ERROR;
354 }
355
356 i=0;
357 while (digit != NULL)
358 {
359 int resp_byte = strtoul(digit, NULL, 16);
360 memcpy((void*)&buf[i+1], &resp_byte, 1);
361 i++;
362 digit = strtok_r(NULL, ":", &tokptr);
363 }
Hariharasubramanian R83951912016-01-20 07:06:36 -0600364
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500365 *data_len = sizeof(buf);
366 memcpy(response, &buf, *data_len);
Hariharasubramanian R83951912016-01-20 07:06:36 -0600367
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500368 return IPMI_CC_OK;
369 }
370 else
371 {
372 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
373 return IPMI_CC_PARM_NOT_SUPPORTED;
374 }
375
376 return rc;
377}
378
379void register_netfn_transport_functions()
380{
381 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
382 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard);
383
384 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
385 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan);
386
387 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
388 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan);
389
390 return;
391}