1 /*
2 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/time.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <errno.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include <ctype.h>
47 #include <sys/time.h>
48 #include <limits.h>
49 #include <fcntl.h>
50
51 #include <termios.h>
52
53 #include <ipmitool/ipmi.h>
54 #include <ipmitool/ipmi_intf.h>
55 #include <ipmitool/helper.h>
56 #include <ipmitool/log.h>
57 #include <ipmitool/ipmi_sel.h>
58 #include <ipmitool/ipmi_sdr.h>
59 #include <ipmitool/ipmi_strings.h>
60 #include <ipmitool/ipmi_channel.h>
61 #include <ipmitool/ipmi_sunoem.h>
62 #include <ipmitool/ipmi_raw.h>
63
64 static const struct valstr sunoem_led_type_vals[] = {
65 { 0, "OK2RM" },
66 { 1, "SERVICE" },
67 { 2, "ACT" },
68 { 3, "LOCATE" },
69 { 0xFF, NULL },
70 };
71
72 static const struct valstr sunoem_led_mode_vals[] = {
73 { 0, "OFF" },
74 { 1, "ON" },
75 { 2, "STANDBY" },
76 { 3, "SLOW" },
77 { 4, "FAST" },
78 { 0xFF, NULL },
79 };
80
81 static const struct valstr sunoem_led_mode_optvals[] = {
82 { 0, "STEADY_OFF" },
83 { 1, "STEADY_ON" },
84 { 2, "STANDBY_BLINK" },
85 { 3, "SLOW_BLINK" },
86 { 4, "FAST_BLINK" },
87 { 0xFF, NULL },
88 };
89
90 #define SUNOEM_SUCCESS 1
91
92 #define IPMI_SUNOEM_GETFILE_VERSION {3,2,0,0}
93 #define IPMI_SUNOEM_GETBEHAVIOR_VERSION {3,2,0,0}
94
95 /*
96 * PRINT_NORMAL: print out the LED value as normal
97 * PRINT_ERROR: print out "na" for the LED value
98 */
99 typedef enum
100 {
101 PRINT_NORMAL = 0, PRINT_ERROR
102 } print_status_t;
103
104 int ret_get = 0;
105 int ret_set = 0;
106
107 static void
ipmi_sunoem_usage(void)108 ipmi_sunoem_usage(void)
109 {
110 lprintf(LOG_NOTICE, "Usage: sunoem <command> [option...]");
111 lprintf(LOG_NOTICE, "");
112 lprintf(LOG_NOTICE, "Commands:");
113 lprintf(LOG_NOTICE, " - cli [<command string> ...]");
114 lprintf(LOG_NOTICE, " Execute SP CLI commands.");
115 lprintf(LOG_NOTICE, "");
116 lprintf(LOG_NOTICE, " - led get [<sensor_id>] [ledtype]");
117 lprintf(LOG_NOTICE, " - Read status of LED found in Generic Device Locator.");
118 lprintf(LOG_NOTICE, "");
119 lprintf(LOG_NOTICE, " - led set <sensor_id> <led_mode> [led_type]");
120 lprintf(LOG_NOTICE, " - Set mode of LED found in Generic Device Locator.");
121 lprintf(LOG_NOTICE, " - You can pass 'all' as the <senso_rid> to change the LED mode of all sensors.");
122 lprintf(LOG_NOTICE, " - Use 'sdr list generic' command to get list of Generic");
123 lprintf(LOG_NOTICE, " - Devices that are controllable LEDs.");
124 lprintf(LOG_NOTICE, "");
125 lprintf(LOG_NOTICE, " - Required SIS LED Mode:");
126 lprintf(LOG_NOTICE, " OFF Off");
127 lprintf(LOG_NOTICE, " ON Steady On");
128 lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate");
129 lprintf(LOG_NOTICE, " SLOW 1HZ blink rate");
130 lprintf(LOG_NOTICE, " FAST 4HZ blink rate");
131 lprintf(LOG_NOTICE, "");
132 lprintf(LOG_NOTICE, " - Optional SIS LED Type:");
133 lprintf(LOG_NOTICE, " OK2RM OK to Remove");
134 lprintf(LOG_NOTICE, " SERVICE Service Required");
135 lprintf(LOG_NOTICE, " ACT Activity");
136 lprintf(LOG_NOTICE, " LOCATE Locate");
137 lprintf(LOG_NOTICE, "");
138 lprintf(LOG_NOTICE, " - nacname <ipmi_nac_name>");
139 lprintf(LOG_NOTICE, " - Returns the full nac name");
140 lprintf(LOG_NOTICE, "");
141 lprintf(LOG_NOTICE, " - ping NUMBER <q>");
142 lprintf(LOG_NOTICE, " - Send and Receive NUMBER (64 Byte) packets.");
143 lprintf(LOG_NOTICE, "");
144 lprintf(LOG_NOTICE, " - q - Quiet. Displays output at start and end");
145 lprintf(LOG_NOTICE, "");
146 lprintf(LOG_NOTICE, " - getval <target_name>");
147 lprintf(LOG_NOTICE, " - Returns the ILOM property value");
148 lprintf(LOG_NOTICE, "");
149 lprintf(LOG_NOTICE, " - setval <property name> <property value> <timeout>");
150 lprintf(LOG_NOTICE, " - Sets the ILOM property value");
151 lprintf(LOG_NOTICE, " - If timeout is not specified, the default is 5 sec.");
152 lprintf(LOG_NOTICE, " - NOTE: must be executed locally on host, not remotely over LAN!");
153 lprintf(LOG_NOTICE, "");
154 lprintf(LOG_NOTICE, " - sshkey del <user_id>");
155 lprintf(LOG_NOTICE, " - Delete ssh key for user id from authorized_keys,");
156 lprintf(LOG_NOTICE, " - view users with 'user list' command.");
157 lprintf(LOG_NOTICE, "");
158 lprintf(LOG_NOTICE, " - sshkey set <user_id> <id_rsa.pub>");
159 lprintf(LOG_NOTICE, " - Set ssh key for a userid into authorized_keys,");
160 lprintf(LOG_NOTICE, " - view users with 'user list' command.");
161 lprintf(LOG_NOTICE, "");
162 lprintf(LOG_NOTICE, " - version");
163 lprintf(LOG_NOTICE, " - Display the software version");
164 lprintf(LOG_NOTICE, "");
165 lprintf(LOG_NOTICE, " - nacname <ipmi_nac_name>");
166 lprintf(LOG_NOTICE, " - Returns the full nac name");
167 lprintf(LOG_NOTICE, "");
168 lprintf(LOG_NOTICE, " - getfile <file_string_id> <destination_file_name>");
169 lprintf(LOG_NOTICE, " - Copy file <file_string_id> to <destination_file_name>");
170 lprintf(LOG_NOTICE, "");
171 lprintf(LOG_NOTICE, " - File string ids:");
172 lprintf(LOG_NOTICE, " SSH_PUBKEYS");
173 lprintf(LOG_NOTICE, " DIAG_PASSED");
174 lprintf(LOG_NOTICE, " DIAG_FAILED");
175 lprintf(LOG_NOTICE, " DIAG_END_TIME");
176 lprintf(LOG_NOTICE, " DIAG_INVENTORY");
177 lprintf(LOG_NOTICE, " DIAG_TEST_LOG");
178 lprintf(LOG_NOTICE, " DIAG_START_TIME");
179 lprintf(LOG_NOTICE, " DIAG_UEFI_LOG");
180 lprintf(LOG_NOTICE, " DIAG_TEST_LOG");
181 lprintf(LOG_NOTICE, " DIAG_LAST_LOG");
182 lprintf(LOG_NOTICE, " DIAG_LAST_CMD");
183 lprintf(LOG_NOTICE, "");
184 lprintf(LOG_NOTICE, " - getbehavior <behavior_string_id>");
185 lprintf(LOG_NOTICE, " - Test if ILOM behavior is enabled");
186 lprintf(LOG_NOTICE, "");
187 lprintf(LOG_NOTICE, " - Behavior string ids:");
188 lprintf(LOG_NOTICE, " SUPPORTS_SIGNED_PACKAGES");
189 lprintf(LOG_NOTICE, " REQUIRES_SIGNED_PACKAGES");
190 lprintf(LOG_NOTICE, "");
191 }
192
193 #define SUNOEM_FAN_MODE_AUTO 0x00
194 #define SUNOEM_FAN_MODE_MANUAL 0x01
195
196 static void
__sdr_list_empty(struct sdr_record_list * head)197 __sdr_list_empty(struct sdr_record_list * head)
198 {
199 struct sdr_record_list * e, *f;
200 for (e = head; e != NULL; e = f) {
201 f = e->next;
202 free(e);
203 }
204 head = NULL;
205 }
206
207 /*
208 * led_print
209 * Print out the led name and the state, if stat is PRINT_NORMAL.
210 * Otherwise, print out the led name and "na".
211 * The state parameter is not referenced if stat is not PRINT_NORMAL.
212 */
213 static void
led_print(const char * name,print_status_t stat,uint8_t state)214 led_print(const char * name, print_status_t stat, uint8_t state)
215 {
216 const char *theValue;
217
218 if (stat == PRINT_NORMAL) {
219 theValue = val2str(state, sunoem_led_mode_vals);
220 } else {
221 theValue = "na";
222 }
223
224 if (csv_output) {
225 printf("%s,%s\n", name, theValue);
226 } else {
227 printf("%-16s | %s\n", name, theValue);
228 }
229 }
230
231 #define CC_NORMAL 0x00
232 #define CC_PARAM_OUT_OF_RANGE 0xc9
233 #define CC_DEST_UNAVAILABLE 0xd3
234 #define CC_UNSPECIFIED_ERR 0xff
235 #define CC_INSUFFICIENT_PRIVILEGE 0xd4
236 #define CC_INV_CMD 0xc1
237 #define CC_INV_DATA_FIELD 0xcc
238
239 /*
240 * sunoem_led_get(....)
241 *
242 * OUTPUT:
243 * SUNOEM_EC_INVALID_ARG if dev is NULL,
244 * SUNOEM_EC_BMC_NOT_RESPONDING if no reply is obtained from BMC,
245 * SUNOEM_EC_BMC_CCODE_NONZERO if completion code is nonzero,
246 * SUNOEM_EC_SUCCESS otherwise.
247 */
248 static sunoem_ec_t
sunoem_led_get(struct ipmi_intf * intf,struct sdr_record_generic_locator * dev,int ledtype,struct ipmi_rs ** loc_rsp)249 sunoem_led_get(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev,
250 int ledtype, struct ipmi_rs **loc_rsp)
251 {
252 struct ipmi_rs * rsp;
253 struct ipmi_rq req;
254 uint8_t rqdata[7];
255 int rqdata_len;
256
257 if (dev == NULL) {
258 *loc_rsp = NULL;
259 return (SUNOEM_EC_INVALID_ARG);
260 }
261
262 rqdata[0] = dev->dev_slave_addr;
263 if (ledtype == 0xFF)
264 rqdata[1] = dev->oem;
265 else
266 rqdata[1] = ledtype;
267
268 rqdata[2] = dev->dev_access_addr;
269 rqdata[3] = dev->oem;
270 rqdata[4] = dev->entity.id;
271 rqdata[5] = dev->entity.instance;
272 rqdata[6] = 0;
273 rqdata_len = 7;
274
275 req.msg.netfn = IPMI_NETFN_SUNOEM;
276 req.msg.cmd = IPMI_SUNOEM_LED_GET;
277 req.msg.lun = dev->lun;
278 req.msg.data = rqdata;
279 req.msg.data_len = rqdata_len;
280
281 rsp = intf->sendrecv(intf, &req);
282 /*
283 * Just return NULL if there was
284 * an error.
285 */
286 if (rsp == NULL) {
287 *loc_rsp = NULL;
288 return (SUNOEM_EC_BMC_NOT_RESPONDING);
289 } else if (rsp->ccode > 0) {
290 *loc_rsp = rsp;
291 return (SUNOEM_EC_BMC_CCODE_NONZERO);
292 } else {
293 *loc_rsp = rsp;
294 return (SUNOEM_EC_SUCCESS);
295 }
296 }
297
298 static struct ipmi_rs *
sunoem_led_set(struct ipmi_intf * intf,struct sdr_record_generic_locator * dev,int ledtype,int ledmode)299 sunoem_led_set(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev,
300 int ledtype, int ledmode)
301 {
302 struct ipmi_rs * rsp;
303 struct ipmi_rq req;
304 uint8_t rqdata[9];
305 int rqdata_len;
306
307 if (dev == NULL)
308 return NULL;
309
310 rqdata[0] = dev->dev_slave_addr;
311
312 if (ledtype == 0xFF)
313 rqdata[1] = dev->oem;
314 else
315 rqdata[1] = ledtype;
316
317 rqdata[2] = dev->dev_access_addr;
318 rqdata[3] = dev->oem;
319 rqdata[4] = ledmode;
320 rqdata[5] = dev->entity.id;
321 rqdata[6] = dev->entity.instance;
322 rqdata[7] = 0;
323 rqdata[8] = 0;
324 rqdata_len = 9;
325
326 req.msg.netfn = IPMI_NETFN_SUNOEM;
327 req.msg.cmd = IPMI_SUNOEM_LED_SET;
328 req.msg.lun = dev->lun;
329 req.msg.data = rqdata;
330 req.msg.data_len = rqdata_len;
331
332 rsp = intf->sendrecv(intf, &req);
333 if (rsp == NULL) {
334 lprintf(LOG_ERR, "Sun OEM Set LED command failed.");
335 return NULL;
336 } else if (rsp->ccode > 0) {
337 lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s",
338 val2str(rsp->ccode, completion_code_vals));
339 return NULL;
340 }
341
342 return (rsp);
343 }
344
345 static void
sunoem_led_get_byentity(struct ipmi_intf * intf,uint8_t entity_id,uint8_t entity_inst,int ledtype)346 sunoem_led_get_byentity(struct ipmi_intf * intf, uint8_t entity_id,
347 uint8_t entity_inst, int ledtype)
348 {
349 struct ipmi_rs * rsp;
350 struct sdr_record_list *elist, *e;
351 struct entity_id entity;
352 sunoem_ec_t res;
353
354 if (entity_id == 0)
355 return;
356
357 /* lookup sdrs with this entity */
358 memset(&entity, 0, sizeof(struct entity_id));
359 entity.id = entity_id;
360 entity.instance = entity_inst;
361
362 elist = ipmi_sdr_find_sdr_byentity(intf, &entity);
363
364 if (elist == NULL)
365 ret_get = -1;
366
367 /* for each generic sensor get its led state */
368 for (e = elist; e != NULL; e = e->next) {
369 if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
370 continue;
371
372 res = sunoem_led_get(intf, e->record.genloc, ledtype, &rsp);
373
374 if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
375 led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL,
376 rsp->data[0]);
377 } else {
378 led_print((const char *) e->record.genloc->id_string, PRINT_ERROR,
379 0);
380 if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp
381 || rsp->ccode != CC_DEST_UNAVAILABLE) {
382 ret_get = -1;
383 }
384 }
385 }
386 __sdr_list_empty(elist);
387 }
388
389 static void
sunoem_led_set_byentity(struct ipmi_intf * intf,uint8_t entity_id,uint8_t entity_inst,int ledtype,int ledmode)390 sunoem_led_set_byentity(struct ipmi_intf * intf, uint8_t entity_id,
391 uint8_t entity_inst, int ledtype, int ledmode)
392 {
393 struct ipmi_rs * rsp;
394 struct sdr_record_list *elist, *e;
395 struct entity_id entity;
396
397 if (entity_id == 0)
398 return;
399
400 /* lookup sdrs with this entity */
401 memset(&entity, 0, sizeof(struct entity_id));
402 entity.id = entity_id;
403 entity.instance = entity_inst;
404
405 elist = ipmi_sdr_find_sdr_byentity(intf, &entity);
406
407 if (elist == NULL)
408 ret_set = -1;
409
410 /* for each generic sensor set its led state */
411 for (e = elist; e != NULL; e = e->next) {
412
413 if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
414 continue;
415
416 rsp = sunoem_led_set(intf, e->record.genloc, ledtype, ledmode);
417 if (rsp && rsp->data_len == 0) {
418 led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL,
419 ledmode);
420 } else if (rsp == NULL) {
421 ret_set = -1;
422 }
423 }
424
425 __sdr_list_empty(elist);
426 }
427
428 /*
429 * IPMI Request Data: 5 bytes
430 *
431 * [byte 0] devAddr Value from the "Device Slave Address" field in
432 * LED's Generic Device Locator record in the SDR
433 * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
434 * [byte 2] ctrlrAddr Controller address; value from the "Device
435 * Access Address" field, 0x20 if the LED is local
436 * [byte 3] hwInfo The OEM field from the SDR record
437 * [byte 4] force 1 = directly access the device
438 * 0 = go thru its controller
439 * Ignored if LED is local
440 *
441 * The format below is for Sun Blade Modular systems only
442 * [byte 4] entityID The entityID field from the SDR record
443 * [byte 5] entityIns The entityIns field from the SDR record
444 * [byte 6] force 1 = directly access the device
445 * 0 = go thru its controller
446 * Ignored if LED is local
447 */
448 static int
ipmi_sunoem_led_get(struct ipmi_intf * intf,int argc,char ** argv)449 ipmi_sunoem_led_get(struct ipmi_intf * intf, int argc, char ** argv)
450 {
451 struct ipmi_rs * rsp;
452 struct sdr_record_list *sdr;
453 struct sdr_record_list *alist, *a;
454 struct sdr_record_entity_assoc *assoc;
455 int ledtype = 0xFF;
456 int i;
457 sunoem_ec_t res;
458
459 /*
460 * sunoem led/sbled get <id> [type]
461 */
462
463 if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
464 ipmi_sunoem_usage();
465 return (0);
466 }
467
468 if (argc > 1) {
469 ledtype = str2val(argv[1], sunoem_led_type_vals);
470 if (ledtype == 0xFF)
471 lprintf(LOG_ERR,
472 "Unknow ledtype, will use data from the SDR oem field");
473 }
474
475 if (strncasecmp(argv[0], "all", 3) == 0) {
476 /* do all generic sensors */
477 alist = ipmi_sdr_find_sdr_bytype(intf,
478 SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
479
480 if (alist == NULL)
481 return (-1);
482
483 for (a = alist; a != NULL; a = a->next) {
484 if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
485 continue;
486 if (a->record.genloc->entity.logical)
487 continue;
488
489 res = sunoem_led_get(intf, a->record.genloc, ledtype, &rsp);
490
491 if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
492 led_print((const char *) a->record.genloc->id_string,
493 PRINT_NORMAL, rsp->data[0]);
494 } else {
495 led_print((const char *) a->record.genloc->id_string,
496 PRINT_ERROR, 0);
497 if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp ||
498 rsp->ccode != CC_DEST_UNAVAILABLE) {
499 ret_get = -1;
500 }
501 }
502 }
503 __sdr_list_empty(alist);
504
505 if (ret_get == -1)
506 return (-1);
507
508 return (0);
509 }
510
511 /* look up generic device locator record in SDR */
512 sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]);
513
514 if (sdr == NULL) {
515 lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
516 return (-1);
517 }
518
519 if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
520 lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type);
521 return (-1);
522 }
523
524 if (!sdr->record.genloc->entity.logical) {
525 /*
526 * handle physical entity
527 */
528
529 res = sunoem_led_get(intf, sdr->record.genloc, ledtype, &rsp);
530
531 if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
532 led_print((const char *) sdr->record.genloc->id_string,
533 PRINT_NORMAL, rsp->data[0]);
534
535 } else {
536 led_print((const char *) sdr->record.genloc->id_string, PRINT_ERROR,
537 0);
538 if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp
539 || rsp->ccode != CC_DEST_UNAVAILABLE) {
540 ret_get = -1;
541 }
542 }
543
544 if (ret_get == -1)
545 return (-1);
546
547 return (0);
548 }
549
550 /*
551 * handle logical entity for LED grouping
552 */
553
554 lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
555
556 /* get entity assoc records */
557 alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC);
558
559 if (alist == NULL)
560 return (-1);
561
562 for (a = alist; a != NULL; a = a->next) {
563 if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC)
564 continue;
565 assoc = a->record.entassoc;
566 if (assoc == NULL)
567 continue;
568
569 /* check that the entity id/instance matches our generic record */
570 if (assoc->entity.id != sdr->record.genloc->entity.id
571 || assoc->entity.instance
572 != sdr->record.genloc->entity.instance)
573 continue;
574
575 if (assoc->flags.isrange) {
576 /*
577 * handle ranged entity associations
578 *
579 * the test for non-zero entity id is handled in
580 * sunoem_led_get_byentity()
581 */
582
583 /* first range set - id 1 and 2 must be equal */
584 if (assoc->entity_id_1 == assoc->entity_id_2)
585 for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
586 sunoem_led_get_byentity(intf, assoc->entity_id_1, i,
587 ledtype);
588
589 /* second range set - id 3 and 4 must be equal */
590 if (assoc->entity_id_3 == assoc->entity_id_4)
591 for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
592 sunoem_led_get_byentity(intf, assoc->entity_id_3, i,
593 ledtype);
594 } else {
595 /*
596 * handle entity list
597 */
598 sunoem_led_get_byentity(intf, assoc->entity_id_1,
599 assoc->entity_inst_1, ledtype);
600 sunoem_led_get_byentity(intf, assoc->entity_id_2,
601 assoc->entity_inst_2, ledtype);
602 sunoem_led_get_byentity(intf, assoc->entity_id_3,
603 assoc->entity_inst_3, ledtype);
604 sunoem_led_get_byentity(intf, assoc->entity_id_4,
605 assoc->entity_inst_4, ledtype);
606 }
607 }
608
609 __sdr_list_empty(alist);
610
611 if (ret_get == -1)
612 return (-1);
613
614 return (0);
615 }
616
617 /*
618 * IPMI Request Data: 7 bytes
619 *
620 * [byte 0] devAddr Value from the "Device Slave Address" field in
621 * LED's Generic Device Locator record in the SDR
622 * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
623 * [byte 2] ctrlrAddr Controller address; value from the "Device
624 * Access Address" field, 0x20 if the LED is local
625 * [byte 3] hwInfo The OEM field from the SDR record
626 * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
627 * [byte 5] force TRUE - directly access the device
628 * FALSE - go thru its controller
629 * Ignored if LED is local
630 * [byte 6] role Used by BMC for authorization purposes
631 *
632 * The format below is for Sun Blade Modular systems only
633 * [byte 5] entityID The entityID field from the SDR record
634 * [byte 6] entityIns The entityIns field from the SDR record
635 * [byte 7] force TRUE - directly access the device
636 * FALSE - go thru its controller
637 * Ignored if LED is local
638 * [byte 8] role Used by BMC for authorization purposes
639 *
640 *
641 * IPMI Response Data: 1 byte
642 *
643 * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
644 */
645
646 static int
ipmi_sunoem_led_set(struct ipmi_intf * intf,int argc,char ** argv)647 ipmi_sunoem_led_set(struct ipmi_intf * intf, int argc, char ** argv)
648 {
649 struct ipmi_rs * rsp;
650 struct sdr_record_list *sdr;
651 struct sdr_record_list *alist, *a;
652 struct sdr_record_entity_assoc *assoc;
653 int ledmode;
654 int ledtype = 0xFF;
655 int i;
656
657 /*
658 * sunoem led/sbled set <id> <mode> [type]
659 */
660
661 if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
662 ipmi_sunoem_usage();
663 return (0);
664 }
665
666 ledmode = str2val(argv[1], sunoem_led_mode_vals);
667 if (ledmode == 0xFF) {
668 ledmode = str2val(argv[1], sunoem_led_mode_optvals);
669 if (ledmode == 0xFF) {
670 lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]);
671 return (-1);
672 }
673 }
674
675 if (argc > 3) {
676 ledtype = str2val(argv[2], sunoem_led_type_vals);
677 if (ledtype == 0xFF)
678 lprintf(LOG_ERR,
679 "Unknow ledtype, will use data from the SDR oem field");
680 }
681
682 if (strncasecmp(argv[0], "all", 3) == 0) {
683 /* do all generic sensors */
684 alist = ipmi_sdr_find_sdr_bytype(intf,
685 SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
686
687 if (alist == NULL)
688 return (-1);
689
690 for (a = alist; a != NULL; a = a->next) {
691 if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
692 continue;
693 if (a->record.genloc->entity.logical)
694 continue;
695 rsp = sunoem_led_set(intf, a->record.genloc, ledtype, ledmode);
696 if (rsp && rsp->ccode == 0)
697 led_print((const char *) a->record.genloc->id_string,
698 PRINT_NORMAL, ledmode);
699 else
700 ret_set = -1;
701 }
702 __sdr_list_empty(alist);
703
704 if (ret_set == -1)
705 return (-1);
706
707 return (0);
708 }
709
710 /* look up generic device locator records in SDR */
711 sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]);
712
713 if (sdr == NULL) {
714 lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
715 return (-1);
716 }
717
718 if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
719 lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type);
720 return (-1);
721 }
722
723 if (!sdr->record.genloc->entity.logical) {
724 /*
725 * handle physical entity
726 */
727 rsp = sunoem_led_set(intf, sdr->record.genloc, ledtype, ledmode);
728 if (rsp && rsp->ccode == 0)
729 led_print(argv[0], PRINT_NORMAL, ledmode);
730 else
731 return (-1);
732
733 return (0);
734 }
735
736 /*
737 * handle logical entity for LED grouping
738 */
739
740 lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
741
742 /* get entity assoc records */
743 alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC);
744
745 if (alist == NULL)
746 return (-1);
747
748 for (a = alist; a != NULL; a = a->next) {
749 if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC)
750 continue;
751 assoc = a->record.entassoc;
752 if (assoc == NULL)
753 continue;
754
755 /* check that the entity id/instance matches our generic record */
756 if (assoc->entity.id != sdr->record.genloc->entity.id
757 || assoc->entity.instance
758 != sdr->record.genloc->entity.instance)
759 continue;
760
761 if (assoc->flags.isrange) {
762 /*
763 * handle ranged entity associations
764 *
765 * the test for non-zero entity id is handled in
766 * sunoem_led_get_byentity()
767 */
768
769 /* first range set - id 1 and 2 must be equal */
770 if (assoc->entity_id_1 == assoc->entity_id_2)
771 for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
772 sunoem_led_set_byentity(intf, assoc->entity_id_1, i,
773 ledtype, ledmode);
774
775 /* second range set - id 3 and 4 must be equal */
776 if (assoc->entity_id_3 == assoc->entity_id_4)
777 for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
778 sunoem_led_set_byentity(intf, assoc->entity_id_3, i,
779 ledtype, ledmode);
780 } else {
781 /*
782 * handle entity list
783 */
784 sunoem_led_set_byentity(intf, assoc->entity_id_1,
785 assoc->entity_inst_1, ledtype, ledmode);
786 sunoem_led_set_byentity(intf, assoc->entity_id_2,
787 assoc->entity_inst_2, ledtype, ledmode);
788 sunoem_led_set_byentity(intf, assoc->entity_id_3,
789 assoc->entity_inst_3, ledtype, ledmode);
790 sunoem_led_set_byentity(intf, assoc->entity_id_4,
791 assoc->entity_inst_4, ledtype, ledmode);
792 }
793 }
794
795 __sdr_list_empty(alist);
796
797 if (ret_set == -1)
798 return (-1);
799
800 return (0);
801 }
802
803 static int
ipmi_sunoem_sshkey_del(struct ipmi_intf * intf,uint8_t uid)804 ipmi_sunoem_sshkey_del(struct ipmi_intf * intf, uint8_t uid)
805 {
806 struct ipmi_rs * rsp;
807 struct ipmi_rq req;
808
809 memset(&req, 0, sizeof(struct ipmi_rq));
810 req.msg.netfn = IPMI_NETFN_SUNOEM;
811 req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY;
812 req.msg.data = &uid;
813 req.msg.data_len = 1;
814
815 rsp = intf->sendrecv(intf, &req);
816 if (rsp == NULL) {
817 lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid);
818 return (-1);
819 } else if (rsp->ccode > 0) {
820 lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid,
821 val2str(rsp->ccode, completion_code_vals));
822 return (-1);
823 }
824
825 printf("Deleted SSH key for user id %d\n", uid);
826 return (0);
827 }
828
829 #define SSHKEY_BLOCK_SIZE 64
830 static int
ipmi_sunoem_sshkey_set(struct ipmi_intf * intf,uint8_t uid,char * ifile)831 ipmi_sunoem_sshkey_set(struct ipmi_intf * intf, uint8_t uid, char * ifile)
832 {
833 struct ipmi_rs * rsp;
834 struct ipmi_rq req;
835 FILE * fp;
836 int count = 0;
837 uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3];
838 int32_t i_size = 0;
839 int32_t r = 0;
840 int32_t size = 0;
841
842 if (ifile == NULL) {
843 lprintf(LOG_ERR, "Invalid or misisng input filename.");
844 return (-1);
845 }
846
847 fp = ipmi_open_file_read(ifile);
848 if (fp == NULL) {
849 lprintf(LOG_ERR, "Unable to open file '%s' for reading.", ifile);
850 return (-1);
851 }
852
853 memset(&req, 0, sizeof(struct ipmi_rq));
854 req.msg.netfn = IPMI_NETFN_SUNOEM;
855 req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY;
856 req.msg.data = wbuf;
857
858 if (fseek(fp, 0, SEEK_END) == (-1)) {
859 lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
860 if (fp != NULL)
861 fclose(fp);
862
863 return (-1);
864 }
865
866 size = (int32_t) ftell(fp);
867 if (size < 0) {
868 lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
869 if (fp != NULL)
870 fclose(fp);
871
872 return (-1);
873 } else if (size == 0) {
874 lprintf(LOG_ERR, "File '%s' is empty.", ifile);
875 if (fp != NULL)
876 fclose(fp);
877
878 return (-1);
879 }
880
881 if (fseek(fp, 0, SEEK_SET) == (-1)) {
882 lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
883 if (fp != NULL)
884 fclose(fp);
885
886 return (-1);
887 }
888
889 printf("Setting SSH key for user id %d...", uid);
890
891 for (r = 0; r < size; r += i_size) {
892 i_size = size - r;
893 if (i_size > SSHKEY_BLOCK_SIZE)
894 i_size = SSHKEY_BLOCK_SIZE;
895
896 memset(wbuf, 0, SSHKEY_BLOCK_SIZE);
897 fseek(fp, r, SEEK_SET);
898 count = fread(wbuf + 3, 1, i_size, fp);
899 if (count != i_size) {
900 printf("failed\n");
901 lprintf(LOG_ERR, "Unable to read %ld bytes from file '%s'.", i_size,
902 ifile);
903 if (fp != NULL)
904 fclose(fp);
905
906 return (-1);
907 }
908
909 printf(".");
910 fflush(stdout);
911
912 wbuf[0] = uid;
913 if ((r + SSHKEY_BLOCK_SIZE) >= size)
914 wbuf[1] = 0xff;
915 else {
916 if ((r / SSHKEY_BLOCK_SIZE) > UINT8_MAX) {
917 printf("failed\n");
918 lprintf(LOG_ERR, "Unable to pack byte %ld from file '%s'.", r,
919 ifile);
920 if (fp != NULL)
921 fclose(fp);
922
923 return (-1);
924 }
925 wbuf[1] = (uint8_t) (r / SSHKEY_BLOCK_SIZE);
926 }
927
928 wbuf[2] = (uint8_t) i_size;
929
930 req.msg.data_len = i_size + 3;
931
932 rsp = intf->sendrecv(intf, &req);
933 if (rsp == NULL) {
934 printf("failed\n");
935 lprintf(LOG_ERR, "Unable to set ssh key for UID %d.", uid);
936 if (fp != NULL)
937 fclose(fp);
938
939 return (-1);
940 } /* if (rsp == NULL) */
941 if (rsp->ccode != 0) {
942 printf("failed\n");
943 lprintf(LOG_ERR, "Unable to set ssh key for UID %d, %s.", uid,
944 val2str(rsp->ccode, completion_code_vals));
945 if (fp != NULL)
946 fclose(fp);
947
948 return (-1);
949 } /* if (rsp->ccode != 0) */
950 }
951
952 printf("done\n");
953
954 fclose(fp);
955 return (0);
956 }
957
958 /*
959 * This structure is used in both the request to and response from the BMC.
960 */
961 #define SUNOEM_CLI_LEGACY_VERSION 1
962 #define SUNOEM_CLI_SEQNUM_VERSION 2
963 #define SUNOEM_CLI_VERSION SUNOEM_CLI_SEQNUM_VERSION
964 #define SUNOEM_CLI_HEADER 8 /* command + spare + handle */
965 #define SUNOEM_CLI_BUF_SIZE (80 - SUNOEM_CLI_HEADER) /* Total 80 bytes */
966 #define SUNOEM_CLI_MSG_SIZE(msg) (SUNOEM_CLI_HEADER + strlen((msg).buf) + 1)
967
968 #ifdef HAVE_PRAGMA_PACK
969 #pragma pack(push, 1)
970 #endif
971 typedef struct
972 {
973 /*
974 * Set version to SUNOEM_CLI_VERSION.
975 */
976 uint8_t version;
977 /*
978 * The command in a request, or in a response indicates an error if
979 * non-zero.
980 */
981 uint8_t command_response;
982 uint8_t seqnum;
983 uint8_t spare;
984 /*
985 * Opaque 4-byte handle, supplied in the response to an OPEN request,
986 * and used in all subsequent POLL and CLOSE requests.
987 */
988 uint8_t handle[4];
989 /*
990 * The client data in a request, or the server data in a response. Must
991 * by null terminated, i.e., it must be at least one byte, but can be
992 * smaller if there's less data.
993 */
994 char buf[SUNOEM_CLI_BUF_SIZE];
995 }__attribute__((packed)) sunoem_cli_msg_t;
996 #ifdef HAVE_PRAGMA_PACK
997 #pragma pack(pop)
998 #endif
999
1000 /*
1001 * Command codes for the command_request field in each request.
1002 */
1003 #define SUNOEM_CLI_CMD_OPEN 0 /* Open a new connection */
1004 #define SUNOEM_CLI_CMD_FORCE 1 /* Close any existing connection, then open */
1005 #define SUNOEM_CLI_CMD_CLOSE 2 /* Close the current connection */
1006 #define SUNOEM_CLI_CMD_POLL 3 /* Poll for new data to/from the server */
1007 #define SUNOEM_CLI_CMD_EOF 4 /* Poll, client is out of data */
1008
1009 #define SUNOEM_CLI_MAX_RETRY 3 /* Maximum number of retries */
1010
1011 #define SUNOEM_CLI_INVALID_VER_ERR "Invalid version"
1012 #define SUNOEM_CLI_BUSY_ERR "Busy"
1013
1014 typedef enum
1015 {
1016 C_CTL_B = 0x02, /* same as left arrow */
1017 C_CTL_C = 0x03,
1018 C_CTL_D = 0x04,
1019 C_CTL_F = 0x06, /* same as right arrow */
1020 C_CTL_N = 0x0E, /* same as down arrow */
1021 C_CTL_P = 0x10, /* same as up arrow */
1022 C_DEL = 0x7f
1023 } canon_char_t;
1024
1025 static int
sunoem_cli_unbufmode_start(FILE * f,struct termios * orig_ts)1026 sunoem_cli_unbufmode_start(FILE *f, struct termios *orig_ts)
1027 {
1028 struct termios ts;
1029 int rc;
1030
1031 if ((rc = tcgetattr(fileno(f), &ts))) {
1032 return (rc);
1033 }
1034 *orig_ts = ts;
1035 ts.c_lflag &= ~(ICANON | ECHO | ISIG);
1036 ts.c_cc[VMIN] = 1;
1037 if ((rc = tcsetattr(fileno(f), TCSAFLUSH, &ts))) {
1038 return (rc);
1039 }
1040
1041 return (0);
1042 }
1043
1044 static int
sunoem_cli_unbufmode_stop(FILE * f,struct termios * ts)1045 sunoem_cli_unbufmode_stop(FILE *f, struct termios *ts)
1046 {
1047 int rc;
1048
1049 if ((rc = tcsetattr(fileno(f), TCSAFLUSH, ts))) {
1050 return (rc);
1051 }
1052
1053 return (0);
1054 }
1055
1056 static int
ipmi_sunoem_cli(struct ipmi_intf * intf,int argc,char * argv[])1057 ipmi_sunoem_cli(struct ipmi_intf * intf, int argc, char *argv[])
1058 {
1059 struct ipmi_rs *rsp;
1060 struct ipmi_rq req;
1061 sunoem_cli_msg_t cli_req;
1062 sunoem_cli_msg_t *cli_rsp;
1063 int arg_num = 0;
1064 int arg_pos = 0;
1065 time_t wait_time = 0;
1066 int retries;
1067 static uint8_t SunOemCliActingVersion = SUNOEM_CLI_VERSION;
1068
1069 unsigned short first_char = 0; /*first char on the line*/
1070 struct termios orig_ts;
1071 int error = 0;
1072
1073 time_t now = 0;
1074 int delay = 0;
1075
1076 /* Prepare to open an SP shell session */
1077 memset(&cli_req, 0, sizeof(cli_req));
1078 cli_req.version = SunOemCliActingVersion;
1079 cli_req.command_response = SUNOEM_CLI_CMD_OPEN;
1080 if (argc > 0 && strcmp(argv[0], "force") == 0) {
1081 cli_req.command_response = SUNOEM_CLI_CMD_FORCE;
1082 argc--;
1083 argv++;
1084 }
1085 memset(&req, 0, sizeof(req));
1086 req.msg.netfn = IPMI_NETFN_SUNOEM;
1087 req.msg.cmd = IPMI_SUNOEM_CLI;
1088 req.msg.data = (uint8_t *) &cli_req;
1089 req.msg.data_len = SUNOEM_CLI_HEADER + 1;
1090 retries = 0;
1091 while (1) {
1092 cli_req.version = SunOemCliActingVersion;
1093 rsp = intf->sendrecv(intf, &req);
1094 if (rsp == NULL) {
1095 lprintf(LOG_ERR, "Sun OEM cli command failed");
1096 return (-1);
1097 }
1098 cli_rsp = (sunoem_cli_msg_t *) rsp->data;
1099 if ((cli_rsp->command_response != 0) || (rsp->ccode != 0)) {
1100 if (strncmp(cli_rsp->buf, SUNOEM_CLI_INVALID_VER_ERR,
1101 sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0
1102 || strncmp(&(cli_rsp->buf[1]), SUNOEM_CLI_INVALID_VER_ERR,
1103 sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0) {
1104 if (SunOemCliActingVersion == SUNOEM_CLI_VERSION) {
1105 /* Server doesn't support version SUNOEM_CLI_VERSION
1106 Fall back to legacy version, and try again*/
1107 SunOemCliActingVersion = SUNOEM_CLI_LEGACY_VERSION;
1108 continue;
1109 }
1110 /* Server doesn't support legacy version either */
1111 lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
1112 return (-1);
1113 } else if (strncmp(cli_rsp->buf, SUNOEM_CLI_BUSY_ERR,
1114 sizeof(SUNOEM_CLI_BUSY_ERR) - 1) == 0) {
1115 if (retries++ < SUNOEM_CLI_MAX_RETRY) {
1116 lprintf(LOG_INFO, "Failed to connect: %s, retrying",
1117 cli_rsp->buf);
1118 sleep(2);
1119 continue;
1120 }
1121 lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
1122 return (-1);
1123 } else {
1124 lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
1125 return (-1);
1126 }
1127 }
1128 break;
1129 }
1130 if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) {
1131 /*
1132 * Bit 1 of seqnum is used as an alternating sequence number
1133 * to allow a server that supports it to detect when a retry is being sent from the host IPMI driver.
1134 * Typically when this occurs, the server's last response message would have been dropped.
1135 * Once the server detects this condition, it will know that it should retry sending the response.
1136 */
1137 cli_req.seqnum ^= 0x1;
1138 }
1139 printf("Connected. Use ^D to exit.\n");
1140 fflush(NULL);
1141
1142 /*
1143 * Remember the handle provided in the response, and issue a
1144 * series of "poll" commands to send and get data
1145 */
1146 memcpy(cli_req.handle, cli_rsp->handle, 4);
1147 cli_req.command_response = SUNOEM_CLI_CMD_POLL;
1148 /*
1149 * If no arguments make input unbuffered and so interactive
1150 */
1151 if (argc == 0) {
1152 if (sunoem_cli_unbufmode_start(stdin, &orig_ts)) {
1153 lprintf(LOG_ERR, "Failed to set interactive mode: %s",
1154 strerror(errno));
1155 return (-1);
1156 }
1157 }
1158 while (rsp->ccode == 0 && cli_rsp->command_response == 0) {
1159 int rc = 0;
1160 int count = 0;
1161 cli_req.buf[0] = '\0';
1162 if (argc == 0) {
1163 /*
1164 * Accept input from stdin. Use select so we don't hang if
1165 * there's no input to read. Select timeout is 500 msec.
1166 */
1167 struct timeval tv = { 0, 500000 }; /* 500 msec */
1168 fd_set rfds;
1169 FD_ZERO(&rfds);
1170 FD_SET(0, &rfds);
1171 rc = select(1, &rfds, NULL, NULL, &tv);
1172 if (rc < 0) {
1173 /* Select returned an error so close and exit */
1174 printf("Broken pipe\n");
1175 cli_req.command_response = SUNOEM_CLI_CMD_CLOSE;
1176 } else if (rc > 0) {
1177 /* Read data from stdin */
1178 count = read(0, cli_req.buf, 1 /* sizeof (cli_req.buf) - 1 */);
1179 /*
1180 * If select said there was data but there was nothing to
1181 * read. This implies user hit ^D.
1182 * Also handle ^D input when pressed as first char at a new line.
1183 */
1184 if (count <= 0 || (first_char && cli_req.buf[0] == C_CTL_D)) {
1185 cli_req.command_response = SUNOEM_CLI_CMD_EOF;
1186 count = 0;
1187 }
1188 first_char = cli_req.buf[0] == '\n' || cli_req.buf[0] == '\r';
1189 }
1190 } else {
1191 /*
1192 * Get data from command line arguments
1193 */
1194 now = time(NULL);
1195 if (now < wait_time) {
1196 /* Do nothing; we're waiting */
1197 } else if (arg_num >= argc) {
1198 /* Last arg was sent. Set EOF */
1199 cli_req.command_response = SUNOEM_CLI_CMD_EOF;
1200 } else if (strncmp(argv[arg_num], "@wait=", 6) == 0) {
1201 /* This is a wait command */
1202 char *s = &argv[arg_num][6];
1203 delay = 0;
1204 if (*s != '\0') {
1205 if (str2int(s, &delay)) {
1206 delay = 0;
1207 }
1208 if (delay < 0) {
1209 delay = 0;
1210 }
1211 }
1212 wait_time = now + delay;
1213 arg_num++;
1214 } else {
1215 /*
1216 * Take data from args. It may be that the argument is larger
1217 * than the request buffer can hold. So pull off BUF_SIZE
1218 * number of characters at a time. When we've consumed the
1219 * entire arg, append a newline and advance to the next arg.
1220 */
1221 int i;
1222 char *s = argv[arg_num];
1223 for (i = arg_pos;
1224 s[i] != '\0' && count < (SUNOEM_CLI_BUF_SIZE - 2);
1225 i++, count++) {
1226 cli_req.buf[count] = s[i];
1227 }
1228 if (s[i] == '\0') {
1229 /* Reached end of the arg string, so append a newline */
1230 cli_req.buf[count++] = '\n';
1231 /* Reset pos to 0 and advance to the next arg next time */
1232 arg_pos = 0;
1233 arg_num++;
1234 } else {
1235 /*
1236 * Otherwise, there's still more characters in the arg
1237 * to send, so remember where we left off
1238 */
1239 arg_pos = i;
1240 }
1241 }
1242 }
1243 /*
1244 * Now send the clients's data (if any) and get data back from the
1245 * server. Loop while the server is giving us data until we suck
1246 * it dry.
1247 */
1248 do {
1249 cli_req.buf[count++] = '\0'; /* Terminate the string */
1250 memset(&req, 0, sizeof(req));
1251 req.msg.netfn = IPMI_NETFN_SUNOEM;
1252 req.msg.cmd = 0x19;
1253 req.msg.data = (uint8_t *) &cli_req;
1254 req.msg.data_len = SUNOEM_CLI_HEADER + count;
1255 for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) {
1256 rsp = intf->sendrecv(intf, &req);
1257 if (rsp == NULL) {
1258 lprintf(LOG_ERR, "Communication error.");
1259 error = 1;
1260 goto cleanup;
1261 }
1262 if (rsp->ccode == IPMI_CC_TIMEOUT) { /* Retry if timed out. */
1263 if (retries == SUNOEM_CLI_MAX_RETRY) { /* If it's the last retry. */
1264 lprintf(LOG_ERR, "Excessive timeout.");
1265 error = 1;
1266 goto cleanup;
1267 }
1268 continue;
1269 }
1270 break;
1271 } /* for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) */
1272
1273 if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) {
1274 cli_req.seqnum ^= 0x1; /* Toggle sequence number after request is sent */
1275 }
1276
1277 cli_rsp = (sunoem_cli_msg_t *) rsp->data;
1278 /* Make sure response string is null terminated */
1279 cli_rsp->buf[sizeof(cli_rsp->buf) - 1] = '\0';
1280 printf("%s", cli_rsp->buf);
1281 fflush(NULL); /* Flush partial lines to stdout */
1282 count = 0; /* Don't re-send the client's data */
1283 if (cli_req.command_response == SUNOEM_CLI_CMD_EOF
1284 && cli_rsp->command_response != 0 && rsp->ccode == 0) {
1285 cli_rsp->command_response = 1;
1286 }
1287 } while (cli_rsp->command_response == 0 && cli_rsp->buf[0] != '\0');
1288 }
1289
1290 cleanup:
1291 /* Restore original input mode if cli was running interactively */
1292 if (argc == 0) {
1293 if (sunoem_cli_unbufmode_stop(stdin, &orig_ts)) {
1294 lprintf(LOG_ERR, "Failed to restore interactive mode: %s",
1295 strerror(errno));
1296 return (-1);
1297 }
1298 }
1299
1300 return ((error == 0 && cli_rsp->command_response == SUNOEM_SUCCESS) ? 0 : -1);
1301 }
1302 #define ECHO_DATA_SIZE 64
1303
1304 #ifdef HAVE_PRAGMA_PACK
1305 #pragma pack(push, 1)
1306 #endif
1307 typedef struct
1308 {
1309 uint16_t seq_num;
1310 unsigned char data[ECHO_DATA_SIZE];
1311 }__attribute__((packed)) sunoem_echo_msg_t;
1312 #ifdef HAVE_PRAGMA_PACK
1313 #pragma pack(pop)
1314 #endif
1315
1316 /*
1317 * Send and receive X packets to the BMC. Each packet has a
1318 * payload size of (sunoem_echo_msg_t) bytes. Each packet is tagged with a
1319 * sequence number
1320 */
1321 static int
ipmi_sunoem_echo(struct ipmi_intf * intf,int argc,char * argv[])1322 ipmi_sunoem_echo(struct ipmi_intf * intf, int argc, char *argv[])
1323 {
1324 struct ipmi_rs *rsp;
1325 struct ipmi_rq req;
1326 sunoem_echo_msg_t echo_req;
1327 sunoem_echo_msg_t *echo_rsp;
1328 struct timeval start_time;
1329 struct timeval end_time;
1330
1331 int rc = 0;
1332 int received = 0;
1333 int transmitted = 0;
1334 int quiet_mode = 0;
1335
1336 uint16_t num, i, j;
1337 uint32_t total_time, resp_time, min_time, max_time;
1338
1339 if (argc < 1) {
1340 return (1);
1341 }
1342
1343 if (argc == 2) {
1344 if (*(argv[1]) == 'q') {
1345 quiet_mode = 1;
1346 } else {
1347 lprintf(LOG_ERR, "Unknown option '%s' given.", argv[1]);
1348 return (-1);
1349 }
1350 } else if (argc > 2) {
1351 lprintf(LOG_ERR,
1352 "Too many parameters given. See help for more information.");
1353 return (-1);
1354 }
1355 /* The number of packets to send/receive */
1356 if (str2ushort(argv[0], &num) != 0) {
1357 lprintf(LOG_ERR,
1358 "Given number of packets is either invalid or out of range.");
1359 return (-1);
1360 }
1361
1362 /* Fill in data packet */
1363 for (i = 0; i < ECHO_DATA_SIZE; i++) {
1364 echo_req.data[i] = (uint8_t) i;
1365 }
1366
1367 memset(&req, 0, sizeof(req));
1368 req.msg.netfn = IPMI_NETFN_SUNOEM;
1369 req.msg.cmd = IPMI_SUNOEM_ECHO;
1370 req.msg.data = (uint8_t *) &echo_req;
1371 req.msg.data_len = sizeof(sunoem_echo_msg_t);
1372 echo_req.seq_num = i;
1373 min_time = INT_MAX;
1374 max_time = 0;
1375 total_time = 0;
1376 for (i = 0; i < num; i++) {
1377 echo_req.seq_num = i;
1378 transmitted++;
1379 gettimeofday(&start_time, NULL);
1380 rsp = intf->sendrecv(intf, &req);
1381 gettimeofday(&end_time, NULL);
1382 resp_time = ((end_time.tv_sec - start_time.tv_sec) * 1000)
1383 + ((end_time.tv_usec - start_time.tv_usec) / 1000);
1384 if ((rsp == NULL) || (rsp->ccode != 0)) {
1385 lprintf(LOG_ERR, "Sun OEM echo command failed. Seq # %d",
1386 echo_req.seq_num);
1387 rc = (-2);
1388 break;
1389 }
1390 echo_rsp = (sunoem_echo_msg_t *) rsp->data;
1391
1392 /* Test if sequence # is valid */
1393 if (echo_rsp->seq_num != echo_req.seq_num) {
1394 printf("Invalid Seq # Expecting %d Received %d\n", echo_req.seq_num,
1395 echo_rsp->seq_num);
1396 rc = (-2);
1397 break;
1398 }
1399
1400 /* Test if response length is valid */
1401 if (rsp->session.msglen == req.msg.data_len) {
1402 printf("Invalid payload size for seq # %d. "
1403 "Expecting %d Received %d\n", echo_rsp->seq_num,
1404 req.msg.data_len, rsp->session.msglen);
1405 rc = (-2);
1406 break;
1407 }
1408
1409 /* Test if the data is valid */
1410 for (j = 0; j < ECHO_DATA_SIZE; j++) {
1411 if (echo_rsp->data[j] != j) {
1412 printf("Corrupt data packet. Seq # %d Offset %d\n",
1413 echo_rsp->seq_num, j);
1414 break;
1415 }
1416 } /* for (j = 0; j < ECHO_DATA_SIZE; j++) */
1417
1418 /* If the for loop terminated early - data is corrupt */
1419 if (j != ECHO_DATA_SIZE) {
1420 rc = (-2);
1421 break;
1422 }
1423
1424 /* cumalative time */
1425 total_time += resp_time;
1426
1427 /* min time */
1428 if (resp_time < min_time) {
1429 min_time = resp_time;
1430 }
1431
1432 /* max time */
1433 if (resp_time > max_time) {
1434 max_time = resp_time;
1435 }
1436
1437 received++;
1438 if (!quiet_mode) {
1439 printf("Receive %u Bytes - Seq. # %d time=%d ms\n",
1440 sizeof(sunoem_echo_msg_t), echo_rsp->seq_num, resp_time);
1441 }
1442 } /* for (i = 0; i < num; i++) */
1443 printf("%d packets transmitted, %d packets received\n", transmitted,
1444 received);
1445 if (received) {
1446 printf("round-trip min/avg/max = %d/%d/%d ms\n", min_time,
1447 total_time / received, max_time);
1448 }
1449
1450 return (rc);
1451 } /* ipmi_sunoem_echo(...) */
1452
1453 #ifdef HAVE_PRAGMA_PACK
1454 #pragma pack(push, 1)
1455 #endif
1456 typedef struct
1457 {
1458 unsigned char oem_record_ver_num;
1459 unsigned char major;
1460 unsigned char minor;
1461 unsigned char update;
1462 unsigned char micro;
1463 char nano[10];
1464 char revision[10];
1465 char version[40];
1466 /*
1467 * When adding new fields (using the spare bytes),
1468 * add it immediately after the spare field to
1469 * ensure backward compatability.
1470 *
1471 * e.g. char version[40];
1472 * unsigned char spare[11];
1473 * int new_item;
1474 * } sunoem_version_response_t;
1475 */
1476 unsigned char spare[15];
1477 }__attribute__((packed)) sunoem_version_response_t;
1478 #ifdef HAVE_PRAGMA_PACK
1479 #pragma pack(pop)
1480 #endif
1481
1482 typedef struct
1483 {
1484 unsigned char major;
1485 unsigned char minor;
1486 unsigned char update;
1487 unsigned char micro;
1488 } supported_version_t;
1489
1490 static int
ipmi_sunoem_getversion(struct ipmi_intf * intf,sunoem_version_response_t ** version_rsp)1491 ipmi_sunoem_getversion(struct ipmi_intf * intf,
1492 sunoem_version_response_t **version_rsp)
1493 {
1494 struct ipmi_rs *rsp;
1495 struct ipmi_rq req;
1496
1497 memset(&req, 0, sizeof(req));
1498 req.msg.netfn = IPMI_NETFN_SUNOEM;
1499 req.msg.cmd = IPMI_SUNOEM_VERSION;
1500 req.msg.data = NULL;
1501 req.msg.data_len = 0;
1502 rsp = intf->sendrecv(intf, &req);
1503
1504 if (rsp == NULL) {
1505 lprintf(LOG_ERR, "Sun OEM Get SP Version Failed.");
1506 return (-1);
1507 }
1508 if (rsp->ccode != 0) {
1509 lprintf(LOG_ERR, "Sun OEM Get SP Version Failed: %d", rsp->ccode);
1510 return (-1);
1511 }
1512
1513 *version_rsp = (sunoem_version_response_t *) rsp->data;
1514
1515 return (0);
1516 }
1517
1518 static void
ipmi_sunoem_print_required_version(const supported_version_t * supp_ver)1519 ipmi_sunoem_print_required_version(const supported_version_t* supp_ver)
1520 {
1521 lprintf(LOG_ERR, "Command is not supported by this version of ILOM,"
1522 " required at least: %d.%d.%d.%d", supp_ver->major, supp_ver->minor,
1523 supp_ver->update, supp_ver->micro);
1524 }
1525
1526 /*
1527 * Function checks current version result against required version.
1528 * Returns:
1529 * - negative value if current ILOM version is smaller than required or
1530 * in case of error
1531 * - positive value if current ILOM version is greater than required
1532 * - 0 if there is an exact ILOM version match
1533 */
1534 static int
ipmi_sunoem_checkversion(struct ipmi_intf * intf,supported_version_t * supp_ver)1535 ipmi_sunoem_checkversion(struct ipmi_intf * intf, supported_version_t* supp_ver)
1536 {
1537 sunoem_version_response_t *version_rsp;
1538 int i = 1;
1539
1540 if (ipmi_sunoem_getversion(intf, &version_rsp)) {
1541 lprintf(LOG_ERR, "Unable to get ILOM version");
1542 return (-1);
1543 }
1544
1545 if (version_rsp->major < supp_ver->major) return (-i);
1546 if (version_rsp->major > supp_ver->major) return (i);
1547 /*version_rsp->major == supp_ver->major*/
1548 ++i;
1549
1550 if (version_rsp->minor < supp_ver->minor) return (-i);
1551 if (version_rsp->minor > supp_ver->minor) return (i);
1552 /*version_rsp->minor == supp_ver->minor*/
1553 ++i;
1554
1555 if (version_rsp->update < supp_ver->update) return (-i);
1556 if (version_rsp->update > supp_ver->update) return (i);
1557 /*version_rsp->update == supp_ver->update*/
1558 ++i;
1559
1560 if (version_rsp->micro < supp_ver->micro) return (-i);
1561 if (version_rsp->micro > supp_ver->micro) return (i);
1562 /*version_rsp->micro == supp_ver->micro*/
1563
1564 return (0);
1565 }
1566
1567 /*
1568 * Extract the SP version data including
1569 * - major #
1570 * - minor #
1571 * - update #
1572 * - micro #
1573 * - nano #
1574 * - Revision/Build #
1575 */
1576 static int
ipmi_sunoem_version(struct ipmi_intf * intf)1577 ipmi_sunoem_version(struct ipmi_intf * intf)
1578 {
1579 sunoem_version_response_t *version_rsp;
1580 int rc = ipmi_sunoem_getversion(intf, &version_rsp);
1581
1582 if (!rc) {
1583 printf("Version: %s\n", version_rsp->version);
1584 }
1585
1586 return (rc);
1587 }
1588
1589 /*
1590 * IPMI Max string length is 16 bytes
1591 * define in usr/src/common/include/ami/IPMI_SDRRecord.h
1592 */
1593 #define MAX_ID_STR_LEN 16
1594 #define MAX_SUNOEM_NAC_SIZE 64
1595 #define LUAPI_MAX_OBJ_PATH_LEN 256
1596 #define LUAPI_MAX_OBJ_VAL_LEN 1024
1597
1598 #ifdef HAVE_PRAGMA_PACK
1599 #pragma pack(push, 1)
1600 #endif
1601 typedef struct
1602 {
1603 unsigned char seq_num;
1604 char nac_name[MAX_SUNOEM_NAC_SIZE];
1605 }__attribute__((packed)) sunoem_nacname_t;
1606 #ifdef HAVE_PRAGMA_PACK
1607 #pragma pack(pop)
1608 #endif
1609
1610 /*
1611 * Retrieve the full NAC name of the IPMI target.
1612 *
1613 * The returned nac name may be larger than the payload size.
1614 * In which case, it make take several request/payload to retrieve
1615 * the entire full path name
1616 *
1617 * The initial seq_num is set to 0. If the return seq_num is incremented,
1618 * only the 1st 72 bytes of the nac name is returned and the caller
1619 * needs to get the next set of string data.
1620 * If the returned seq_num is identical to the input seq_num, all data
1621 * has been returned.
1622 */
1623 static int
ipmi_sunoem_nacname(struct ipmi_intf * intf,int argc,char * argv[])1624 ipmi_sunoem_nacname(struct ipmi_intf * intf, int argc, char *argv[])
1625 {
1626 struct ipmi_rs *rsp;
1627 struct ipmi_rq req;
1628 sunoem_nacname_t nacname_req;
1629 sunoem_nacname_t *nacname_rsp;
1630 char full_nac_name[LUAPI_MAX_OBJ_PATH_LEN];
1631
1632 if (argc < 1) {
1633 return (1);
1634 }
1635
1636 if (strlen(argv[0]) > MAX_ID_STR_LEN) {
1637 lprintf(LOG_ERR,
1638 "Sun OEM nacname command failed: Max size on IPMI name");
1639 return (-1);
1640 }
1641
1642 nacname_req.seq_num = 0;
1643 strcpy(nacname_req.nac_name, argv[0]);
1644
1645 full_nac_name[0] = '\0';
1646 while (1) {
1647 memset(&req, 0, sizeof(req));
1648 req.msg.netfn = IPMI_NETFN_SUNOEM;
1649 req.msg.cmd = IPMI_SUNOEM_NACNAME;
1650 req.msg.data = (uint8_t *) &nacname_req;
1651 req.msg.data_len = sizeof(sunoem_nacname_t);
1652 rsp = intf->sendrecv(intf, &req);
1653
1654 if (rsp == NULL) {
1655 lprintf(LOG_ERR, "Sun OEM nacname command failed.");
1656 return (-1);
1657 }
1658 if (rsp->ccode != 0) {
1659 lprintf(LOG_ERR, "Sun OEM nacname command failed: %d", rsp->ccode);
1660 return (-1);
1661 }
1662
1663 nacname_rsp = (sunoem_nacname_t *) rsp->data;
1664 strncat(full_nac_name, nacname_rsp->nac_name, MAX_SUNOEM_NAC_SIZE);
1665
1666 /*
1667 * break out of the loop if there is no more data
1668 * In most cases, if not all, the NAC name fits into a
1669 * single payload
1670 */
1671 if (nacname_req.seq_num == nacname_rsp->seq_num) {
1672 break;
1673 }
1674
1675 /* Get the next seq of string bytes */
1676 nacname_req.seq_num = nacname_rsp->seq_num;
1677
1678 /* Check if we exceeded the size of the full nac name */
1679 if ((nacname_req.seq_num * MAX_SUNOEM_NAC_SIZE) > LUAPI_MAX_OBJ_PATH_LEN) {
1680 lprintf(LOG_ERR,
1681 "Sun OEM nacname command failed: invalid path length");
1682 return (-1);
1683 }
1684 }
1685
1686 printf("NAC Name: %s\n", full_nac_name);
1687 return (0);
1688 }
1689
1690 /* Constants used by ipmi_sunoem_getval */
1691 #define MAX_SUNOEM_VAL_PAYLOAD 79
1692 #define MAX_SUNOEM_VAL_COMPACT_PAYLOAD 56
1693
1694 /*
1695 * SUNOEM GET/SET LUAPI Commands
1696 *
1697 * SUNOEM_REQ_VAL - Request LUAPI Property Value
1698 * SUNOEM_GET_VAL - Return the value from SUNOEM_REQ_VAL
1699 * SUNOEM_SET_VAL - Set the LUAPI Property value
1700 * SUNOEM_GET_STATUS - Return the Status from SUNOEM_SET_VAL
1701 */
1702 #define SUNOEM_REQ_VAL 1
1703 #define SUNOEM_GET_VAL 2
1704 #define SUNOEM_SET_VAL 3
1705 #define SUNOEM_GET_STATUS 4
1706
1707 /* Status Code */
1708 #define SUNOEM_REQ_RECV 1
1709 #define SUNOEM_REQ_FAILED 2
1710 #define SUNOEM_DATA_READY 3
1711 #define SUNOEM_DATA_NOT_READY 4
1712 #define SUNOEM_DATA_NOT_FOUND 5
1713 #define GETVAL_MAX_RETRIES 5
1714
1715 /* Parameter type Codes */
1716 #define SUNOEM_LUAPI_TARGET 0
1717 #define SUNOEM_LUAPI_VALUE 1
1718
1719 #ifdef HAVE_PRAGMA_PACK
1720 #pragma pack(push, 1)
1721 #endif
1722 typedef struct
1723 {
1724 unsigned char cmd_code;
1725 unsigned char luapi_value[MAX_SUNOEM_VAL_PAYLOAD];
1726 }__attribute__((packed)) sunoem_getval_t;
1727 #ifdef HAVE_PRAGMA_PACK
1728 #pragma pack(pop)
1729 #endif
1730
1731 /*
1732 * REQUEST PAYLOAD
1733 *
1734 * cmd_code - SUNOEM GET/SET LUAPI Cmds - see above
1735 * param_type: 0: luapi_data contains the luapi property name
1736 * 1: luapi_data contains the luapi value
1737 * luapi_data: Either luapi property name or value
1738 * tid: Transaction ID. If 0. This is the initial request for the
1739 * param_type. If tid > 0, this luapi_data string is a concatenation
1740 * of the previous request. Handle cases where the LUAPI target name
1741 * or value is > MAX_SUNOEM_VAL_COMPACT_PAYLOAD
1742 * eof: If non zero, this is the last payload for the request
1743 */
1744 #ifdef HAVE_PRAGMA_PACK
1745 #pragma pack(push, 1)
1746 #endif
1747 typedef struct
1748 {
1749 unsigned char cmd_code;
1750 unsigned char param_type;
1751 unsigned char tid;
1752 unsigned char eof;
1753 char luapi_data[MAX_SUNOEM_VAL_COMPACT_PAYLOAD];
1754 }__attribute__((packed)) sunoem_setval_t;
1755 #ifdef HAVE_PRAGMA_PACK
1756 #pragma pack(pop)
1757 #endif
1758
1759 /*
1760 * RESPONSE PAYLOAD
1761 *
1762 * status_code - see above for code definitions
1763 * tid - transaction ID - assigned ny the ILOM stack
1764 */
1765 #ifdef HAVE_PRAGMA_PACK
1766 #pragma pack(push, 1)
1767 #endif
1768 typedef struct
1769 {
1770 unsigned char status_code;
1771 unsigned char tid;
1772 }__attribute__((packed)) sunoem_setval_resp_t;
1773 #ifdef HAVE_PRAGMA_PACK
1774 #pragma pack(pop)
1775 #endif
1776
1777 /*
1778 * Return the ILOM target property value
1779 */
1780 static int
ipmi_sunoem_getval(struct ipmi_intf * intf,int argc,char * argv[])1781 ipmi_sunoem_getval(struct ipmi_intf * intf, int argc, char *argv[])
1782 {
1783 struct ipmi_rs *rsp;
1784 struct ipmi_rq req;
1785 sunoem_getval_t getval_req;
1786 sunoem_getval_t *getval_rsp;
1787 int i;
1788
1789 const char* sp_path = "/SP";
1790 supported_version_t supp_ver = { 3, 2, 0, 0 };
1791
1792 if (argc < 1) {
1793 return (1);
1794 }
1795
1796 if (strlen(argv[0]) > MAX_SUNOEM_VAL_PAYLOAD) {
1797 lprintf(LOG_ERR,
1798 "Sun OEM get value command failed: Max size on IPMI name");
1799 return (-1);
1800 }
1801
1802 if ((ipmi_sunoem_checkversion(intf, &supp_ver) < 0)
1803 && (!strncmp(argv[0], sp_path, strlen(sp_path)))) {
1804 argv[0][1] = 'X'; /*replace SP by X to gain access to hidden properties*/
1805 memmove(&argv[0][2], &argv[0][3], strlen(argv[0]) - 2);
1806 }
1807
1808 /*
1809 * Setup the initial request to fetch the data.
1810 * Upon function return, the next cmd (SUNOEM_GET_VAL)
1811 * can be requested.
1812 */
1813 memset(&getval_req, 0, sizeof(getval_req));
1814 strncpy((char*) getval_req.luapi_value, argv[0], MAX_SUNOEM_VAL_PAYLOAD);
1815 getval_req.cmd_code = SUNOEM_REQ_VAL;
1816
1817 memset(&req, 0, sizeof(req));
1818 req.msg.netfn = IPMI_NETFN_SUNOEM;
1819 req.msg.cmd = IPMI_SUNOEM_GETVAL;
1820 req.msg.data = (uint8_t *) &getval_req;
1821 req.msg.data_len = sizeof(sunoem_getval_t);
1822 rsp = intf->sendrecv(intf, &req);
1823
1824 if (rsp == NULL) {
1825 lprintf(LOG_ERR, "Sun OEM getval1 command failed.");
1826 return (-1);
1827 }
1828 if (rsp->ccode != 0) {
1829 lprintf(LOG_ERR, "Sun OEM getval1 command failed: %d", rsp->ccode);
1830 return (-1);
1831 }
1832
1833 /*
1834 * Fetch the data value - if it is not ready,
1835 * retry the request up to GETVAL_MAX_RETRIES
1836 */
1837 for (i = 0; i < GETVAL_MAX_RETRIES; i++) {
1838 memset(&req, 0, sizeof(req));
1839 req.msg.netfn = IPMI_NETFN_SUNOEM;
1840 req.msg.cmd = IPMI_SUNOEM_GETVAL;
1841 getval_req.cmd_code = SUNOEM_GET_VAL;
1842 req.msg.data = (uint8_t *) &getval_req;
1843 req.msg.data_len = sizeof(sunoem_getval_t);
1844 rsp = intf->sendrecv(intf, &req);
1845
1846 if (rsp == NULL) {
1847 lprintf(LOG_ERR, "Sun OEM getval2 command failed.");
1848 return (-1);
1849 }
1850
1851 if (rsp->ccode != 0) {
1852 lprintf(LOG_ERR, "Sun OEM getval2 command failed: %d", rsp->ccode);
1853 return (-1);
1854 }
1855
1856 getval_rsp = (sunoem_getval_t *) rsp->data;
1857
1858 if (getval_rsp->cmd_code == SUNOEM_DATA_READY) {
1859 printf("Target Value: %s\n", getval_rsp->luapi_value);
1860 return (0);
1861 } else if (getval_rsp->cmd_code == SUNOEM_DATA_NOT_FOUND) {
1862 lprintf(LOG_ERR, "Target: %s not found", getval_req.luapi_value);
1863 return (-1);
1864 }
1865
1866 sleep(1);
1867 }
1868
1869 lprintf(LOG_ERR, "Unable to retrieve target value.");
1870 return (-1);
1871 }
1872
1873 static int
send_luapi_prop_name(struct ipmi_intf * intf,int len,char * prop_name,unsigned char * tid_num)1874 send_luapi_prop_name(struct ipmi_intf * intf, int len, char *prop_name,
1875 unsigned char *tid_num)
1876 {
1877 int i = 0;
1878 struct ipmi_rs *rsp;
1879 struct ipmi_rq req;
1880 sunoem_setval_t setval_req;
1881 sunoem_setval_resp_t *setval_rsp;
1882
1883 *tid_num = 0;
1884 while (i < len) {
1885 /*
1886 * Setup the request,
1887 * Upon function return, the next cmd (SUNOEM_SET_VAL)
1888 * can be requested.
1889 */
1890 memset(&req, 0, sizeof(req));
1891 memset(&setval_req, 0, sizeof(sunoem_setval_t));
1892 req.msg.netfn = IPMI_NETFN_SUNOEM;
1893 req.msg.cmd = IPMI_SUNOEM_SETVAL;
1894 setval_req.cmd_code = SUNOEM_SET_VAL;
1895 setval_req.param_type = SUNOEM_LUAPI_TARGET;
1896 setval_req.tid = *tid_num;
1897 setval_req.eof = 0;
1898 /*
1899 * If the property name is > payload, only copy
1900 * the payload size and increment the string offset (i)
1901 * for the next payload
1902 */
1903 if (strlen(&(prop_name[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
1904 strncpy(setval_req.luapi_data, &(prop_name[i]),
1905 MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
1906 } else {
1907 strncpy(setval_req.luapi_data, &(prop_name[i]),
1908 strlen(&(prop_name[i])));
1909 }
1910 req.msg.data = (uint8_t *) &setval_req;
1911 req.msg.data_len = sizeof(sunoem_setval_t);
1912 rsp = intf->sendrecv(intf, &req);
1913
1914 if (rsp == NULL) {
1915 lprintf(LOG_ERR, "Sun OEM setval prop name: response is NULL");
1916 return (-1);
1917 }
1918
1919 if (rsp->ccode != 0) {
1920 lprintf(LOG_ERR, "Sun OEM setval prop name: request failed: %d",
1921 rsp->ccode);
1922 return (-1);
1923 }
1924
1925 setval_rsp = (sunoem_setval_resp_t *) rsp->data;
1926
1927 /*
1928 * If the return code is other than data received, the
1929 * request failed
1930 */
1931 if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
1932 lprintf(LOG_ERR,
1933 "Sun OEM setval prop name: invalid status code: %d",
1934 setval_rsp->status_code);
1935 return (-1);
1936 }
1937 /* Use the tid returned by ILOM */
1938 *tid_num = setval_rsp->tid;
1939 /* Increment the string offset */
1940 i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
1941 }
1942
1943 return (0);
1944 }
1945
1946 static int
send_luapi_prop_value(struct ipmi_intf * intf,int len,char * prop_value,unsigned char tid_num)1947 send_luapi_prop_value(struct ipmi_intf * intf, int len, char *prop_value,
1948 unsigned char tid_num)
1949 {
1950 int i = 0;
1951 struct ipmi_rs *rsp;
1952 struct ipmi_rq req;
1953 sunoem_setval_t setval_req;
1954 sunoem_setval_resp_t *setval_rsp;
1955
1956 while (i < len) {
1957 /*
1958 * Setup the request,
1959 * Upon function return, the next cmd (SUNOEM_GET_VAL)
1960 * can be requested.
1961 */
1962 memset(&req, 0, sizeof(req));
1963 memset(&setval_req, 0, sizeof(sunoem_setval_t));
1964 req.msg.netfn = IPMI_NETFN_SUNOEM;
1965 req.msg.cmd = IPMI_SUNOEM_SETVAL;
1966 setval_req.cmd_code = SUNOEM_SET_VAL;
1967 setval_req.param_type = SUNOEM_LUAPI_VALUE;
1968 setval_req.tid = tid_num;
1969 /*
1970 * If the property name is > payload, only copy the
1971 * the payload size and increment the string offset
1972 * for the next payload
1973 */
1974 if (strlen(&(prop_value[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
1975 strncpy(setval_req.luapi_data, &(prop_value[i]),
1976 MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
1977 } else {
1978 /* Captured the entire string, mark this as the last payload */
1979 strncpy(setval_req.luapi_data, &(prop_value[i]),
1980 strlen(&(prop_value[i])));
1981 setval_req.eof = 1;
1982 }
1983 req.msg.data = (uint8_t *) &setval_req;
1984 req.msg.data_len = sizeof(sunoem_setval_t);
1985 rsp = intf->sendrecv(intf, &req);
1986
1987 if (rsp == NULL) {
1988 lprintf(LOG_ERR, "Sun OEM setval prop value: response is NULL");
1989 return (-1);
1990 }
1991
1992 if (rsp->ccode != 0) {
1993 lprintf(LOG_ERR, "Sun OEM setval prop value: request failed: %d",
1994 rsp->ccode);
1995 return (-1);
1996 }
1997
1998 setval_rsp = (sunoem_setval_resp_t *) rsp->data;
1999
2000 /*
2001 * If the return code is other than data received, the
2002 * request failed
2003 */
2004 if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
2005 lprintf(LOG_ERR,
2006 "Sun OEM setval prop value: invalid status code: %d",
2007 setval_rsp->status_code);
2008 return (-1);
2009 }
2010
2011 /* Increment the string offset */
2012 i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
2013 }
2014 return (0);
2015 }
2016
2017 static int
ipmi_sunoem_setval(struct ipmi_intf * intf,int argc,char * argv[])2018 ipmi_sunoem_setval(struct ipmi_intf * intf, int argc, char *argv[])
2019 {
2020 struct ipmi_rs *rsp;
2021 struct ipmi_rq req;
2022 sunoem_setval_t setval_req;
2023 sunoem_setval_resp_t *setval_rsp;
2024 int prop_len;
2025 int value_len;
2026 int i;
2027 unsigned char tid_num;
2028 int retries;
2029
2030 prop_len = strlen(argv[0]);
2031 value_len = strlen(argv[1]);
2032 if (prop_len > LUAPI_MAX_OBJ_PATH_LEN) {
2033 lprintf(LOG_ERR,
2034 "Sun OEM set value command failed: Max size on property name");
2035 return (-1);
2036 }
2037 if (value_len > LUAPI_MAX_OBJ_VAL_LEN) {
2038 lprintf(LOG_ERR,
2039 "Sun OEM set value command failed: Max size on property value");
2040 return (-1);
2041 }
2042
2043 /* Test if there is a timeout specified */
2044 if (argc == 3) {
2045 if ((str2int(argv[2], &retries) != 0) || retries < 0) {
2046 lprintf(LOG_ERR,
2047 "Invalid input given or out of range for time-out parameter.");
2048 return (-1);
2049 }
2050 } else {
2051 retries = GETVAL_MAX_RETRIES;
2052 }
2053
2054 /* Send the property name 1st */
2055 if (send_luapi_prop_name(intf, prop_len, argv[0], &tid_num) != 0) {
2056 /* return if there is an error */
2057 return (-1);
2058 }
2059
2060 if (send_luapi_prop_value(intf, value_len, argv[1], tid_num) != 0) {
2061 /* return if there is an error */
2062 return (-1);
2063 }
2064
2065 /*
2066 * Get The status of the command.
2067 * if it is not ready, retry the request up to
2068 * GETVAL_MAX_RETRIES
2069 */
2070 for (i = 0; i < retries; i++) {
2071 memset(&req, 0, sizeof(req));
2072 req.msg.netfn = IPMI_NETFN_SUNOEM;
2073 req.msg.cmd = IPMI_SUNOEM_SETVAL;
2074 setval_req.cmd_code = SUNOEM_GET_STATUS;
2075 setval_req.tid = tid_num;
2076 req.msg.data = (uint8_t *) &setval_req;
2077 req.msg.data_len = sizeof(sunoem_setval_t);
2078 rsp = intf->sendrecv(intf, &req);
2079
2080 if (rsp == NULL) {
2081 lprintf(LOG_ERR, "Sun OEM setval command failed.");
2082 return (-1);
2083 }
2084
2085 if (rsp->ccode != 0) {
2086 lprintf(LOG_ERR, "Sun OEM setval command failed: %d", rsp->ccode);
2087 return (-1);
2088 }
2089
2090 setval_rsp = (sunoem_setval_resp_t *) rsp->data;
2091
2092 if (setval_rsp->status_code == SUNOEM_DATA_READY) {
2093 printf("Sun OEM setval command successful.\n");
2094 return (0);
2095 } else if (setval_rsp->status_code != SUNOEM_DATA_NOT_READY) {
2096 lprintf(LOG_ERR, "Sun OEM setval command failed.");
2097 return (-1);
2098 }
2099
2100 sleep(1);
2101 }
2102 /* If we reached here, retries exceeded */
2103 lprintf(LOG_ERR, "Sun OEM setval command failed: Command Timed Out");
2104
2105 return (-1);
2106 }
2107
2108 #define MAX_FILE_DATA_SIZE 1024
2109 #define MAX_FILEID_LEN 16
2110 #define CORE_TUNNEL_SUBCMD_GET_FILE 11
2111
2112 #ifdef HAVE_PRAGMA_PACK
2113 #pragma pack(push, 1)
2114 #endif
2115 typedef struct
2116 {
2117 unsigned char cmd_code;
2118 unsigned char file_id[MAX_FILEID_LEN];
2119 unsigned int block_num;
2120 }__attribute__((packed)) getfile_req_t;
2121
2122 typedef struct
2123 {
2124 unsigned int block_num;
2125 unsigned int data_size;
2126 unsigned char eof;
2127 unsigned char data[MAX_FILE_DATA_SIZE];
2128 }__attribute__((packed)) getfile_rsp_t;
2129 #ifdef HAVE_PRAGMA_PACK
2130 #pragma pack(pop)
2131 #endif
2132
2133 static int
ipmi_sunoem_getfile(struct ipmi_intf * intf,int argc,char * argv[])2134 ipmi_sunoem_getfile(struct ipmi_intf * intf, int argc, char *argv[])
2135 {
2136 struct ipmi_rs *rsp;
2137 struct ipmi_rq req;
2138 getfile_req_t getfile_req;
2139 getfile_rsp_t *getfile_rsp;
2140 int block_num = 0;
2141 int nbo_blk_num; /* Network Byte Order Block Num */
2142 FILE *fp;
2143 unsigned data_size;
2144 supported_version_t supp_ver = IPMI_SUNOEM_GETFILE_VERSION;
2145
2146 if (argc < 1) {
2147 return (-1);
2148 }
2149
2150 /*check if command is supported by this version of ilom*/
2151 if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
2152 ipmi_sunoem_print_required_version(&supp_ver);
2153 return (-1);
2154 }
2155
2156 /*
2157 * File ID is < MAX_FILEID_LEN
2158 * Save 1 byte for null Terminated string
2159 */
2160 if (strlen(argv[0]) >= MAX_FILE_DATA_SIZE) {
2161 lprintf(LOG_ERR, "File ID >= %d characters", MAX_FILEID_LEN);
2162 return (-1);
2163 }
2164
2165 memset(&getfile_req, 0, sizeof(getfile_req));
2166 strncpy((char*) getfile_req.file_id, argv[0], MAX_FILEID_LEN - 1);
2167
2168 /* Create the destination file */
2169 fp = ipmi_open_file_write(argv[1]);
2170 if (fp == NULL) {
2171 lprintf(LOG_ERR, "Unable to open file: %s", argv[1]);
2172 return (-1);
2173 }
2174
2175 memset(&req, 0, sizeof(req));
2176 req.msg.netfn = IPMI_NETFN_SUNOEM;
2177 req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
2178 req.msg.data = (uint8_t *) &getfile_req;
2179 req.msg.data_len = sizeof(getfile_req_t);
2180 getfile_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_FILE;
2181
2182 do {
2183
2184 nbo_blk_num = htonl(block_num);
2185 /* Block Num must be in network byte order */
2186 memcpy(&(getfile_req.block_num), &nbo_blk_num,
2187 sizeof(getfile_req.block_num));
2188
2189 rsp = intf->sendrecv(intf, &req);
2190
2191 if (rsp == NULL) {
2192 lprintf(LOG_ERR, "Sun OEM getfile command failed.");
2193 fclose(fp);
2194 return (-1);
2195 }
2196 if (rsp->ccode != 0) {
2197 lprintf(LOG_ERR, "Sun OEM getfile command failed: %d", rsp->ccode);
2198 fclose(fp);
2199 return (-1);
2200 }
2201
2202 getfile_rsp = (getfile_rsp_t *) rsp->data;
2203
2204 memcpy(&data_size, &(getfile_rsp->data_size),
2205 sizeof(getfile_rsp->data_size));
2206 data_size = ntohl(data_size);
2207
2208 if (data_size > MAX_FILE_DATA_SIZE) {
2209 lprintf(LOG_ERR, "Sun OEM getfile invalid data size: %d",
2210 data_size);
2211 fclose(fp);
2212 return (-1);
2213 }
2214
2215 /* Check if Block Num matches */
2216 if (memcmp(&(getfile_req.block_num), &(getfile_rsp->block_num),
2217 sizeof(getfile_req.block_num)) != 0) {
2218 lprintf(LOG_ERR, "Sun OEM getfile Incorrect Block Num Returned");
2219 lprintf(LOG_ERR, "Expecting: %x Received: %x",
2220 getfile_req.block_num, getfile_rsp->block_num);
2221 fclose(fp);
2222 return (-1);
2223 }
2224
2225 if (fwrite(getfile_rsp->data, 1, data_size, fp) != data_size) {
2226 lprintf(LOG_ERR, "Sun OEM getfile write failed: %d", rsp->ccode);
2227 fclose(fp);
2228 return (-1);
2229 }
2230
2231 block_num++;
2232 } while (getfile_rsp->eof == 0);
2233
2234 fclose(fp);
2235
2236 return (0);
2237 }
2238
2239 /*
2240 * Query BMC for capability/behavior.
2241 */
2242
2243 #define CORE_TUNNEL_SUBCMD_GET_BEHAVIOR 15
2244 #define SUNOEM_BEHAVIORID_SIZE 32
2245
2246 #ifdef HAVE_PRAGMA_PACK
2247 #pragma pack(push, 1)
2248 #endif
2249 typedef struct
2250 {
2251 unsigned char cmd_code;
2252 unsigned char behavior_id[SUNOEM_BEHAVIORID_SIZE];
2253 }__attribute__((packed)) getbehavior_req_t;
2254
2255 typedef struct
2256 {
2257 unsigned char enabled;
2258 }__attribute__((packed)) getbehavior_rsp_t;
2259 #ifdef HAVE_PRAGMA_PACK
2260 #pragma pack(pop)
2261 #endif
2262
2263 static int
ipmi_sunoem_getbehavior(struct ipmi_intf * intf,int argc,char * argv[])2264 ipmi_sunoem_getbehavior(struct ipmi_intf * intf, int argc, char *argv[])
2265 {
2266 struct ipmi_rq req;
2267 struct ipmi_rs *rsp;
2268 getbehavior_req_t getbehavior_req;
2269 getbehavior_rsp_t *getbehavior_rsp;
2270 supported_version_t supp_ver = IPMI_SUNOEM_GETBEHAVIOR_VERSION;
2271
2272 if (argc < 1) {
2273 return (-1);
2274 }
2275
2276 /*check if command is supported by this version of ilom*/
2277 if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
2278 ipmi_sunoem_print_required_version(&supp_ver);
2279 return (-1);
2280 }
2281
2282 /*
2283 * Behavior ID is < SUNOEM_BEHAVIORID_SIZE.
2284 * Save 1 byte for null terminated string
2285 */
2286 if (strlen(argv[0]) >= SUNOEM_BEHAVIORID_SIZE) {
2287 lprintf(LOG_ERR, "Behavior ID >= %d characters",
2288 SUNOEM_BEHAVIORID_SIZE);
2289 return (-1);
2290 }
2291
2292 memset(&getbehavior_req, 0, sizeof(getbehavior_req));
2293 strncpy(getbehavior_req.behavior_id, argv[0], SUNOEM_BEHAVIORID_SIZE - 1);
2294
2295 memset(&req, 0, sizeof(req));
2296 req.msg.netfn = IPMI_NETFN_SUNOEM;
2297 req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
2298 req.msg.data = (uint8_t *) &getbehavior_req;
2299 req.msg.data_len = sizeof(getbehavior_req_t);
2300 getbehavior_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_BEHAVIOR;
2301
2302 rsp = intf->sendrecv(intf, &req);
2303
2304 if (rsp == NULL) {
2305 lprintf(LOG_ERR, "Sun OEM getbehavior command failed.");
2306 return (-1);
2307 }
2308
2309 if (rsp->ccode != 0) {
2310 lprintf(LOG_ERR, "Sun OEM getbehavior command failed: %d", rsp->ccode);
2311 return (-1);
2312 }
2313
2314 getbehavior_rsp = (getbehavior_rsp_t *) rsp->data;
2315 printf("ILOM behavior %s %s enabled\n", getbehavior_req.behavior_id,
2316 getbehavior_rsp->enabled ? "is" : "is not");
2317
2318 return (0);
2319 }
2320
2321 int
ipmi_sunoem_main(struct ipmi_intf * intf,int argc,char ** argv)2322 ipmi_sunoem_main(struct ipmi_intf * intf, int argc, char ** argv)
2323 {
2324 int rc = 0;
2325
2326 if (argc == 0 || strcmp(argv[0], "help") == 0) {
2327 ipmi_sunoem_usage();
2328 return (0);
2329 } /* if (argc == 0 || strcmp(argv[0], "help") == 0) */
2330
2331 if (strcmp(argv[0], "cli") == 0) {
2332 rc = ipmi_sunoem_cli(intf, argc - 1, &argv[1]);
2333 } else if ((strcmp(argv[0], "led") == 0) || (strcmp(argv[0], "sbled") == 0)) {
2334 if (argc < 2) {
2335 ipmi_sunoem_usage();
2336 return (-1);
2337 }
2338
2339 if (strcmp(argv[1], "get") == 0) {
2340 if (argc < 3) {
2341 char * arg[] = { "all" };
2342 rc = ipmi_sunoem_led_get(intf, 1, arg);
2343 } else {
2344 rc = ipmi_sunoem_led_get(intf, argc - 2, &(argv[2]));
2345 }
2346 } else if (strcmp(argv[1], "set") == 0) {
2347 if (argc < 4) {
2348 ipmi_sunoem_usage();
2349 return (-1);
2350 }
2351 rc = ipmi_sunoem_led_set(intf, argc - 2, &(argv[2]));
2352 } else {
2353 ipmi_sunoem_usage();
2354 return (-1);
2355 }
2356 } else if (strcmp(argv[0], "sshkey") == 0) {
2357 uint8_t uid = 0;
2358 if (argc < 3) {
2359 ipmi_sunoem_usage();
2360 return (-1);
2361 }
2362 rc = str2uchar(argv[2], &uid);
2363 if (rc == 0) {
2364 /* conversion should be OK. */
2365 } else if (rc == 2) {
2366 lprintf(LOG_NOTICE, "Invalid interval given.");
2367 return (-1);
2368 } else {
2369 /* defaults to rc = 3 */
2370 lprintf(LOG_NOTICE, "Given interval is too big.");
2371 return (-1);
2372 }
2373
2374 if (strcmp(argv[1], "del") == 0) {
2375 /* number of arguments, three, is already checked at this point */
2376 rc = ipmi_sunoem_sshkey_del(intf, uid);
2377 } else if (strcmp(argv[1], "set") == 0) {
2378 if (argc < 4) {
2379 ipmi_sunoem_usage();
2380 return (-1);
2381 }
2382 rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]);
2383 } else {
2384 ipmi_sunoem_usage();
2385 return (-1);
2386 }
2387 } else if (strcmp(argv[0], "ping") == 0) {
2388 if (argc < 2) {
2389 ipmi_sunoem_usage();
2390 return (-1);
2391 }
2392 rc = ipmi_sunoem_echo(intf, argc - 1, &(argv[1]));
2393 } else if (strcmp(argv[0], "version") == 0) {
2394 rc = ipmi_sunoem_version(intf);
2395 } else if (strcmp(argv[0], "nacname") == 0) {
2396 if (argc < 2) {
2397 ipmi_sunoem_usage();
2398 return (-1);
2399 }
2400 rc = ipmi_sunoem_nacname(intf, argc - 1, &(argv[1]));
2401 } else if (strcmp(argv[0], "getval") == 0) {
2402 if (argc < 2) {
2403 ipmi_sunoem_usage();
2404 return (-1);
2405 }
2406 rc = ipmi_sunoem_getval(intf, argc - 1, &(argv[1]));
2407 } else if (strcmp(argv[0], "setval") == 0) {
2408 if (argc < 3) {
2409 ipmi_sunoem_usage();
2410 return (-1);
2411 }
2412 rc = ipmi_sunoem_setval(intf, argc - 1, &(argv[1]));
2413 } else if (strcmp(argv[0], "getfile") == 0) {
2414 if (argc < 3) {
2415 ipmi_sunoem_usage();
2416 return (-1);
2417 }
2418 rc = ipmi_sunoem_getfile(intf, argc - 1, &(argv[1]));
2419 } else if (strcmp(argv[0], "getbehavior") == 0) {
2420 if (argc < 2) {
2421 ipmi_sunoem_usage();
2422 return (-1);
2423 }
2424 rc = ipmi_sunoem_getbehavior(intf, argc - 1, &(argv[1]));
2425 } else {
2426 lprintf(LOG_ERR, "Invalid sunoem command: %s", argv[0]);
2427 return (-1);
2428 } /* if (strcmp(argv[0], "cli") == 0) */
2429
2430 return (rc);
2431 }
2432