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 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 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 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 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 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 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 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 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 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 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 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 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 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