1 #include "apphandler.h"
2 #include "host-ipmid/ipmid-api.h"
3 #include "ipmid.hpp"
4 #include "types.hpp"
5 #include "utils.hpp"
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdint.h>
10 #include <systemd/sd-bus.h>
11 #include <mapper.h>
12 #include <array>
13 #include <arpa/inet.h>
14 #include "transporthandler.hpp"
15 
16 #include <phosphor-logging/log.hpp>
17 #include <phosphor-logging/elog-errors.hpp>
18 #include "xyz/openbmc_project/Common/error.hpp"
19 
20 extern sd_bus *bus;
21 
22 constexpr auto app_obj = "/org/openbmc/NetworkManager/Interface";
23 constexpr auto app_ifc = "org.openbmc.NetworkManager";
24 constexpr auto app_nwinterface = "eth0";
25 
26 constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
27 
28 void register_netfn_app_functions() __attribute__((constructor));
29 
30 using namespace phosphor::logging;
31 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
32 
33 // Offset in get device id command.
34 typedef struct
35 {
36    uint8_t id;
37    uint8_t revision;
38    uint8_t fw[2];
39    uint8_t ipmi_ver;
40    uint8_t addn_dev_support;
41    uint8_t manuf_id[3];
42    uint8_t prod_id[2];
43    uint8_t aux[4];
44 }__attribute__((packed)) ipmi_device_id_t;
45 
46 ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
47                              ipmi_request_t request, ipmi_response_t response,
48                              ipmi_data_len_t data_len, ipmi_context_t context)
49 {
50     ipmi_ret_t rc = IPMI_CC_OK;
51     *data_len = 0;
52 
53     printf("IPMI SET ACPI STATE Ignoring for now\n");
54     return rc;
55 }
56 
57 
58 typedef struct
59 {
60     char major;
61     char minor;
62     uint16_t d[2];
63 } rev_t;
64 
65 
66 /* Currently only supports the vx.x-x-[-x] format Will return -1 if not in  */
67 /* the format this routine knows how to parse                               */
68 /* version = v0.6-19-gf363f61-dirty                                         */
69 /*            ^ ^ ^^          ^                                             */
70 /*            | |  |----------|-- additional details                        */
71 /*            | |---------------- Minor                                     */
72 /*            |------------------ Major                                     */
73 /* Additional details : If the option group exists it will force Auxiliary  */
74 /* Firmware Revision Information 4th byte to 1 indicating the build was     */
75 /* derived with additional edits                                            */
76 int convert_version(const char *p, rev_t *rev)
77 {
78     char *s, *token;
79     uint16_t commits;
80 
81     if (*p != 'v')
82         return -1;
83     p++;
84 
85     s = strdup(p);
86     token = strtok(s,".-");
87 
88     rev->major = (int8_t) atoi(token);
89 
90     token = strtok(NULL, ".-");
91     rev->minor = (int8_t) atoi(token);
92 
93     // Capture the number of commits on top of the minor tag.
94     // I'm using BE format like the ipmi spec asked for
95     token = strtok(NULL,".-");
96 
97     if (token) {
98         commits = (int16_t) atoi(token);
99         rev->d[0] = (commits>>8) | (commits<<8);
100 
101         // commit number we skip
102         token = strtok(NULL,".-");
103 
104     } else {
105         rev->d[0] = 0;
106     }
107 
108     // Any value of the optional parameter forces it to 1
109     if (token)
110         token = strtok(NULL,".-");
111 
112     rev->d[1] = (token != NULL) ? 1 : 0;
113 
114     free(s);
115     return 0;
116 }
117 
118 ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
119                              ipmi_request_t request, ipmi_response_t response,
120                              ipmi_data_len_t data_len, ipmi_context_t context)
121 {
122     ipmi_ret_t rc = IPMI_CC_OK;
123     const char  *objname = "/org/openbmc/inventory/system/chassis/motherboard/bmc";
124     const char  *iface   = "org.openbmc.InventoryItem";
125     char *ver = NULL;
126     char *busname = NULL;
127     int r;
128     rev_t rev = {0};
129     ipmi_device_id_t dev_id{};
130 
131     // Data length
132     *data_len = sizeof(dev_id);
133 
134     // From IPMI spec, controller that have different application commands, or different
135     // definitions of OEM fields, are expected to have different Device ID values.
136     // Set to 0 now.
137 
138     // Device Revision is set to 0 now.
139     // Bit7 identifies if device provide Device SDRs,  obmc don't have SDR,we use ipmi to
140     // simulate SDR, hence the value:
141     dev_id.revision = 0x80;
142 
143     // Firmware revision is already implemented, so get it from appropriate position.
144     r = mapper_get_service(bus, objname, &busname);
145     if (r < 0) {
146         fprintf(stderr, "Failed to get %s bus name: %s\n",
147                 objname, strerror(-r));
148         goto finish;
149     }
150     r = sd_bus_get_property_string(bus,busname,objname,iface,"version", NULL, &ver);
151     if ( r < 0 ) {
152         fprintf(stderr, "Failed to obtain version property: %s\n", strerror(-r));
153     } else {
154         r = convert_version(ver, &rev);
155         if( r >= 0 ) {
156             // bit7 identifies if the device is available, 0=normal operation,
157             // 1=device firmware, SDR update or self-initialization in progress.
158             // our SDR is normal working condition, so mask:
159             dev_id.fw[0] = 0x7F & rev.major;
160 
161             rev.minor = (rev.minor > 99 ? 99 : rev.minor);
162             dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
163             memcpy(&dev_id.aux, rev.d, 4);
164         }
165     }
166 
167     // IPMI Spec verison 2.0
168     dev_id.ipmi_ver = 2;
169 
170     // Additional device Support.
171     // List the 'logical device' commands and functions that the controller supports
172     // that are in addition to the mandatory IPM and Application commands.
173     // [7] Chassis Device (device functions as chassis device per ICMB spec.)
174     // [6] Bridge (device responds to Bridge NetFn commands)
175     // [5] IPMB Event Generator
176     // [4] IPMB Event Receiver
177     // [3] FRU Inventory Device
178     // [2] SEL Device
179     // [1] SDR Repository Device
180     // [0] Sensor Device
181     // We support FRU/SEL/Sensor now:
182     dev_id.addn_dev_support = 0x8D;
183 
184     // This value is the IANA number assigned to "IBM Platform Firmware
185     // Division", which is also used by our service processor.  We may want
186     // a different number or at least a different version?
187     dev_id.manuf_id[0] = 0x41;
188     dev_id.manuf_id[1] = 0xA7;
189     dev_id.manuf_id[2] = 0x00;
190 
191     // Witherspoon's product ID is hardcoded to 4F42(ASCII 'OB').
192     // TODO: openbmc/openbmc#495
193     dev_id.prod_id[0] = 0x4F;
194     dev_id.prod_id[1] = 0x42;
195 
196     // Pack the actual response
197     memcpy(response, &dev_id, *data_len);
198 finish:
199     free(busname);
200     free(ver);
201     return rc;
202 }
203 
204 ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
205                              ipmi_request_t request, ipmi_response_t response,
206                              ipmi_data_len_t data_len, ipmi_context_t context)
207 {
208     ipmi_ret_t rc = IPMI_CC_OK;
209 
210     // Byte 2:
211     //  55h - No error.
212     //  56h - Self Test funciton not implemented in this controller.
213     //  57h - Corrupted or inaccesssible data or devices.
214     //  58h - Fatal hardware error.
215     //  FFh - reserved.
216     //  all other: Device-specific 'internal failure'.
217     //  Byte 3:
218     //      For byte 2 = 55h, 56h, FFh:     00h
219     //      For byte 2 = 58h, all other:    Device-specific
220     //      For byte 2 = 57h:   self-test error bitfield.
221     //      Note: returning 57h does not imply that all test were run.
222     //      [7] 1b = Cannot access SEL device.
223     //      [6] 1b = Cannot access SDR Repository.
224     //      [5] 1b = Cannot access BMC FRU device.
225     //      [4] 1b = IPMB signal lines do not respond.
226     //      [3] 1b = SDR Repository empty.
227     //      [2] 1b = Internal Use Area of BMC FRU corrupted.
228     //      [1] 1b = controller update 'boot block' firmware corrupted.
229     //      [0] 1b = controller operational firmware corrupted.
230 
231     char selftestresults[2] = {0};
232 
233     *data_len = 2;
234 
235     selftestresults[0] = 0x56;
236     selftestresults[1] = 0;
237 
238     memcpy(response, selftestresults, *data_len);
239 
240     return rc;
241 }
242 
243 ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
244                              ipmi_request_t request, ipmi_response_t response,
245                              ipmi_data_len_t data_len, ipmi_context_t context)
246 {
247     const char  *objname = "/org/openbmc/control/chassis0";
248     const char  *iface = "org.freedesktop.DBus.Properties";
249     const char  *chassis_iface = "org.openbmc.control.Chassis";
250     sd_bus_message *reply = NULL;
251     sd_bus_error error = SD_BUS_ERROR_NULL;
252     int r = 0;
253     char *uuid = NULL;
254     char *busname = NULL;
255 
256     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
257     // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte order
258     // Ex: 0x2332fc2c40e66298e511f2782395a361
259 
260     const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
261     uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
262     int resp_loc = resp_size-1; // Point resp end of array to save in reverse order
263     int i = 0;
264     char *tokptr = NULL;
265     char *id_octet = NULL;
266 
267     // Status code.
268     ipmi_ret_t rc = IPMI_CC_OK;
269     *data_len = 0;
270 
271     printf("IPMI GET DEVICE GUID\n");
272 
273     // Call Get properties method with the interface and property name
274     r = mapper_get_service(bus, objname, &busname);
275     if (r < 0) {
276         fprintf(stderr, "Failed to get %s bus name: %s\n",
277                 objname, strerror(-r));
278         goto finish;
279     }
280     r = sd_bus_call_method(bus,busname,objname,iface,
281                            "Get",&error, &reply, "ss",
282                            chassis_iface, "uuid");
283     if (r < 0)
284     {
285         fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
286         rc = IPMI_CC_UNSPECIFIED_ERROR;
287         goto finish;
288     }
289 
290     r = sd_bus_message_read(reply, "v", "s", &uuid);
291     if (r < 0 || uuid == NULL)
292     {
293         fprintf(stderr, "Failed to get a response: %s", strerror(-r));
294         rc = IPMI_CC_RESPONSE_ERROR;
295         goto finish;
296     }
297 
298     // Traverse the UUID
299     id_octet = strtok_r(uuid, "-", &tokptr); // Get the UUID octects separated by dash
300 
301     if (id_octet == NULL)
302     {
303         // Error
304         fprintf(stderr, "Unexpected UUID format: %s", uuid);
305         rc = IPMI_CC_RESPONSE_ERROR;
306         goto finish;
307     }
308 
309     while (id_octet != NULL)
310     {
311         // Calculate the octet string size since it varies
312         // Divide it by 2 for the array size since 1 byte is built from 2 chars
313         int tmp_size = strlen(id_octet)/2;
314 
315         for(i = 0; i < tmp_size; i++)
316         {
317             char tmp_array[3] = {0}; // Holder of the 2 chars that will become a byte
318             strncpy(tmp_array, id_octet, 2); // 2 chars at a time
319 
320             int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
321             memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1); // Copy end to first
322             resp_loc--;
323             id_octet+=2; // Finished with the 2 chars, advance
324         }
325         id_octet=strtok_r(NULL, "-", &tokptr); // Get next octet
326     }
327 
328     // Data length
329     *data_len = resp_size;
330 
331     // Pack the actual response
332     memcpy(response, &resp_uuid, *data_len);
333 
334 finish:
335     sd_bus_error_free(&error);
336     reply = sd_bus_message_unref(reply);
337     free(busname);
338 
339     return rc;
340 }
341 
342 ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
343                              ipmi_request_t request, ipmi_response_t response,
344                              ipmi_data_len_t data_len, ipmi_context_t context)
345 {
346     printf("Handling Netfn:[0x%X], Cmd:[0x%X]\n",netfn,cmd);
347 
348     // Status code.
349     ipmi_ret_t rc = IPMI_CC_OK;
350 
351     // Per IPMI 2.0 spec, the input and output buffer size must be the max
352     // buffer size minus one byte to allocate space for the length byte.
353     uint8_t str[] = {0x01, MAX_IPMI_BUFFER-1, MAX_IPMI_BUFFER-1, 0x0A, 0x01};
354 
355     // Data length
356     *data_len = sizeof(str);
357 
358     // Pack the actual response
359     memcpy(response, &str, *data_len);
360 
361     return rc;
362 }
363 
364 
365 struct set_wd_data_t {
366     uint8_t t_use;
367     uint8_t t_action;
368     uint8_t preset;
369     uint8_t flags;
370     uint8_t ls;
371     uint8_t ms;
372 }  __attribute__ ((packed));
373 
374 
375 
376 ipmi_ret_t ipmi_app_set_watchdog(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
377                              ipmi_request_t request, ipmi_response_t response,
378                              ipmi_data_len_t data_len, ipmi_context_t context)
379 {
380     const char  *objname = "/xyz/openbmc_project/watchdog/host0";
381     const char  *iface = "xyz.openbmc_project.State.Watchdog";
382     const char  *property_iface = "org.freedesktop.DBus.Properties";
383     sd_bus_message *reply = NULL;
384     sd_bus_error error = SD_BUS_ERROR_NULL;
385     int r = 0;
386 
387     set_wd_data_t *reqptr = (set_wd_data_t*) request;
388     uint16_t timer = 0;
389 
390     // Making this uint64_t to match with provider
391     uint64_t timer_ms = 0;
392     char *busname = NULL;
393     *data_len = 0;
394 
395     // Get number of 100ms intervals
396     timer = (((uint16_t)reqptr->ms) << 8) + reqptr->ls;
397     // Get timer value in ms
398     timer_ms = timer * 100;
399 
400     printf("WATCHDOG SET Timer:[0x%X] 100ms intervals\n",timer);
401 
402     // Get bus name
403     r = mapper_get_service(bus, objname, &busname);
404     if (r < 0) {
405         fprintf(stderr, "Failed to get %s bus name: %s\n",
406                 objname, strerror(-r));
407         goto finish;
408     }
409 
410     // Disable watchdog if running
411     r = sd_bus_call_method(bus, busname, objname, property_iface,
412                            "Set", &error, &reply, "ssv",
413                            iface, "Enabled", "b", false);
414     if(r < 0) {
415         fprintf(stderr, "Failed to disable Watchdog: %s\n",
416                     strerror(-r));
417         goto finish;
418     }
419 
420     if (reqptr->t_use & 0x40)
421     {
422         sd_bus_error_free(&error);
423         reply = sd_bus_message_unref(reply);
424 
425         // Now Enable Watchdog
426         r = sd_bus_call_method(bus, busname, objname, property_iface,
427                                "Set", &error, &reply, "ssv",
428                                iface, "Enabled", "b", true);
429         if(r < 0) {
430             fprintf(stderr, "Failed to Enable Watchdog: %s\n",
431                     strerror(-r));
432             goto finish;
433         }
434 
435         // Set watchdog timer
436         r = sd_bus_call_method(bus, busname, objname, property_iface,
437                                "Set", &error, &reply, "ssv",
438                                iface, "TimeRemaining", "t", timer_ms);
439         if(r < 0) {
440             fprintf(stderr, "Failed to set new expiration time: %s\n",
441                     strerror(-r));
442             goto finish;
443         }
444     }
445 
446 finish:
447     sd_bus_error_free(&error);
448     reply = sd_bus_message_unref(reply);
449     free(busname);
450 
451     return (r < 0) ? -1 : IPMI_CC_OK;
452 }
453 
454 
455 ipmi_ret_t ipmi_app_reset_watchdog(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
456                              ipmi_request_t request, ipmi_response_t response,
457                              ipmi_data_len_t data_len, ipmi_context_t context)
458 {
459     const char  *objname = "/xyz/openbmc_project/watchdog/host0";
460     const char  *iface = "xyz.openbmc_project.State.Watchdog";
461     const char  *property_iface = "org.freedesktop.DBus.Properties";
462     sd_bus_message *reply = NULL;
463     sd_bus_error error = SD_BUS_ERROR_NULL;
464     int r = 0;
465     char *busname = NULL;
466 
467     // Current time interval that is set in watchdog.
468     uint64_t interval = 0;
469 
470     // Status code.
471     ipmi_ret_t rc = IPMI_CC_OK;
472     *data_len = 0;
473 
474     printf("WATCHDOG RESET\n");
475     // Get bus name
476     r = mapper_get_service(bus, objname, &busname);
477     if (r < 0) {
478         fprintf(stderr, "Failed to get %s bus name: %s\n",
479                 objname, strerror(-r));
480         goto finish;
481     }
482 
483     // Get the current interval and set it back.
484     r = sd_bus_call_method(bus, busname, objname, property_iface,
485                            "Get", &error, &reply, "ss",
486                            iface, "Interval");
487 
488     if(r < 0) {
489         fprintf(stderr, "Failed to get current Interval msg: %s\n",
490                 strerror(-r));
491         goto finish;
492     }
493 
494     // Now extract the value
495     r = sd_bus_message_read(reply, "v", "t", &interval);
496     if (r < 0) {
497         fprintf(stderr, "Failed to read current interval: %s\n",
498                 strerror(-r));
499         goto finish;
500     }
501 
502     sd_bus_error_free(&error);
503     reply = sd_bus_message_unref(reply);
504 
505     // Set watchdog timer
506     r = sd_bus_call_method(bus, busname, objname, property_iface,
507                            "Set", &error, &reply, "ssv",
508                            iface, "TimeRemaining", "t", interval);
509     if(r < 0) {
510         fprintf(stderr, "Failed to refresh the timer: %s\n",
511                 strerror(-r));
512         goto finish;
513     }
514 
515 finish:
516     sd_bus_error_free(&error);
517     reply = sd_bus_message_unref(reply);
518     free(busname);
519 
520     return rc;
521 }
522 
523 extern struct ChannelConfig_t channelConfig;
524 
525 ipmi_ret_t ipmi_set_channel_access(ipmi_netfn_t netfn,
526                                    ipmi_cmd_t cmd,
527                                    ipmi_request_t request,
528                                    ipmi_response_t response,
529                                    ipmi_data_len_t data_len,
530                                    ipmi_context_t context)
531 {
532     ipmi_ret_t rc = IPMI_CC_OK;
533 
534     std::string ipaddress;
535     std::string gateway;
536     uint8_t prefix {};
537     uint32_t vlanID {};
538 
539     // Todo: parse the request data if needed.
540 
541     // Using Set Channel cmd to apply changes of Set Lan Cmd.
542     try
543     {
544 
545         sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
546 
547         log<level::INFO>("Network data from Cache",
548                          entry("PREFIX=%s", channelConfig.netmask.c_str()),
549                          entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
550                          entry("GATEWAY=%s", channelConfig.gateway.c_str()));
551 
552         auto systemObject = ipmi::getDbusObject(bus,
553                                  ipmi::network::SYSTEMCONFIG_INTERFACE,
554                                  ipmi::network::ROOT);
555 
556         // TODO Currently IPMI supports single interface,need to handle
557         // Multiple interface through
558         // https://github.com/openbmc/openbmc/issues/2138
559 
560         auto networkInterfaceObject = ipmi::getDbusObject(
561                     bus,
562                     ipmi::network::ETHERNET_INTERFACE,
563                     ipmi::network::ROOT,
564                     ipmi::network::INTERFACE);
565 
566 
567 
568         // check wthether user has given all the data
569         if (!channelConfig.ipaddr.empty() &&
570             !channelConfig.netmask.empty() &&
571             !channelConfig.gateway.empty())
572         {
573             //convert mask into prefix
574             ipaddress = channelConfig.ipaddr;
575             prefix = ipmi::network::toPrefix(AF_INET, channelConfig.netmask);
576             gateway = channelConfig.gateway;
577 
578             if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
579             {
580                 //get the first twelve bits which is vlan id
581                 //not interested in rest of the bits.
582                 vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
583                 channelConfig.vlanID = le32toh(channelConfig.vlanID);
584             }
585 
586         }
587         else
588         {
589             // We have partial filled cache so get the remaning
590             // info from the system.
591 
592             // gets the network data from the system as user has
593             // not given all the data then use the data fetched from the
594             // system but it is implementation dependent,IPMI spec doesn't
595             // force it.
596 
597             // if system is not having any ip object don't throw error,
598             try
599             {
600                 auto ipObjectInfo = ipmi::getDbusObject(bus,
601                         ipmi::network::IP_INTERFACE,
602                         ipmi::network::ROOT,
603                         ipmi::network::IP_TYPE);
604 
605                 auto properties = ipmi::getAllDbusProperties(bus,
606                         ipObjectInfo.second,
607                         ipObjectInfo.first,
608                         ipmi::network::IP_INTERFACE);
609 
610                 ipaddress = channelConfig.ipaddr.empty() ?
611                     std::move(properties["Address"].get<std::string>()) :
612                     channelConfig.ipaddr;
613 
614                 prefix = channelConfig.netmask.empty() ?
615                     properties["PrefixLength"].get<uint8_t>() :
616                     ipmi::network::toPrefix(AF_INET,
617                                             channelConfig.netmask);
618 
619                 if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
620                 {
621                     //get the first twelve bits which is vlan id
622                     //not interested in rest of the bits.
623                     vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
624                     channelConfig.vlanID = le32toh(channelConfig.vlanID);
625                 }
626                 else
627                 {
628                     vlanID = ipmi::network::getVLAN(ipObjectInfo.first);
629                 }
630 
631             }
632             catch (InternalFailure& e)
633             {
634                 log<level::INFO>("Failed to get IP object which matches",
635                         entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
636                         entry("MATCH=%s", ipmi::network::IP_TYPE));
637             }
638 
639             auto systemProperties = ipmi::getAllDbusProperties(
640                     bus,
641                     systemObject.second,
642                     systemObject.first,
643                     ipmi::network::SYSTEMCONFIG_INTERFACE);
644 
645             gateway = channelConfig.gateway.empty() ?
646                 std::move(systemProperties["DefaultGateway"].get<std::string>()) :
647                 channelConfig.gateway;
648 
649         }
650 
651         // Currently network manager doesn't support purging of all the
652         // ip addresses and the vlan interfaces from the parent interface,
653         // TODO once the support is there, will make the change here.
654         // https://github.com/openbmc/openbmc/issues/2141.
655 
656         // TODO Currently IPMI supports single interface,need to handle
657         // Multiple interface through
658         // https://github.com/openbmc/openbmc/issues/2138
659 
660         //delete all the vlan interfaces
661         //delete all the ipv4 addresses
662         ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
663                                    ipmi::network::VLAN_INTERFACE);
664         ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT,
665                                    ipmi::network::IP_INTERFACE,
666                                    ipmi::network::IP_TYPE);
667         if (vlanID)
668         {
669             ipmi::network::createVLAN(bus, ipmi::network::SERVICE,
670                                       ipmi::network::ROOT,
671                                       ipmi::network::INTERFACE, vlanID);
672 
673             networkInterfaceObject = ipmi::getDbusObject(
674                     bus,
675                     ipmi::network::VLAN_INTERFACE,
676                     ipmi::network::ROOT);
677         }
678 
679         ipmi::network::createIP(bus, networkInterfaceObject.second,
680                                 networkInterfaceObject.first,
681                                 ipv4Protocol, ipaddress, prefix);
682 
683         ipmi::setDbusProperty(bus, systemObject.second, systemObject.first,
684                               ipmi::network::SYSTEMCONFIG_INTERFACE,
685                               "DefaultGateway", gateway);
686 
687     }
688     catch (InternalFailure& e)
689     {
690         log<level::ERR>("Failed to set network data",
691                         entry("PREFIX=%d", prefix),
692                         entry("ADDRESS=%s", ipaddress),
693                         entry("GATEWAY=%s", gateway));
694 
695         commit<InternalFailure>();
696         rc = IPMI_CC_UNSPECIFIED_ERROR;
697     }
698 
699     channelConfig.clear();
700     return rc;
701 }
702 
703 
704 // ATTENTION: This ipmi function is very hardcoded on purpose
705 // OpenBMC does not fully support IPMI.  This command is useful
706 // to have around because it enables testing of interfaces with
707 // the IPMI tool.
708 #define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
709 // IPMI Table 6-2
710 #define IPMI_CHANNEL_TYPE_IPMB 1
711 // IPMI Table 6-3
712 #define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
713 
714 ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
715                              ipmi_request_t request, ipmi_response_t response,
716                              ipmi_data_len_t data_len, ipmi_context_t context)
717 {
718     ipmi_ret_t rc = IPMI_CC_OK;
719     uint8_t resp[] = {
720         1,
721         IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
722         IPMI_CHANNEL_TYPE_IPMB,
723         1,0x41,0xA7,0x00,0,0};
724     uint8_t *p = (uint8_t*) request;
725 
726     printf("IPMI APP GET CHANNEL INFO\n");
727 
728     // The supported channels numbers are 1 and 8.
729     // Channel Number E is used as way to identify the current channel
730     // that the command is being is received from.
731     if (*p == 0xe || *p == 1 || *p == 8) {
732 
733         *data_len = sizeof(resp);
734         memcpy(response, resp, *data_len);
735 
736     } else {
737         rc = IPMI_CC_PARM_OUT_OF_RANGE;
738         *data_len = 0;
739     }
740 
741     return rc;
742 }
743 
744 ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
745                               ipmi_request_t request, ipmi_response_t response,
746                               ipmi_data_len_t data_len, ipmi_context_t context)
747 {
748     printf("Handling WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
749 
750     // Status code.
751     ipmi_ret_t rc = IPMI_CC_INVALID;
752 
753     *data_len = strlen("THIS IS WILDCARD");
754 
755     // Now pack actual response
756     memcpy(response, "THIS IS WILDCARD", *data_len);
757 
758     return rc;
759 }
760 
761 void register_netfn_app_functions()
762 {
763     // <Get BT Interface Capabilities>
764     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_CAP_BIT);
765     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL, ipmi_app_get_bt_capabilities,
766                            PRIVILEGE_USER);
767 
768     // <Wildcard Command>
769     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_WILDCARD);
770     ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL, ipmi_app_wildcard_handler,
771                            PRIVILEGE_USER);
772 
773     // <Reset Watchdog Timer>
774     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_RESET_WD);
775     ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL, ipmi_app_reset_watchdog,
776                            PRIVILEGE_OPERATOR);
777 
778     // <Set Watchdog Timer>
779     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_SET_WD);
780     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL, ipmi_app_set_watchdog,
781                            PRIVILEGE_OPERATOR);
782 
783     // <Get Device ID>
784     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_DEVICE_ID);
785     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL, ipmi_app_get_device_id,
786                            PRIVILEGE_USER);
787 
788     // <Get Self Test Results>
789     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS);
790     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
791                     ipmi_app_get_self_test_results, PRIVILEGE_USER);
792 
793     // <Get Device GUID>
794     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID);
795     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL, ipmi_app_get_device_guid,
796                            PRIVILEGE_USER);
797 
798     // <Set ACPI Power State>
799     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_SET_ACPI);
800     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL, ipmi_app_set_acpi_power_state,
801                            PRIVILEGE_ADMIN);
802 
803     // <Set Channel Access>
804     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP,
805                                             IPMI_CMD_SET_CHAN_ACCESS);
806     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
807                                     ipmi_set_channel_access, PRIVILEGE_ADMIN);
808 
809     // <Get Channel Info Command>
810     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_CHAN_INFO);
811     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL, ipmi_app_channel_info,
812                            PRIVILEGE_USER);
813 
814     return;
815 }
816 
817 
818