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