1 #include "apphandler.h"
2 #include "app/channel.hpp"
3 #include "app/watchdog.hpp"
4 #include "host-ipmid/ipmid-api.h"
5 #include "ipmid.hpp"
6 #include "nlohmann/json.hpp"
7 #include "types.hpp"
8 #include "utils.hpp"
9 
10 #include <fstream>
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <systemd/sd-bus.h>
14 #include <mapper.h>
15 #include <array>
16 #include <vector>
17 #include <string>
18 #include <cstddef>
19 #include <experimental/filesystem>
20 
21 #include <arpa/inet.h>
22 #include "transporthandler.hpp"
23 
24 #include <phosphor-logging/log.hpp>
25 #include <phosphor-logging/elog-errors.hpp>
26 #include "xyz/openbmc_project/Common/error.hpp"
27 #include "xyz/openbmc_project/Software/Version/server.hpp"
28 #include "xyz/openbmc_project/Software/Activation/server.hpp"
29 
30 extern sd_bus *bus;
31 
32 constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
33 constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
34 constexpr auto bmc_guid_property = "UUID";
35 constexpr auto bmc_guid_len = 16;
36 
37 static constexpr auto redundancyIntf =
38     "xyz.openbmc_project.Software.RedundancyPriority";
39 static constexpr auto versionIntf =
40     "xyz.openbmc_project.Software.Version";
41 static constexpr auto activationIntf =
42     "xyz.openbmc_project.Software.Activation";
43 static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
44 
45 void register_netfn_app_functions() __attribute__((constructor));
46 
47 using namespace phosphor::logging;
48 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
49 using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
50 using Activation =
51     sdbusplus::xyz::openbmc_project::Software::server::Activation;
52 namespace fs = std::experimental::filesystem;
53 
54 // Offset in get device id command.
55 typedef struct
56 {
57    uint8_t id;
58    uint8_t revision;
59    uint8_t fw[2];
60    uint8_t ipmi_ver;
61    uint8_t addn_dev_support;
62    uint8_t manuf_id[3];
63    uint8_t prod_id[2];
64    uint8_t aux[4];
65 }__attribute__((packed)) ipmi_device_id_t;
66 
67 /**
68  * @brief Returns the Version info from primary s/w object
69  *
70  * Get the Version info from the active s/w object which is having high
71  * "Priority" value(a smaller number is a higher priority) and "Purpose"
72  * is "BMC" from the list of all s/w objects those are implementing
73  * RedundancyPriority interface from the given softwareRoot path.
74  *
75  * @return On success returns the Version info from primary s/w object.
76  *
77  */
78 std::string getActiveSoftwareVersionInfo()
79 {
80     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
81 
82     std::string revision{};
83     auto objectTree = ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf,
84                                               "");
85     if (objectTree.empty())
86     {
87         log<level::ERR>("No Obj has implemented the s/w redundancy interface",
88                         entry("INTERFACE=%s", redundancyIntf));
89         elog<InternalFailure>();
90     }
91 
92     auto objectFound = false;
93     for (auto& softObject : objectTree)
94     {
95         auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
96         auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
97 
98         auto minPriority = 0xFF;
99         for (const auto& objIter : objValueTree)
100         {
101             try
102             {
103                 auto& intfMap = objIter.second;
104                 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
105                 auto& versionProps = intfMap.at(versionIntf);
106                 auto& activationProps = intfMap.at(activationIntf);
107                 auto priority =
108                     redundancyPriorityProps.at("Priority").get<uint8_t>();
109                 auto purpose = versionProps.at("Purpose").get<std::string>();
110                 auto activation =
111                     activationProps.at("Activation").get<std::string>();
112                 auto version = versionProps.at("Version").get<std::string>();
113                 if ((Version::convertVersionPurposeFromString(purpose) ==
114                      Version::VersionPurpose::BMC) &&
115                     (Activation::convertActivationsFromString(activation) ==
116                      Activation::Activations::Active))
117                 {
118                     if (priority < minPriority)
119                     {
120                         minPriority = priority;
121                         objectFound = true;
122                         revision = std::move(version);
123                     }
124                 }
125             }
126             catch (const std::exception& e)
127             {
128                 log<level::ERR>(e.what());
129             }
130         }
131     }
132 
133     if (!objectFound)
134     {
135         log<level::ERR>("Could not found an BMC software Object");
136         elog<InternalFailure>();
137     }
138 
139     return revision;
140 }
141 
142 
143 ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
144                              ipmi_request_t request, ipmi_response_t response,
145                              ipmi_data_len_t data_len, ipmi_context_t context)
146 {
147     ipmi_ret_t rc = IPMI_CC_OK;
148     *data_len = 0;
149 
150     log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n");
151     return rc;
152 }
153 
154 typedef struct
155 {
156     char major;
157     char minor;
158     uint16_t d[2];
159 } rev_t;
160 
161 /* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will     */
162 /* return -1 if not in those formats, this routine knows how to parse       */
163 /* version = v0.6-19-gf363f61-dirty                                         */
164 /*            ^ ^ ^^          ^                                             */
165 /*            | |  |----------|-- additional details                        */
166 /*            | |---------------- Minor                                     */
167 /*            |------------------ Major                                     */
168 /* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715                        */
169 /*                ^ ^  ^^ ^                                                 */
170 /*                | |  |--|---------- additional details                    */
171 /*                | |---------------- Minor                                 */
172 /*                |------------------ Major                                 */
173 /* Additional details : If the option group exists it will force Auxiliary  */
174 /* Firmware Revision Information 4th byte to 1 indicating the build was     */
175 /* derived with additional edits                                            */
176 int convert_version(const char * p, rev_t *rev)
177 {
178     std::string s(p);
179     std::string token;
180     uint16_t commits;
181 
182     auto location  = s.find_first_of('v');
183     if (location != std::string::npos)
184     {
185         s = s.substr(location+1);
186     }
187 
188     if (!s.empty())
189     {
190         location = s.find_first_of(".");
191         if (location != std::string::npos)
192         {
193             rev->major = static_cast<char>(
194                     std::stoi(s.substr(0, location), 0, 16));
195             token = s.substr(location+1);
196         }
197 
198         if (!token.empty())
199         {
200             location = token.find_first_of(".-");
201             if (location != std::string::npos)
202             {
203                 rev->minor = static_cast<char>(
204                         std::stoi(token.substr(0, location), 0, 16));
205                 token = token.substr(location+1);
206             }
207         }
208 
209         // Capture the number of commits on top of the minor tag.
210         // I'm using BE format like the ipmi spec asked for
211         location = token.find_first_of(".-");
212         if (!token.empty())
213         {
214             commits = std::stoi(token.substr(0, location), 0, 16);
215             rev->d[0] = (commits>>8) | (commits<<8);
216 
217             // commit number we skip
218             location = token.find_first_of(".-");
219             if (location != std::string::npos)
220             {
221                 token = token.substr(location+1);
222             }
223         }
224         else {
225             rev->d[0] = 0;
226         }
227 
228         if (location != std::string::npos)
229         {
230             token = token.substr(location+1);
231         }
232 
233         // Any value of the optional parameter forces it to 1
234         location = token.find_first_of(".-");
235         if (location != std::string::npos)
236         {
237             token = token.substr(location+1);
238         }
239         commits = (!token.empty()) ? 1 : 0;
240 
241         //We do this operation to get this displayed in least significant bytes
242         //of ipmitool device id command.
243         rev->d[1] = (commits>>8) | (commits<<8);
244     }
245 
246     return 0;
247 }
248 
249 ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
250                              ipmi_request_t request, ipmi_response_t response,
251                              ipmi_data_len_t data_len, ipmi_context_t context)
252 {
253     ipmi_ret_t rc = IPMI_CC_OK;
254     int r = -1;
255     rev_t rev = {0};
256     static ipmi_device_id_t dev_id{};
257     static bool dev_id_initialized = false;
258     const char* filename = "/usr/share/ipmi-providers/dev_id.json";
259 
260     // Data length
261     *data_len = sizeof(dev_id);
262 
263     if (!dev_id_initialized)
264     {
265         try
266         {
267             auto version = getActiveSoftwareVersionInfo();
268             r = convert_version(version.c_str(), &rev);
269         }
270         catch (const std::exception& e)
271         {
272             log<level::ERR>(e.what());
273         }
274 
275         if( r >= 0 ) {
276             // bit7 identifies if the device is available
277             // 0=normal operation
278             // 1=device firmware, SDR update,
279             // or self-initialization in progress.
280             // our SDR is normal working condition, so mask:
281             dev_id.fw[0] = 0x7F & rev.major;
282 
283             rev.minor = (rev.minor > 99 ? 99 : rev.minor);
284             dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
285             memcpy(&dev_id.aux, rev.d, 4);
286         }
287 
288         // IPMI Spec version 2.0
289         dev_id.ipmi_ver = 2;
290 
291         std::ifstream dev_id_file(filename);
292         if (dev_id_file.is_open())
293         {
294             auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
295             if (!data.is_discarded())
296             {
297                 dev_id.id = data.value("id", 0);
298                 dev_id.revision = data.value("revision", 0);
299                 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
300                 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
301                 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
302                 dev_id.manuf_id[0] = data.value("manuf_id", 0);
303                 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
304                 dev_id.prod_id[0] = data.value("prod_id", 0);
305                 dev_id.aux[3] = data.value("aux", 0);
306                 dev_id.aux[2] = data.value("aux", 0) >> 8;
307                 dev_id.aux[1] = data.value("aux", 0) >> 16;
308                 dev_id.aux[0] = data.value("aux", 0) >> 24;
309 
310                 //Don't read the file every time if successful
311                 dev_id_initialized = true;
312             }
313             else
314             {
315                 log<level::ERR>("Device ID JSON parser failure");
316                 rc = IPMI_CC_UNSPECIFIED_ERROR;
317             }
318         }
319         else
320         {
321             log<level::ERR>("Device ID file not found");
322             rc = IPMI_CC_UNSPECIFIED_ERROR;
323         }
324     }
325 
326     // Pack the actual response
327     memcpy(response, &dev_id, *data_len);
328 
329     return rc;
330 }
331 
332 ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
333                              ipmi_request_t request, ipmi_response_t response,
334                              ipmi_data_len_t data_len, ipmi_context_t context)
335 {
336     ipmi_ret_t rc = IPMI_CC_OK;
337 
338     // Byte 2:
339     //  55h - No error.
340     //  56h - Self Test function not implemented in this controller.
341     //  57h - Corrupted or inaccesssible data or devices.
342     //  58h - Fatal hardware error.
343     //  FFh - reserved.
344     //  all other: Device-specific 'internal failure'.
345     //  Byte 3:
346     //      For byte 2 = 55h, 56h, FFh:     00h
347     //      For byte 2 = 58h, all other:    Device-specific
348     //      For byte 2 = 57h:   self-test error bitfield.
349     //      Note: returning 57h does not imply that all test were run.
350     //      [7] 1b = Cannot access SEL device.
351     //      [6] 1b = Cannot access SDR Repository.
352     //      [5] 1b = Cannot access BMC FRU device.
353     //      [4] 1b = IPMB signal lines do not respond.
354     //      [3] 1b = SDR Repository empty.
355     //      [2] 1b = Internal Use Area of BMC FRU corrupted.
356     //      [1] 1b = controller update 'boot block' firmware corrupted.
357     //      [0] 1b = controller operational firmware corrupted.
358 
359     char selftestresults[2] = {0};
360 
361     *data_len = 2;
362 
363     selftestresults[0] = 0x56;
364     selftestresults[1] = 0;
365 
366     memcpy(response, selftestresults, *data_len);
367 
368     return rc;
369 }
370 
371 ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
372                              ipmi_request_t request, ipmi_response_t response,
373                              ipmi_data_len_t data_len, ipmi_context_t context)
374 {
375     const char  *objname = "/org/openbmc/control/chassis0";
376     const char  *iface = "org.freedesktop.DBus.Properties";
377     const char  *chassis_iface = "org.openbmc.control.Chassis";
378     sd_bus_message *reply = NULL;
379     sd_bus_error error = SD_BUS_ERROR_NULL;
380     int r = 0;
381     char *uuid = NULL;
382     char *busname = NULL;
383 
384     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
385     // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
386     // order
387     // Ex: 0x2332fc2c40e66298e511f2782395a361
388 
389     const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
390     uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
391     // Point resp end of array to save in reverse order
392     int resp_loc = resp_size-1;
393     int i = 0;
394     char *tokptr = NULL;
395     char *id_octet = NULL;
396 
397     // Status code.
398     ipmi_ret_t rc = IPMI_CC_OK;
399     *data_len = 0;
400 
401     // Call Get properties method with the interface and property name
402     r = mapper_get_service(bus, objname, &busname);
403     if (r < 0) {
404         log<level::ERR>("Failed to get bus name",
405                         entry("BUS=%s", objname),
406                         entry("ERRNO=0x%X", -r));
407         goto finish;
408     }
409     r = sd_bus_call_method(bus,busname,objname,iface,
410                            "Get",&error, &reply, "ss",
411                            chassis_iface, "uuid");
412     if (r < 0)
413     {
414         log<level::ERR>("Failed to call Get Method",
415                         entry("ERRNO=0x%X", -r));
416         rc = IPMI_CC_UNSPECIFIED_ERROR;
417         goto finish;
418     }
419 
420     r = sd_bus_message_read(reply, "v", "s", &uuid);
421     if (r < 0 || uuid == NULL)
422     {
423         log<level::ERR>("Failed to get a response",
424                         entry("ERRNO=0x%X", -r));
425         rc = IPMI_CC_RESPONSE_ERROR;
426         goto finish;
427     }
428 
429     // Traverse the UUID
430     // Get the UUID octects separated by dash
431     id_octet = strtok_r(uuid, "-", &tokptr);
432 
433     if (id_octet == NULL)
434     {
435         // Error
436         log<level::ERR>("Unexpected UUID format",
437                         entry("UUID=%s", uuid));
438         rc = IPMI_CC_RESPONSE_ERROR;
439         goto finish;
440     }
441 
442     while (id_octet != NULL)
443     {
444         // Calculate the octet string size since it varies
445         // Divide it by 2 for the array size since 1 byte is built from 2 chars
446         int tmp_size = strlen(id_octet)/2;
447 
448         for(i = 0; i < tmp_size; i++)
449         {
450             // Holder of the 2 chars that will become a byte
451             char tmp_array[3] = {0};
452             strncpy(tmp_array, id_octet, 2); // 2 chars at a time
453 
454             int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
455             // Copy end to first
456             memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
457             resp_loc--;
458             id_octet+=2; // Finished with the 2 chars, advance
459         }
460         id_octet=strtok_r(NULL, "-", &tokptr); // Get next octet
461     }
462 
463     // Data length
464     *data_len = resp_size;
465 
466     // Pack the actual response
467     memcpy(response, &resp_uuid, *data_len);
468 
469 finish:
470     sd_bus_error_free(&error);
471     reply = sd_bus_message_unref(reply);
472     free(busname);
473 
474     return rc;
475 }
476 
477 ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
478                              ipmi_request_t request, ipmi_response_t response,
479                              ipmi_data_len_t data_len, ipmi_context_t context)
480 {
481 
482     // Status code.
483     ipmi_ret_t rc = IPMI_CC_OK;
484 
485     // Per IPMI 2.0 spec, the input and output buffer size must be the max
486     // buffer size minus one byte to allocate space for the length byte.
487     uint8_t str[] = {0x01, MAX_IPMI_BUFFER-1, MAX_IPMI_BUFFER-1, 0x0A, 0x01};
488 
489     // Data length
490     *data_len = sizeof(str);
491 
492     // Pack the actual response
493     memcpy(response, &str, *data_len);
494 
495     return rc;
496 }
497 
498 ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
499                               ipmi_request_t request, ipmi_response_t response,
500                               ipmi_data_len_t data_len, ipmi_context_t context)
501 {
502     // Status code.
503     ipmi_ret_t rc = IPMI_CC_INVALID;
504 
505     *data_len = strlen("THIS IS WILDCARD");
506 
507     // Now pack actual response
508     memcpy(response, "THIS IS WILDCARD", *data_len);
509 
510     return rc;
511 }
512 
513 ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
514                              ipmi_request_t request, ipmi_response_t response,
515                              ipmi_data_len_t data_len, ipmi_context_t context)
516 
517 {
518     ipmi_ret_t rc = IPMI_CC_OK;
519     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
520 
521     try
522     {
523         // Get the Inventory object implementing BMC interface
524         ipmi::DbusObjectInfo bmcObject =
525             ipmi::getDbusObject(bus, bmc_interface);
526 
527         // Read UUID property value from bmcObject
528         // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
529         auto variant = ipmi::getDbusProperty(
530                 bus, bmcObject.second, bmcObject.first, bmc_guid_interface,
531                 bmc_guid_property);
532         std::string guidProp = variant.get<std::string>();
533 
534         // Erase "-" characters from the property value
535         guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
536                 guidProp.end());
537 
538         auto guidPropLen = guidProp.length();
539         // Validate UUID data
540         // Divide by 2 as 1 byte is built from 2 chars
541         if ( (guidPropLen <=0) || ((guidPropLen/2) != bmc_guid_len) )
542 
543         {
544             log<level::ERR>("Invalid UUID property value",
545                     entry("UUID_LENGTH=%d", guidPropLen));
546             return IPMI_CC_RESPONSE_ERROR;
547         }
548 
549         // Convert data in RFC4122(MSB) format to LSB format
550         // Get 2 characters at a time as 1 byte is built from 2 chars and
551         // convert to hex byte
552         // TODO: Data printed for GUID command is not as per the
553         // GUID format defined in IPMI specification 2.0 section 20.8
554         // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
555         uint8_t respGuid[bmc_guid_len];
556         for (size_t i = 0, respLoc = (bmc_guid_len - 1);
557             i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
558         {
559             auto value = static_cast<uint8_t>(
560                     std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
561             respGuid[respLoc] = value;
562         }
563 
564         *data_len = bmc_guid_len;
565         memcpy(response, &respGuid, bmc_guid_len);
566     }
567     catch (const InternalFailure& e)
568     {
569         log<level::ERR>("Failed in reading BMC UUID property",
570                         entry("INTERFACE=%s", bmc_interface),
571                         entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
572                         entry("PROPERTY=%s", bmc_guid_property));
573         return IPMI_CC_UNSPECIFIED_ERROR;
574     }
575     return rc;
576 }
577 
578 void register_netfn_app_functions()
579 {
580     // <Get BT Interface Capabilities>
581     ipmi_register_callback(NETFUN_APP,
582                            IPMI_CMD_GET_CAP_BIT,
583                            NULL,
584                            ipmi_app_get_bt_capabilities,
585                            PRIVILEGE_USER);
586 
587     // <Wildcard Command>
588     ipmi_register_callback(NETFUN_APP,
589                            IPMI_CMD_WILDCARD,
590                            NULL,
591                            ipmi_app_wildcard_handler,
592                            PRIVILEGE_USER);
593 
594     // <Reset Watchdog Timer>
595     ipmi_register_callback(NETFUN_APP,
596                            IPMI_CMD_RESET_WD,
597                            NULL,
598                            ipmi_app_watchdog_reset,
599                            PRIVILEGE_OPERATOR);
600 
601     // <Set Watchdog Timer>
602     ipmi_register_callback(NETFUN_APP,
603                            IPMI_CMD_SET_WD,
604                            NULL,
605                            ipmi_app_watchdog_set,
606                            PRIVILEGE_OPERATOR);
607 
608     // <Get Watchdog Timer>
609     ipmi_register_callback(NETFUN_APP,
610                            IPMI_CMD_GET_WD,
611                            NULL,
612                            ipmi_app_watchdog_get,
613                            PRIVILEGE_OPERATOR);
614 
615     // <Get Device ID>
616     ipmi_register_callback(NETFUN_APP,
617                            IPMI_CMD_GET_DEVICE_ID,
618                            NULL,
619                            ipmi_app_get_device_id,
620                            PRIVILEGE_USER);
621 
622     // <Get Self Test Results>
623     ipmi_register_callback(NETFUN_APP,
624                            IPMI_CMD_GET_SELF_TEST_RESULTS,
625                            NULL,
626                            ipmi_app_get_self_test_results,
627                            PRIVILEGE_USER);
628 
629     // <Get Device GUID>
630     ipmi_register_callback(NETFUN_APP,
631                            IPMI_CMD_GET_DEVICE_GUID,
632                            NULL,
633                            ipmi_app_get_device_guid,
634                            PRIVILEGE_USER);
635 
636     // <Set ACPI Power State>
637     ipmi_register_callback(NETFUN_APP,
638                            IPMI_CMD_SET_ACPI,
639                            NULL,
640                            ipmi_app_set_acpi_power_state,
641                            PRIVILEGE_ADMIN);
642 
643     // <Get Channel Access>
644     ipmi_register_callback(NETFUN_APP,
645                            IPMI_CMD_GET_CHANNEL_ACCESS,
646                            NULL,
647                            ipmi_get_channel_access,
648                            PRIVILEGE_USER);
649 
650     // <Get Channel Info Command>
651     ipmi_register_callback(NETFUN_APP,
652                            IPMI_CMD_GET_CHAN_INFO,
653                            NULL,
654                            ipmi_app_channel_info,
655                            PRIVILEGE_USER);
656 
657     // <Get System GUID Command>
658     ipmi_register_callback(NETFUN_APP,
659                            IPMI_CMD_GET_SYS_GUID,
660                            NULL,
661                            ipmi_app_get_sys_guid,
662                            PRIVILEGE_USER);
663 
664     // <Get Channel Cipher Suites Command>
665     ipmi_register_callback(NETFUN_APP,
666                            IPMI_CMD_GET_CHAN_CIPHER_SUITES,
667                            NULL,
668                            getChannelCipherSuites,
669                            PRIVILEGE_CALLBACK);
670     return;
671 }
672 
673