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