xref: /openbmc/ipmitool/lib/ipmi_sunoem.c (revision d531785a)
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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 		if (i > UINT8_MAX)
1365 			break;
1366 
1367 		echo_req.data[i] = (uint8_t) i;
1368 	}
1369 
1370 	memset(&req, 0, sizeof(req));
1371 	req.msg.netfn = IPMI_NETFN_SUNOEM;
1372 	req.msg.cmd = IPMI_SUNOEM_ECHO;
1373 	req.msg.data = (uint8_t *) &echo_req;
1374 	req.msg.data_len = sizeof(sunoem_echo_msg_t);
1375 	echo_req.seq_num = i;
1376 	min_time = INT_MAX;
1377 	max_time = 0;
1378 	total_time = 0;
1379 	for (i = 0; i < num; i++) {
1380 		echo_req.seq_num = i;
1381 		transmitted++;
1382 		gettimeofday(&start_time, NULL);
1383 		rsp = intf->sendrecv(intf, &req);
1384 		gettimeofday(&end_time, NULL);
1385 		resp_time = ((end_time.tv_sec - start_time.tv_sec) * 1000)
1386 				+ ((end_time.tv_usec - start_time.tv_usec) / 1000);
1387 		if ((rsp == NULL) || (rsp->ccode != 0)) {
1388 			lprintf(LOG_ERR, "Sun OEM echo command failed. Seq # %d",
1389 					echo_req.seq_num);
1390 			rc = (-2);
1391 			break;
1392 		}
1393 		echo_rsp = (sunoem_echo_msg_t *) rsp->data;
1394 
1395 		/* Test if sequence # is valid */
1396 		if (echo_rsp->seq_num != echo_req.seq_num) {
1397 			printf("Invalid Seq # Expecting %d Received %d\n", echo_req.seq_num,
1398 					echo_rsp->seq_num);
1399 			rc = (-2);
1400 			break;
1401 		}
1402 
1403 		/* Test if response length is valid */
1404 		if (rsp->session.msglen == req.msg.data_len) {
1405 			printf("Invalid payload size for seq # %d. "
1406 					"Expecting %d Received %d\n", echo_rsp->seq_num,
1407 					req.msg.data_len, rsp->session.msglen);
1408 			rc = (-2);
1409 			break;
1410 		}
1411 
1412 		/* Test if the data is valid */
1413 		for (j = 0; j < ECHO_DATA_SIZE; j++) {
1414 			if (echo_rsp->data[j] != j) {
1415 				printf("Corrupt data packet. Seq # %d Offset %d\n",
1416 						echo_rsp->seq_num, j);
1417 				break;
1418 			}
1419 		} /* for (j = 0; j < ECHO_DATA_SIZE; j++) */
1420 
1421 		/* If the for loop terminated early - data is corrupt */
1422 		if (j != ECHO_DATA_SIZE) {
1423 			rc = (-2);
1424 			break;
1425 		}
1426 
1427 		/* cumalative time */
1428 		total_time += resp_time;
1429 
1430 		/* min time */
1431 		if (resp_time < min_time) {
1432 			min_time = resp_time;
1433 		}
1434 
1435 		/* max time */
1436 		if (resp_time > max_time) {
1437 			max_time = resp_time;
1438 		}
1439 
1440 		received++;
1441 		if (!quiet_mode) {
1442 			printf("Receive %u Bytes - Seq. # %d time=%d ms\n",
1443 					sizeof(sunoem_echo_msg_t), echo_rsp->seq_num, resp_time);
1444 		}
1445 	} /* for (i = 0; i < num; i++) */
1446 	printf("%d packets transmitted, %d packets received\n", transmitted,
1447 			received);
1448 	if (received) {
1449 		printf("round-trip min/avg/max = %d/%d/%d ms\n", min_time,
1450 				total_time / received, max_time);
1451 	}
1452 
1453 	return (rc);
1454 } /* ipmi_sunoem_echo(...) */
1455 
1456 #ifdef HAVE_PRAGMA_PACK
1457 #pragma pack(push, 1)
1458 #endif
1459 typedef struct
1460 {
1461 	unsigned char oem_record_ver_num;
1462 	unsigned char major;
1463 	unsigned char minor;
1464 	unsigned char update;
1465 	unsigned char micro;
1466 	char nano[10];
1467 	char revision[10];
1468 	char version[40];
1469 	/*
1470 	 * When adding new fields (using the spare bytes),
1471 	 * add it immediately after the spare field to
1472 	 * ensure backward compatability.
1473 	 *
1474 	 * e.g.   char version[40];
1475 	 *        unsigned char spare[11];
1476 	 *        int new_item;
1477 	 *    } sunoem_version_response_t;
1478 	 */
1479 	unsigned char spare[15];
1480 }__attribute__((packed)) sunoem_version_response_t;
1481 #ifdef HAVE_PRAGMA_PACK
1482 #pragma pack(pop)
1483 #endif
1484 
1485 typedef struct
1486 {
1487 	unsigned char major;
1488 	unsigned char minor;
1489 	unsigned char update;
1490 	unsigned char micro;
1491 } supported_version_t;
1492 
1493 static int
1494 ipmi_sunoem_getversion(struct ipmi_intf * intf,
1495 		sunoem_version_response_t **version_rsp)
1496 {
1497 	struct ipmi_rs *rsp;
1498 	struct ipmi_rq req;
1499 
1500 	memset(&req, 0, sizeof(req));
1501 	req.msg.netfn = IPMI_NETFN_SUNOEM;
1502 	req.msg.cmd = IPMI_SUNOEM_VERSION;
1503 	req.msg.data = NULL;
1504 	req.msg.data_len = 0;
1505 	rsp = intf->sendrecv(intf, &req);
1506 
1507 	if (rsp == NULL) {
1508 		lprintf(LOG_ERR, "Sun OEM Get SP Version Failed.");
1509 		return (-1);
1510 	}
1511 	if (rsp->ccode != 0) {
1512 		lprintf(LOG_ERR, "Sun OEM Get SP Version Failed: %d", rsp->ccode);
1513 		return (-1);
1514 	}
1515 
1516 	*version_rsp = (sunoem_version_response_t *) rsp->data;
1517 
1518 	return (0);
1519 }
1520 
1521 static void
1522 ipmi_sunoem_print_required_version(const supported_version_t* supp_ver)
1523 {
1524 	lprintf(LOG_ERR, "Command is not supported by this version of ILOM,"
1525 			" required at least: %d.%d.%d.%d", supp_ver->major, supp_ver->minor,
1526 			supp_ver->update, supp_ver->micro);
1527 }
1528 
1529 /*
1530  * Function checks current version result against required version.
1531  * Returns:
1532  *  - negative value if current ILOM version is smaller than required or
1533  *    in case of error
1534  *  - positive value if current ILOM version is greater than required
1535  *  - 0 if there is an exact ILOM version match
1536  */
1537 static int
1538 ipmi_sunoem_checkversion(struct ipmi_intf * intf, supported_version_t* supp_ver)
1539 {
1540 	sunoem_version_response_t *version_rsp;
1541 	int i = 1;
1542 
1543 	if (ipmi_sunoem_getversion(intf, &version_rsp)) {
1544 		lprintf(LOG_ERR, "Unable to get ILOM version");
1545 		return (-1);
1546 	}
1547 
1548 	if (version_rsp->major < supp_ver->major) return (-i);
1549 	if (version_rsp->major > supp_ver->major) return (i);
1550 	/*version_rsp->major == supp_ver->major*/
1551 	++i;
1552 
1553 	if (version_rsp->minor < supp_ver->minor) return (-i);
1554 	if (version_rsp->minor > supp_ver->minor) return (i);
1555 	/*version_rsp->minor == supp_ver->minor*/
1556 	++i;
1557 
1558 	if (version_rsp->update < supp_ver->update) return (-i);
1559 	if (version_rsp->update > supp_ver->update) return (i);
1560 	/*version_rsp->update == supp_ver->update*/
1561 	++i;
1562 
1563 	if (version_rsp->micro < supp_ver->micro) return (-i);
1564 	if (version_rsp->micro > supp_ver->micro) return (i);
1565 	/*version_rsp->micro == supp_ver->micro*/
1566 
1567 	return (0);
1568 }
1569 
1570 /*
1571  * Extract the SP version data including
1572  * - major #
1573  * - minor #
1574  * - update #
1575  * - micro #
1576  * - nano #
1577  * - Revision/Build #
1578  */
1579 static int
1580 ipmi_sunoem_version(struct ipmi_intf * intf)
1581 {
1582 	sunoem_version_response_t *version_rsp;
1583 	int rc = ipmi_sunoem_getversion(intf, &version_rsp);
1584 
1585 	if (!rc) {
1586 		printf("Version: %s\n", version_rsp->version);
1587 	}
1588 
1589 	return (rc);
1590 }
1591 
1592 /*
1593  * IPMI Max string length is 16 bytes
1594  * define in usr/src/common/include/ami/IPMI_SDRRecord.h
1595  */
1596 #define MAX_ID_STR_LEN  16
1597 #define MAX_SUNOEM_NAC_SIZE 64
1598 #define LUAPI_MAX_OBJ_PATH_LEN 256
1599 #define LUAPI_MAX_OBJ_VAL_LEN 1024
1600 
1601 #ifdef HAVE_PRAGMA_PACK
1602 #pragma pack(push, 1)
1603 #endif
1604 typedef struct
1605 {
1606 	unsigned char seq_num;
1607 	char nac_name[MAX_SUNOEM_NAC_SIZE];
1608 }__attribute__((packed)) sunoem_nacname_t;
1609 #ifdef HAVE_PRAGMA_PACK
1610 #pragma pack(pop)
1611 #endif
1612 
1613 /*
1614  * Retrieve the full NAC name of the IPMI target.
1615  *
1616  * The returned nac name may be larger than the payload size.
1617  * In which case, it make take several request/payload to retrieve
1618  * the entire full path name
1619  *
1620  * The initial seq_num is set to 0. If the return seq_num is incremented,
1621  * only the 1st 72 bytes of the nac name is returned and the caller
1622  * needs to get the next set of string data.
1623  * If the returned seq_num is identical to the input seq_num, all data
1624  * has been returned.
1625  */
1626 static int
1627 ipmi_sunoem_nacname(struct ipmi_intf * intf, int argc, char *argv[])
1628 {
1629 	struct ipmi_rs *rsp;
1630 	struct ipmi_rq req;
1631 	sunoem_nacname_t nacname_req;
1632 	sunoem_nacname_t *nacname_rsp;
1633 	char full_nac_name[LUAPI_MAX_OBJ_PATH_LEN];
1634 
1635 	if (argc < 1) {
1636 		return (1);
1637 	}
1638 
1639 	if (strlen(argv[0]) > MAX_ID_STR_LEN) {
1640 		lprintf(LOG_ERR,
1641 				"Sun OEM nacname command failed: Max size on IPMI name");
1642 		return (-1);
1643 	}
1644 
1645 	nacname_req.seq_num = 0;
1646 	strcpy(nacname_req.nac_name, argv[0]);
1647 
1648 	full_nac_name[0] = '\0';
1649 	while (1) {
1650 		memset(&req, 0, sizeof(req));
1651 		req.msg.netfn = IPMI_NETFN_SUNOEM;
1652 		req.msg.cmd = IPMI_SUNOEM_NACNAME;
1653 		req.msg.data = (uint8_t *) &nacname_req;
1654 		req.msg.data_len = sizeof(sunoem_nacname_t);
1655 		rsp = intf->sendrecv(intf, &req);
1656 
1657 		if (rsp == NULL) {
1658 			lprintf(LOG_ERR, "Sun OEM nacname command failed.");
1659 			return (-1);
1660 		}
1661 		if (rsp->ccode != 0) {
1662 			lprintf(LOG_ERR, "Sun OEM nacname command failed: %d", rsp->ccode);
1663 			return (-1);
1664 		}
1665 
1666 		nacname_rsp = (sunoem_nacname_t *) rsp->data;
1667 		strncat(full_nac_name, nacname_rsp->nac_name, MAX_SUNOEM_NAC_SIZE);
1668 
1669 		/*
1670 		 * break out of the loop if there is no more data
1671 		 * In most cases, if not all, the NAC name fits into a
1672 		 * single payload
1673 		 */
1674 		if (nacname_req.seq_num == nacname_rsp->seq_num) {
1675 			break;
1676 		}
1677 
1678 		/* Get the next seq of string bytes */
1679 		nacname_req.seq_num = nacname_rsp->seq_num;
1680 
1681 		/* Check if we exceeded the size of the full nac name */
1682 		if ((nacname_req.seq_num * MAX_SUNOEM_NAC_SIZE) > LUAPI_MAX_OBJ_PATH_LEN) {
1683 			lprintf(LOG_ERR,
1684 					"Sun OEM nacname command failed: invalid path length");
1685 			return (-1);
1686 		}
1687 	}
1688 
1689 	printf("NAC Name: %s\n", full_nac_name);
1690 	return (0);
1691 }
1692 
1693 /* Constants used by ipmi_sunoem_getval */
1694 #define MAX_SUNOEM_VAL_PAYLOAD 79
1695 #define MAX_SUNOEM_VAL_COMPACT_PAYLOAD 56
1696 
1697 /*
1698  * SUNOEM GET/SET LUAPI Commands
1699  *
1700  * SUNOEM_REQ_VAL - Request LUAPI Property Value
1701  * SUNOEM_GET_VAL - Return the value from  SUNOEM_REQ_VAL
1702  * SUNOEM_SET_VAL - Set the LUAPI Property value
1703  * SUNOEM_GET_STATUS - Return the Status from SUNOEM_SET_VAL
1704  */
1705 #define SUNOEM_REQ_VAL 1
1706 #define SUNOEM_GET_VAL 2
1707 #define SUNOEM_SET_VAL 3
1708 #define SUNOEM_GET_STATUS 4
1709 
1710 /* Status Code */
1711 #define SUNOEM_REQ_RECV 1
1712 #define SUNOEM_REQ_FAILED 2
1713 #define SUNOEM_DATA_READY 3
1714 #define SUNOEM_DATA_NOT_READY 4
1715 #define SUNOEM_DATA_NOT_FOUND 5
1716 #define GETVAL_MAX_RETRIES 5
1717 
1718 /* Parameter type Codes */
1719 #define SUNOEM_LUAPI_TARGET 0
1720 #define SUNOEM_LUAPI_VALUE  1
1721 
1722 #ifdef HAVE_PRAGMA_PACK
1723 #pragma pack(push, 1)
1724 #endif
1725 typedef struct
1726 {
1727 	unsigned char cmd_code;
1728 	unsigned char luapi_value[MAX_SUNOEM_VAL_PAYLOAD];
1729 }__attribute__((packed)) sunoem_getval_t;
1730 #ifdef HAVE_PRAGMA_PACK
1731 #pragma pack(pop)
1732 #endif
1733 
1734 /*
1735  * REQUEST PAYLOAD
1736  *
1737  * cmd_code - SUNOEM GET/SET LUAPI Cmds - see above
1738  * param_type: 0: luapi_data contains the luapi property name
1739  *             1: luapi_data contains the luapi value
1740  * luapi_data: Either luapi property name or value
1741  * tid: Transaction ID. If 0. This is the initial request for the
1742  *      param_type. If tid > 0, this luapi_data string is a concatenation
1743  *      of the previous request. Handle cases where the LUAPI target name
1744  *      or value is > MAX_SUNOEM_VAL_COMPACT_PAYLOAD
1745  * eof: If non zero, this is the last payload for the request
1746  */
1747 #ifdef HAVE_PRAGMA_PACK
1748 #pragma pack(push, 1)
1749 #endif
1750 typedef struct
1751 {
1752 	unsigned char cmd_code;
1753 	unsigned char param_type;
1754 	unsigned char tid;
1755 	unsigned char eof;
1756 	char luapi_data[MAX_SUNOEM_VAL_COMPACT_PAYLOAD];
1757 }__attribute__((packed)) sunoem_setval_t;
1758 #ifdef HAVE_PRAGMA_PACK
1759 #pragma pack(pop)
1760 #endif
1761 
1762 /*
1763  * RESPONSE PAYLOAD
1764  *
1765  * status_code - see above for code definitions
1766  * tid - transaction ID - assigned ny the ILOM stack
1767  */
1768 #ifdef HAVE_PRAGMA_PACK
1769 #pragma pack(push, 1)
1770 #endif
1771 typedef struct
1772 {
1773 	unsigned char status_code;
1774 	unsigned char tid;
1775 }__attribute__((packed)) sunoem_setval_resp_t;
1776 #ifdef HAVE_PRAGMA_PACK
1777 #pragma pack(pop)
1778 #endif
1779 
1780 /*
1781  * Return the ILOM target property value
1782  */
1783 static int
1784 ipmi_sunoem_getval(struct ipmi_intf * intf, int argc, char *argv[])
1785 {
1786 	struct ipmi_rs *rsp;
1787 	struct ipmi_rq req;
1788 	sunoem_getval_t getval_req;
1789 	sunoem_getval_t *getval_rsp;
1790 	int i;
1791 
1792 	const char* sp_path = "/SP";
1793 	supported_version_t supp_ver = { 3, 2, 0, 0 };
1794 
1795 	if (argc < 1) {
1796 		return (1);
1797 	}
1798 
1799 	if (strlen(argv[0]) > MAX_SUNOEM_VAL_PAYLOAD) {
1800 		lprintf(LOG_ERR,
1801 				"Sun OEM get value command failed: Max size on IPMI name");
1802 		return (-1);
1803 	}
1804 
1805 	if ((ipmi_sunoem_checkversion(intf, &supp_ver) < 0)
1806 			&& (!strncmp(argv[0], sp_path, strlen(sp_path)))) {
1807 		argv[0][1] = 'X'; /*replace SP by X to gain access to hidden properties*/
1808 		memmove(&argv[0][2], &argv[0][3], strlen(argv[0]) - 2);
1809 	}
1810 
1811 	/*
1812 	 * Setup the initial request to fetch the data.
1813 	 * Upon function return, the next cmd (SUNOEM_GET_VAL)
1814 	 * can be requested.
1815 	 */
1816 	memset(&getval_req, 0, sizeof(getval_req));
1817 	strncpy((char*) getval_req.luapi_value, argv[0], MAX_SUNOEM_VAL_PAYLOAD);
1818 	getval_req.cmd_code = SUNOEM_REQ_VAL;
1819 
1820 	memset(&req, 0, sizeof(req));
1821 	req.msg.netfn = IPMI_NETFN_SUNOEM;
1822 	req.msg.cmd = IPMI_SUNOEM_GETVAL;
1823 	req.msg.data = (uint8_t *) &getval_req;
1824 	req.msg.data_len = sizeof(sunoem_getval_t);
1825 	rsp = intf->sendrecv(intf, &req);
1826 
1827 	if (rsp == NULL) {
1828 		lprintf(LOG_ERR, "Sun OEM getval1 command failed.");
1829 		return (-1);
1830 	}
1831 	if (rsp->ccode != 0) {
1832 		lprintf(LOG_ERR, "Sun OEM getval1 command failed: %d", rsp->ccode);
1833 		return (-1);
1834 	}
1835 
1836 	/*
1837 	 * Fetch the data value - if it is not ready,
1838 	 * retry the request up to GETVAL_MAX_RETRIES
1839 	 */
1840 	for (i = 0; i < GETVAL_MAX_RETRIES; i++) {
1841 		memset(&req, 0, sizeof(req));
1842 		req.msg.netfn = IPMI_NETFN_SUNOEM;
1843 		req.msg.cmd = IPMI_SUNOEM_GETVAL;
1844 		getval_req.cmd_code = SUNOEM_GET_VAL;
1845 		req.msg.data = (uint8_t *) &getval_req;
1846 		req.msg.data_len = sizeof(sunoem_getval_t);
1847 		rsp = intf->sendrecv(intf, &req);
1848 
1849 		if (rsp == NULL) {
1850 			lprintf(LOG_ERR, "Sun OEM getval2 command failed.");
1851 			return (-1);
1852 		}
1853 
1854 		if (rsp->ccode != 0) {
1855 			lprintf(LOG_ERR, "Sun OEM getval2 command failed: %d", rsp->ccode);
1856 			return (-1);
1857 		}
1858 
1859 		getval_rsp = (sunoem_getval_t *) rsp->data;
1860 
1861 		if (getval_rsp->cmd_code == SUNOEM_DATA_READY) {
1862 			printf("Target Value: %s\n", getval_rsp->luapi_value);
1863 			return (0);
1864 		} else if (getval_rsp->cmd_code == SUNOEM_DATA_NOT_FOUND) {
1865 			lprintf(LOG_ERR, "Target: %s not found", getval_req.luapi_value);
1866 			return (-1);
1867 		}
1868 
1869 		sleep(1);
1870 	}
1871 
1872 	lprintf(LOG_ERR, "Unable to retrieve target value.");
1873 	return (-1);
1874 }
1875 
1876 static int
1877 send_luapi_prop_name(struct ipmi_intf * intf, int len, char *prop_name,
1878 		unsigned char *tid_num)
1879 {
1880 	int i = 0;
1881 	struct ipmi_rs *rsp;
1882 	struct ipmi_rq req;
1883 	sunoem_setval_t setval_req;
1884 	sunoem_setval_resp_t *setval_rsp;
1885 
1886 	*tid_num = 0;
1887 	while (i < len) {
1888 		/*
1889 		 * Setup the request,
1890 		 * Upon function return, the next cmd (SUNOEM_SET_VAL)
1891 		 * can be requested.
1892 		 */
1893 		memset(&req, 0, sizeof(req));
1894 		memset(&setval_req, 0, sizeof(sunoem_setval_t));
1895 		req.msg.netfn = IPMI_NETFN_SUNOEM;
1896 		req.msg.cmd = IPMI_SUNOEM_SETVAL;
1897 		setval_req.cmd_code = SUNOEM_SET_VAL;
1898 		setval_req.param_type = SUNOEM_LUAPI_TARGET;
1899 		setval_req.tid = *tid_num;
1900 		setval_req.eof = 0;
1901 		/*
1902 		 * If the property name is > payload, only copy
1903 		 * the payload size and increment the string offset (i)
1904 		 * for the next payload
1905 		 */
1906 		if (strlen(&(prop_name[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
1907 			strncpy(setval_req.luapi_data, &(prop_name[i]),
1908 			MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
1909 		} else {
1910 			strncpy(setval_req.luapi_data, &(prop_name[i]),
1911 					strlen(&(prop_name[i])));
1912 		}
1913 		req.msg.data = (uint8_t *) &setval_req;
1914 		req.msg.data_len = sizeof(sunoem_setval_t);
1915 		rsp = intf->sendrecv(intf, &req);
1916 
1917 		if (rsp == NULL) {
1918 			lprintf(LOG_ERR, "Sun OEM setval prop name: response is NULL");
1919 			return (-1);
1920 		}
1921 
1922 		if (rsp->ccode != 0) {
1923 			lprintf(LOG_ERR, "Sun OEM setval prop name: request failed: %d",
1924 					rsp->ccode);
1925 			return (-1);
1926 		}
1927 
1928 		setval_rsp = (sunoem_setval_resp_t *) rsp->data;
1929 
1930 		/*
1931 		 * If the return code is other than data received, the
1932 		 * request failed
1933 		 */
1934 		if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
1935 			lprintf(LOG_ERR,
1936 					"Sun OEM setval prop name: invalid status code: %d",
1937 					setval_rsp->status_code);
1938 			return (-1);
1939 		}
1940 		/* Use the tid returned by ILOM */
1941 		*tid_num = setval_rsp->tid;
1942 		/* Increment the string offset */
1943 		i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
1944 	}
1945 
1946 	return (0);
1947 }
1948 
1949 static int
1950 send_luapi_prop_value(struct ipmi_intf * intf, int len,	char *prop_value,
1951 		unsigned char tid_num)
1952 {
1953 	int i = 0;
1954 	struct ipmi_rs *rsp;
1955 	struct ipmi_rq req;
1956 	sunoem_setval_t setval_req;
1957 	sunoem_setval_resp_t *setval_rsp;
1958 
1959 	while (i < len) {
1960 		/*
1961 		 * Setup the request,
1962 		 * Upon function return, the next cmd (SUNOEM_GET_VAL)
1963 		 * can be requested.
1964 		 */
1965 		memset(&req, 0, sizeof(req));
1966 		memset(&setval_req, 0, sizeof(sunoem_setval_t));
1967 		req.msg.netfn = IPMI_NETFN_SUNOEM;
1968 		req.msg.cmd = IPMI_SUNOEM_SETVAL;
1969 		setval_req.cmd_code = SUNOEM_SET_VAL;
1970 		setval_req.param_type = SUNOEM_LUAPI_VALUE;
1971 		setval_req.tid = tid_num;
1972 		/*
1973 		 * If the property name is > payload, only copy the
1974 		 * the payload size and increment the string offset
1975 		 * for the next payload
1976 		 */
1977 		if (strlen(&(prop_value[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
1978 			strncpy(setval_req.luapi_data, &(prop_value[i]),
1979 			MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
1980 		} else {
1981 			/* Captured the entire string, mark this as the last payload */
1982 			strncpy(setval_req.luapi_data, &(prop_value[i]),
1983 					strlen(&(prop_value[i])));
1984 			setval_req.eof = 1;
1985 		}
1986 		req.msg.data = (uint8_t *) &setval_req;
1987 		req.msg.data_len = sizeof(sunoem_setval_t);
1988 		rsp = intf->sendrecv(intf, &req);
1989 
1990 		if (rsp == NULL) {
1991 			lprintf(LOG_ERR, "Sun OEM setval prop value: response is NULL");
1992 			return (-1);
1993 		}
1994 
1995 		if (rsp->ccode != 0) {
1996 			lprintf(LOG_ERR, "Sun OEM setval prop value: request failed: %d",
1997 					rsp->ccode);
1998 			return (-1);
1999 		}
2000 
2001 		setval_rsp = (sunoem_setval_resp_t *) rsp->data;
2002 
2003 		/*
2004 		 * If the return code is other than data received, the
2005 		 * request failed
2006 		 */
2007 		if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
2008 			lprintf(LOG_ERR,
2009 					"Sun OEM setval prop value: invalid status code: %d",
2010 					setval_rsp->status_code);
2011 			return (-1);
2012 		}
2013 
2014 		/* Increment the string offset */
2015 		i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
2016 	}
2017 	return (0);
2018 }
2019 
2020 static int
2021 ipmi_sunoem_setval(struct ipmi_intf * intf, int argc, char *argv[])
2022 {
2023 	struct ipmi_rs *rsp;
2024 	struct ipmi_rq req;
2025 	sunoem_setval_t setval_req;
2026 	sunoem_setval_resp_t *setval_rsp;
2027 	int prop_len;
2028 	int value_len;
2029 	int i;
2030 	unsigned char tid_num;
2031 	int retries;
2032 
2033 	prop_len = strlen(argv[0]);
2034 	value_len = strlen(argv[1]);
2035 	if (prop_len > LUAPI_MAX_OBJ_PATH_LEN) {
2036 		lprintf(LOG_ERR,
2037 				"Sun OEM set value command failed: Max size on property name");
2038 		return (-1);
2039 	}
2040 	if (value_len > LUAPI_MAX_OBJ_VAL_LEN) {
2041 		lprintf(LOG_ERR,
2042 				"Sun OEM set value command failed: Max size on property value");
2043 		return (-1);
2044 	}
2045 
2046 	/* Test if there is a timeout specified */
2047 	if (argc == 3) {
2048 		if ((str2int(argv[2], &retries) != 0) || retries < 0) {
2049 			lprintf(LOG_ERR,
2050 					"Invalid input given or out of range for time-out parameter.");
2051 			return (-1);
2052 		}
2053 	} else {
2054 		retries = GETVAL_MAX_RETRIES;
2055 	}
2056 
2057 	/* Send the property name 1st */
2058 	if (send_luapi_prop_name(intf, prop_len, argv[0], &tid_num) != 0) {
2059 		/* return if there is an error */
2060 		return (-1);
2061 	}
2062 
2063 	if (send_luapi_prop_value(intf, value_len, argv[1], tid_num) != 0) {
2064 		/* return if there is an error */
2065 		return (-1);
2066 	}
2067 
2068 	/*
2069 	 * Get The status of the command.
2070 	 * if it is not ready, retry the request up to
2071 	 * GETVAL_MAX_RETRIES
2072 	 */
2073 	for (i = 0; i < retries; i++) {
2074 		memset(&req, 0, sizeof(req));
2075 		req.msg.netfn = IPMI_NETFN_SUNOEM;
2076 		req.msg.cmd = IPMI_SUNOEM_SETVAL;
2077 		setval_req.cmd_code = SUNOEM_GET_STATUS;
2078 		setval_req.tid = tid_num;
2079 		req.msg.data = (uint8_t *) &setval_req;
2080 		req.msg.data_len = sizeof(sunoem_setval_t);
2081 		rsp = intf->sendrecv(intf, &req);
2082 
2083 		if (rsp == NULL) {
2084 			lprintf(LOG_ERR, "Sun OEM setval command failed.");
2085 			return (-1);
2086 		}
2087 
2088 		if (rsp->ccode != 0) {
2089 			lprintf(LOG_ERR, "Sun OEM setval command failed: %d", rsp->ccode);
2090 			return (-1);
2091 		}
2092 
2093 		setval_rsp = (sunoem_setval_resp_t *) rsp->data;
2094 
2095 		if (setval_rsp->status_code == SUNOEM_DATA_READY) {
2096 			printf("Sun OEM setval command successful.\n");
2097 			return (0);
2098 		} else if (setval_rsp->status_code != SUNOEM_DATA_NOT_READY) {
2099 			lprintf(LOG_ERR, "Sun OEM setval command failed.");
2100 			return (-1);
2101 		}
2102 
2103 		sleep(1);
2104 	}
2105 	/* If we reached here, retries exceeded */
2106 	lprintf(LOG_ERR, "Sun OEM setval command failed: Command Timed Out");
2107 
2108 	return (-1);
2109 }
2110 
2111 #define MAX_FILE_DATA_SIZE            1024
2112 #define MAX_FILEID_LEN                16
2113 #define CORE_TUNNEL_SUBCMD_GET_FILE   11
2114 
2115 #ifdef HAVE_PRAGMA_PACK
2116 #pragma pack(push, 1)
2117 #endif
2118 typedef struct
2119 {
2120 	unsigned char cmd_code;
2121 	unsigned char file_id[MAX_FILEID_LEN];
2122 	unsigned int block_num;
2123 }__attribute__((packed)) getfile_req_t;
2124 
2125 typedef struct
2126 {
2127 	unsigned int block_num;
2128 	unsigned int data_size;
2129 	unsigned char eof;
2130 	unsigned char data[MAX_FILE_DATA_SIZE];
2131 }__attribute__((packed)) getfile_rsp_t;
2132 #ifdef HAVE_PRAGMA_PACK
2133 #pragma pack(pop)
2134 #endif
2135 
2136 static int
2137 ipmi_sunoem_getfile(struct ipmi_intf * intf, int argc, char *argv[])
2138 {
2139 	struct ipmi_rs *rsp;
2140 	struct ipmi_rq req;
2141 	getfile_req_t getfile_req;
2142 	getfile_rsp_t *getfile_rsp;
2143 	int block_num = 0;
2144 	int nbo_blk_num; /* Network Byte Order Block Num */
2145 	FILE *fp;
2146 	unsigned data_size;
2147 	supported_version_t supp_ver = IPMI_SUNOEM_GETFILE_VERSION;
2148 
2149 	if (argc < 1) {
2150 		return (-1);
2151 	}
2152 
2153 	/*check if command is supported by this version of ilom*/
2154 	if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
2155 		ipmi_sunoem_print_required_version(&supp_ver);
2156 		return (-1);
2157 	}
2158 
2159 	/*
2160 	 * File ID is < MAX_FILEID_LEN
2161 	 * Save 1 byte for null Terminated string
2162 	 */
2163 	if (strlen(argv[0]) >= MAX_FILE_DATA_SIZE) {
2164 		lprintf(LOG_ERR, "File ID >= %d characters", MAX_FILEID_LEN);
2165 		return (-1);
2166 	}
2167 
2168 	memset(&getfile_req, 0, sizeof(getfile_req));
2169 	strncpy((char*) getfile_req.file_id, argv[0], MAX_FILEID_LEN - 1);
2170 
2171 	/* Create the destination file */
2172 	fp = ipmi_open_file_write(argv[1]);
2173 	if (fp == NULL) {
2174 		lprintf(LOG_ERR, "Unable to open file: %s", argv[1]);
2175 		return (-1);
2176 	}
2177 
2178 	memset(&req, 0, sizeof(req));
2179 	req.msg.netfn = IPMI_NETFN_SUNOEM;
2180 	req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
2181 	req.msg.data = (uint8_t *) &getfile_req;
2182 	req.msg.data_len = sizeof(getfile_req_t);
2183 	getfile_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_FILE;
2184 
2185 	do {
2186 
2187 		nbo_blk_num = htonl(block_num);
2188 		/* Block Num must be in network byte order */
2189 		memcpy(&(getfile_req.block_num), &nbo_blk_num,
2190 				sizeof(getfile_req.block_num));
2191 
2192 		rsp = intf->sendrecv(intf, &req);
2193 
2194 		if (rsp == NULL) {
2195 			lprintf(LOG_ERR, "Sun OEM getfile command failed.");
2196 			fclose(fp);
2197 			return (-1);
2198 		}
2199 		if (rsp->ccode != 0) {
2200 			lprintf(LOG_ERR, "Sun OEM getfile command failed: %d", rsp->ccode);
2201 			fclose(fp);
2202 			return (-1);
2203 		}
2204 
2205 		getfile_rsp = (getfile_rsp_t *) rsp->data;
2206 
2207 		memcpy(&data_size, &(getfile_rsp->data_size),
2208 				sizeof(getfile_rsp->data_size));
2209 		data_size = ntohl(data_size);
2210 
2211 		if (data_size > MAX_FILE_DATA_SIZE) {
2212 			lprintf(LOG_ERR, "Sun OEM getfile invalid data size: %d",
2213 					data_size);
2214 			fclose(fp);
2215 			return (-1);
2216 		}
2217 
2218 		/* Check if Block Num matches */
2219 		if (memcmp(&(getfile_req.block_num), &(getfile_rsp->block_num),
2220 				sizeof(getfile_req.block_num)) != 0) {
2221 			lprintf(LOG_ERR, "Sun OEM getfile Incorrect Block Num Returned");
2222 			lprintf(LOG_ERR, "Expecting: %x Received: %x",
2223 					getfile_req.block_num, getfile_rsp->block_num);
2224 			fclose(fp);
2225 			return (-1);
2226 		}
2227 
2228 		if (fwrite(getfile_rsp->data, 1, data_size, fp) != data_size) {
2229 			lprintf(LOG_ERR, "Sun OEM getfile write failed: %d", rsp->ccode);
2230 			fclose(fp);
2231 			return (-1);
2232 		}
2233 
2234 		block_num++;
2235 	} while (getfile_rsp->eof == 0);
2236 
2237 	fclose(fp);
2238 
2239 	return (0);
2240 }
2241 
2242 /*
2243  * Query BMC for capability/behavior.
2244  */
2245 
2246 #define CORE_TUNNEL_SUBCMD_GET_BEHAVIOR   15
2247 #define SUNOEM_BEHAVIORID_SIZE            32
2248 
2249 #ifdef HAVE_PRAGMA_PACK
2250 #pragma pack(push, 1)
2251 #endif
2252 typedef struct
2253 {
2254 	unsigned char cmd_code;
2255 	unsigned char behavior_id[SUNOEM_BEHAVIORID_SIZE];
2256 }__attribute__((packed)) getbehavior_req_t;
2257 
2258 typedef struct
2259 {
2260 	unsigned char enabled;
2261 }__attribute__((packed)) getbehavior_rsp_t;
2262 #ifdef HAVE_PRAGMA_PACK
2263 #pragma pack(pop)
2264 #endif
2265 
2266 static int
2267 ipmi_sunoem_getbehavior(struct ipmi_intf * intf, int argc, char *argv[])
2268 {
2269 	struct ipmi_rq req;
2270 	struct ipmi_rs *rsp;
2271 	getbehavior_req_t getbehavior_req;
2272 	getbehavior_rsp_t *getbehavior_rsp;
2273 	supported_version_t supp_ver = IPMI_SUNOEM_GETBEHAVIOR_VERSION;
2274 
2275 	if (argc < 1) {
2276 		return (-1);
2277 	}
2278 
2279 	/*check if command is supported by this version of ilom*/
2280 	if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
2281 		ipmi_sunoem_print_required_version(&supp_ver);
2282 		return (-1);
2283 	}
2284 
2285 	/*
2286 	 * Behavior ID is < SUNOEM_BEHAVIORID_SIZE.
2287 	 * Save 1 byte for null terminated string
2288 	 */
2289 	if (strlen(argv[0]) >= SUNOEM_BEHAVIORID_SIZE) {
2290 		lprintf(LOG_ERR, "Behavior ID >= %d characters",
2291 		SUNOEM_BEHAVIORID_SIZE);
2292 		return (-1);
2293 	}
2294 
2295 	memset(&getbehavior_req, 0, sizeof(getbehavior_req));
2296 	strncpy(getbehavior_req.behavior_id, argv[0], SUNOEM_BEHAVIORID_SIZE - 1);
2297 
2298 	memset(&req, 0, sizeof(req));
2299 	req.msg.netfn = IPMI_NETFN_SUNOEM;
2300 	req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
2301 	req.msg.data = (uint8_t *) &getbehavior_req;
2302 	req.msg.data_len = sizeof(getbehavior_req_t);
2303 	getbehavior_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_BEHAVIOR;
2304 
2305 	rsp = intf->sendrecv(intf, &req);
2306 
2307 	if (rsp == NULL) {
2308 		lprintf(LOG_ERR, "Sun OEM getbehavior command failed.");
2309 		return (-1);
2310 	}
2311 
2312 	if (rsp->ccode != 0) {
2313 		lprintf(LOG_ERR, "Sun OEM getbehavior command failed: %d", rsp->ccode);
2314 		return (-1);
2315 	}
2316 
2317 	getbehavior_rsp = (getbehavior_rsp_t *) rsp->data;
2318 	printf("ILOM behavior %s %s enabled\n", getbehavior_req.behavior_id,
2319 			getbehavior_rsp->enabled ? "is" : "is not");
2320 
2321 	return (0);
2322 }
2323 
2324 int
2325 ipmi_sunoem_main(struct ipmi_intf * intf, int argc, char ** argv)
2326 {
2327 	int rc = 0;
2328 
2329 	if (argc == 0 || strcmp(argv[0], "help") == 0) {
2330 		ipmi_sunoem_usage();
2331 		return (0);
2332 	} /* if (argc == 0 || strcmp(argv[0], "help") == 0) */
2333 
2334 	if (strcmp(argv[0], "cli") == 0) {
2335 		rc = ipmi_sunoem_cli(intf, argc - 1, &argv[1]);
2336 	} else if ((strcmp(argv[0], "led") == 0) || (strcmp(argv[0], "sbled") == 0)) {
2337 		if (argc < 2) {
2338 			ipmi_sunoem_usage();
2339 			return (-1);
2340 		}
2341 
2342 		if (strcmp(argv[1], "get") == 0) {
2343 			if (argc < 3) {
2344 				char * arg[] = { "all" };
2345 				rc = ipmi_sunoem_led_get(intf, 1, arg);
2346 			} else {
2347 				rc = ipmi_sunoem_led_get(intf, argc - 2, &(argv[2]));
2348 			}
2349 		} else if (strcmp(argv[1], "set") == 0) {
2350 			if (argc < 4) {
2351 				ipmi_sunoem_usage();
2352 				return (-1);
2353 			}
2354 			rc = ipmi_sunoem_led_set(intf, argc - 2, &(argv[2]));
2355 		} else {
2356 			ipmi_sunoem_usage();
2357 			return (-1);
2358 		}
2359 	} else if (strcmp(argv[0], "sshkey") == 0) {
2360 		uint8_t uid = 0;
2361 		if (argc < 3) {
2362 			ipmi_sunoem_usage();
2363 			return (-1);
2364 		}
2365 		rc = str2uchar(argv[2], &uid);
2366 		if (rc == 0) {
2367 			/* conversion should be OK. */
2368 		} else if (rc == 2) {
2369 			lprintf(LOG_NOTICE, "Invalid interval given.");
2370 			return (-1);
2371 		} else {
2372 			/* defaults to rc = 3 */
2373 			lprintf(LOG_NOTICE, "Given interval is too big.");
2374 			return (-1);
2375 		}
2376 
2377 		if (strcmp(argv[1], "del") == 0) {
2378 			/* number of arguments, three, is already checked at this point */
2379 			rc = ipmi_sunoem_sshkey_del(intf, uid);
2380 		} else if (strcmp(argv[1], "set") == 0) {
2381 			if (argc < 4) {
2382 				ipmi_sunoem_usage();
2383 				return (-1);
2384 			}
2385 			rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]);
2386 		} else {
2387 			ipmi_sunoem_usage();
2388 			return (-1);
2389 		}
2390 	} else if (strcmp(argv[0], "ping") == 0) {
2391 		if (argc < 2) {
2392 			ipmi_sunoem_usage();
2393 			return (-1);
2394 		}
2395 		rc = ipmi_sunoem_echo(intf, argc - 1, &(argv[1]));
2396 	} else if (strcmp(argv[0], "version") == 0) {
2397 		rc = ipmi_sunoem_version(intf);
2398 	} else if (strcmp(argv[0], "nacname") == 0) {
2399 		if (argc < 2) {
2400 			ipmi_sunoem_usage();
2401 			return (-1);
2402 		}
2403 		rc = ipmi_sunoem_nacname(intf, argc - 1, &(argv[1]));
2404 	} else if (strcmp(argv[0], "getval") == 0) {
2405 		if (argc < 2) {
2406 			ipmi_sunoem_usage();
2407 			return (-1);
2408 		}
2409 		rc = ipmi_sunoem_getval(intf, argc - 1, &(argv[1]));
2410 	} else if (strcmp(argv[0], "setval") == 0) {
2411 		if (argc < 3) {
2412 			ipmi_sunoem_usage();
2413 			return (-1);
2414 		}
2415 		rc = ipmi_sunoem_setval(intf, argc - 1, &(argv[1]));
2416 	} else if (strcmp(argv[0], "getfile") == 0) {
2417 		if (argc < 3) {
2418 			ipmi_sunoem_usage();
2419 			return (-1);
2420 		}
2421 		rc = ipmi_sunoem_getfile(intf, argc - 1, &(argv[1]));
2422 	} else if (strcmp(argv[0], "getbehavior") == 0) {
2423 		if (argc < 2) {
2424 			ipmi_sunoem_usage();
2425 			return (-1);
2426 		}
2427 		rc = ipmi_sunoem_getbehavior(intf, argc - 1, &(argv[1]));
2428 	} else {
2429 		lprintf(LOG_ERR, "Invalid sunoem command: %s", argv[0]);
2430 		return (-1);
2431 	} /* if (strcmp(argv[0], "cli") == 0) */
2432 
2433 	return (rc);
2434 }
2435