1 /* 2 * Copyright (c) 2003 Sun Microsystems, Inc. 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 <string.h> 35 #include <strings.h> 36 #include <stdio.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/select.h> 40 #include <sys/time.h> 41 #include <time.h> 42 #include <signal.h> 43 #include <unistd.h> 44 45 #if defined(HAVE_CONFIG_H) 46 # include <config.h> 47 #endif 48 49 #if defined(HAVE_TERMIOS_H) 50 # include <termios.h> 51 #elif defined (HAVE_SYS_TERMIOS_H) 52 # include <sys/termios.h> 53 #endif 54 55 #include <ipmitool/helper.h> 56 #include <ipmitool/log.h> 57 #include <ipmitool/ipmi.h> 58 #include <ipmitool/ipmi_intf.h> 59 #include <ipmitool/ipmi_sol.h> 60 #include <ipmitool/ipmi_strings.h> 61 #include <ipmitool/bswap.h> 62 63 64 #define SOL_PARAMETER_SET_IN_PROGRESS 0x00 65 #define SOL_PARAMETER_SOL_ENABLE 0x01 66 #define SOL_PARAMETER_SOL_AUTHENTICATION 0x02 67 #define SOL_PARAMETER_CHARACTER_INTERVAL 0x03 68 #define SOL_PARAMETER_SOL_RETRY 0x04 69 #define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05 70 #define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE 0x06 71 #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07 72 #define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08 73 74 #define MAX_SOL_RETRY 6 75 76 const struct valstr sol_parameter_vals[] = { 77 { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" }, 78 { SOL_PARAMETER_SOL_ENABLE, "Enable (1)" }, 79 { SOL_PARAMETER_SOL_AUTHENTICATION, "Authentication (2)" }, 80 { SOL_PARAMETER_CHARACTER_INTERVAL, "Character Interval (3)" }, 81 { SOL_PARAMETER_SOL_RETRY, "Retry (4)" }, 82 { SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" }, 83 { SOL_PARAMETER_SOL_VOLATILE_BIT_RATE, "Volatile Bitrate (6)" }, 84 { SOL_PARAMETER_SOL_PAYLOAD_CHANNEL, "Payload Channel (7)" }, 85 { SOL_PARAMETER_SOL_PAYLOAD_PORT, "Payload Port (8)" }, 86 { 0x00, NULL }, 87 }; 88 89 90 static struct timeval _start_keepalive; 91 static struct termios _saved_tio; 92 static int _in_raw_mode = 0; 93 static int _disable_keepalive = 0; 94 static int _use_sol_for_keepalive = 0; 95 static int _keepalive_retries = 0; 96 97 extern int verbose; 98 99 /* 100 * ipmi_sol_payload_access 101 */ 102 int 103 ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel, 104 uint8_t userid, int enable) 105 { 106 struct ipmi_rq req; 107 struct ipmi_rs *rsp; 108 int rc = (-1); 109 uint8_t data[6]; 110 111 memset(&req, 0, sizeof(req)); 112 req.msg.netfn = IPMI_NETFN_APP; 113 req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS; 114 req.msg.data = data; 115 req.msg.data_len = 6; 116 117 memset(data, 0, 6); 118 /* channel */ 119 data[0] = channel & 0xf; 120 /* user id */ 121 data[1] = userid & 0x3f; 122 if (!enable) { 123 /* disable */ 124 data[1] |= 0x40; 125 } 126 /* payload 1 is SOL */ 127 data[2] = 0x02; 128 rsp = intf->sendrecv(intf, &req); 129 if (rsp == NULL) { 130 lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d", 131 enable ? "en" : "dis", userid, channel); 132 rc = (-1); 133 } else if (rsp->ccode != 0) { 134 lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s", 135 enable ? "en" : "dis", userid, channel, 136 val2str(rsp->ccode, completion_code_vals)); 137 rc = (-1); 138 } else { 139 rc = 0; 140 } 141 return rc; 142 } 143 144 int 145 ipmi_sol_payload_access_status(struct ipmi_intf * intf, 146 uint8_t channel, 147 uint8_t userid) 148 { 149 struct ipmi_rq req; 150 struct ipmi_rs *rsp; 151 uint8_t data[2]; 152 153 memset(&req, 0, sizeof(req)); 154 req.msg.netfn = IPMI_NETFN_APP; 155 req.msg.cmd = IPMI_GET_USER_PAYLOAD_ACCESS; 156 req.msg.data = data; 157 req.msg.data_len = sizeof(data); 158 159 data[0] = channel & 0xf; /* channel */ 160 data[1] = userid & 0x3f; /* user id */ 161 rsp = intf->sendrecv(intf, &req); 162 163 if (rsp == NULL) { 164 lprintf(LOG_ERR, "Error. No valid response received."); 165 return -1; 166 } 167 168 switch(rsp->ccode) { 169 case 0x00: 170 if (rsp->data_len != 4) { 171 lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d", 172 userid, channel); 173 return -1; 174 } 175 176 printf("User %d on channel %d is %sabled\n", 177 userid, channel, (rsp->data[0] & 0x02) ? "en":"dis"); 178 return 0; 179 180 default: 181 lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s", 182 userid, channel, 183 val2str(rsp->ccode, completion_code_vals)); 184 return -1; 185 } 186 } 187 188 189 /* 190 * ipmi_get_sol_info 191 */ 192 int 193 ipmi_get_sol_info( 194 struct ipmi_intf * intf, 195 uint8_t channel, 196 struct sol_config_parameters * params) 197 { 198 struct ipmi_rs * rsp; 199 struct ipmi_rq req; 200 uint8_t data[4]; 201 202 memset(&req, 0, sizeof(req)); 203 req.msg.netfn = IPMI_NETFN_TRANSPORT; 204 req.msg.cmd = IPMI_GET_SOL_CONFIG_PARAMETERS; 205 req.msg.data_len = 4; 206 req.msg.data = data; 207 208 /* 209 * set in progress 210 */ 211 memset(data, 0, sizeof(data)); 212 data[0] = channel; /* channel number */ 213 data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */ 214 data[2] = 0x00; /* set selector */ 215 data[3] = 0x00; /* block selector */ 216 217 rsp = intf->sendrecv(intf, &req); 218 if (rsp == NULL) { 219 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 220 val2str(data[1], sol_parameter_vals)); 221 return (-1); 222 } 223 224 switch (rsp->ccode) { 225 case 0x00: 226 if (rsp->data_len == 2) { 227 params->set_in_progress = rsp->data[1]; 228 } else { 229 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 230 "for SOL parameter '%s'", 231 rsp->data_len, 232 val2str(data[1], sol_parameter_vals)); 233 } 234 break; 235 case 0x80: 236 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 237 val2str(data[1], sol_parameter_vals)); 238 break; 239 default: 240 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 241 val2str(data[1], sol_parameter_vals), 242 val2str(rsp->ccode, completion_code_vals)); 243 return (-1); 244 } 245 246 /* 247 * SOL enable 248 */ 249 memset(data, 0, sizeof(data)); 250 data[0] = channel; /* channel number */ 251 data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */ 252 data[2] = 0x00; /* set selector */ 253 data[3] = 0x00; /* block selector */ 254 255 rsp = intf->sendrecv(intf, &req); 256 if (rsp == NULL) { 257 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 258 val2str(data[1], sol_parameter_vals)); 259 return (-1); 260 } 261 262 switch (rsp->ccode) { 263 case 0x00: 264 if (rsp->data_len == 2) { 265 params->enabled = rsp->data[1]; 266 } else { 267 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 268 "for SOL parameter '%s'", 269 rsp->data_len, 270 val2str(data[1], sol_parameter_vals)); 271 } 272 break; 273 case 0x80: 274 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 275 val2str(data[1], sol_parameter_vals)); 276 break; 277 default: 278 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 279 val2str(data[1], sol_parameter_vals), 280 val2str(rsp->ccode, completion_code_vals)); 281 return (-1); 282 } 283 284 /* 285 * SOL authentication 286 */ 287 memset(data, 0, sizeof(data)); 288 data[0] = channel; /* channel number */ 289 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */ 290 data[2] = 0x00; /* set selector */ 291 data[3] = 0x00; /* block selector */ 292 293 rsp = intf->sendrecv(intf, &req); 294 if (rsp == NULL) { 295 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 296 val2str(data[1], sol_parameter_vals)); 297 return (-1); 298 } 299 300 switch (rsp->ccode) { 301 case 0x00: 302 if (rsp->data_len == 2) { 303 params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0); 304 params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0); 305 params->privilege_level = rsp->data[1] & 0x0F; 306 } else { 307 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 308 "for SOL parameter '%s'", 309 rsp->data_len, 310 val2str(data[1], sol_parameter_vals)); 311 } 312 break; 313 case 0x80: 314 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 315 val2str(data[1], sol_parameter_vals)); 316 break; 317 default: 318 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 319 val2str(data[1], sol_parameter_vals), 320 val2str(rsp->ccode, completion_code_vals)); 321 return (-1); 322 } 323 324 /* 325 * Character accumulate interval and character send interval 326 */ 327 memset(data, 0, sizeof(data)); 328 data[0] = channel; /* channel number */ 329 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */ 330 data[2] = 0x00; /* set selector */ 331 data[3] = 0x00; /* block selector */ 332 333 rsp = intf->sendrecv(intf, &req); 334 if (rsp == NULL) { 335 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 336 val2str(data[1], sol_parameter_vals)); 337 return (-1); 338 } 339 340 switch (rsp->ccode) { 341 case 0x00: 342 if (rsp->data_len == 3) { 343 params->character_accumulate_level = rsp->data[1]; 344 params->character_send_threshold = rsp->data[2]; 345 } else { 346 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 347 "for SOL parameter '%s'", 348 rsp->data_len, 349 val2str(data[1], sol_parameter_vals)); 350 } 351 break; 352 case 0x80: 353 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 354 val2str(data[1], sol_parameter_vals)); 355 break; 356 default: 357 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 358 val2str(data[1], sol_parameter_vals), 359 val2str(rsp->ccode, completion_code_vals)); 360 return (-1); 361 } 362 363 /* 364 * SOL retry 365 */ 366 memset(data, 0, sizeof(data)); 367 data[0] = channel; /* channel number */ 368 data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */ 369 data[2] = 0x00; /* set selector */ 370 data[3] = 0x00; /* block selector */ 371 372 rsp = intf->sendrecv(intf, &req); 373 if (rsp == NULL) { 374 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 375 val2str(data[1], sol_parameter_vals)); 376 return (-1); 377 } 378 379 switch (rsp->ccode) { 380 case 0x00: 381 if (rsp->data_len == 3) { 382 params->retry_count = rsp->data[1]; 383 params->retry_interval = rsp->data[2]; 384 } else { 385 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 386 "for SOL parameter '%s'", 387 rsp->data_len, 388 val2str(data[1], sol_parameter_vals)); 389 } 390 break; 391 case 0x80: 392 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 393 val2str(data[1], sol_parameter_vals)); 394 break; 395 default: 396 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 397 val2str(data[1], sol_parameter_vals), 398 val2str(rsp->ccode, completion_code_vals)); 399 return (-1); 400 } 401 402 /* 403 * SOL non-volatile bit rate 404 */ 405 memset(data, 0, sizeof(data)); 406 data[0] = channel; /* channel number */ 407 data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */ 408 data[2] = 0x00; /* set selector */ 409 data[3] = 0x00; /* block selector */ 410 411 rsp = intf->sendrecv(intf, &req); 412 if (rsp == NULL) { 413 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 414 val2str(data[1], sol_parameter_vals)); 415 return (-1); 416 } 417 418 switch (rsp->ccode) { 419 case 0x00: 420 if (rsp->data_len == 2) { 421 params->non_volatile_bit_rate = rsp->data[1] & 0x0F; 422 } else { 423 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 424 "for SOL parameter '%s'", 425 rsp->data_len, 426 val2str(data[1], sol_parameter_vals)); 427 } 428 break; 429 case 0x80: 430 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 431 val2str(data[1], sol_parameter_vals)); 432 break; 433 default: 434 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 435 val2str(data[1], sol_parameter_vals), 436 val2str(rsp->ccode, completion_code_vals)); 437 return (-1); 438 } 439 440 /* 441 * SOL volatile bit rate 442 */ 443 memset(data, 0, sizeof(data)); 444 data[0] = channel; /* channel number */ 445 data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */ 446 data[2] = 0x00; /* set selector */ 447 data[3] = 0x00; /* block selector */ 448 449 rsp = intf->sendrecv(intf, &req); 450 if (rsp == NULL) { 451 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 452 val2str(data[1], sol_parameter_vals)); 453 return (-1); 454 } 455 456 switch (rsp->ccode) { 457 case 0x00: 458 if (rsp->data_len == 2) { 459 params->volatile_bit_rate = rsp->data[1] & 0x0F; 460 } else { 461 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 462 "for SOL parameter '%s'", 463 rsp->data_len, 464 val2str(data[1], sol_parameter_vals)); 465 } 466 break; 467 case 0x80: 468 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", 469 val2str(data[1], sol_parameter_vals)); 470 break; 471 default: 472 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 473 val2str(data[1], sol_parameter_vals), 474 val2str(rsp->ccode, completion_code_vals)); 475 return (-1); 476 } 477 478 /* 479 * SOL payload channel 480 */ 481 memset(data, 0, sizeof(data)); 482 data[0] = channel; /* channel number */ 483 data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */ 484 data[2] = 0x00; /* set selector */ 485 data[3] = 0x00; /* block selector */ 486 487 rsp = intf->sendrecv(intf, &req); 488 if (rsp == NULL) { 489 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 490 val2str(data[1], sol_parameter_vals)); 491 return (-1); 492 } 493 494 switch (rsp->ccode) { 495 case 0x00: 496 if (rsp->data_len == 2) { 497 params->payload_channel = rsp->data[1]; 498 } else { 499 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 500 "for SOL parameter '%s'", 501 rsp->data_len, 502 val2str(data[1], sol_parameter_vals)); 503 } 504 break; 505 case 0x80: 506 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x", 507 val2str(data[1], sol_parameter_vals), channel); 508 params->payload_channel = channel; 509 break; 510 default: 511 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 512 val2str(data[1], sol_parameter_vals), 513 val2str(rsp->ccode, completion_code_vals)); 514 return (-1); 515 } 516 517 /* 518 * SOL payload port 519 */ 520 memset(data, 0, sizeof(data)); 521 data[0] = channel; /* channel number */ 522 data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */ 523 data[2] = 0x00; /* set selector */ 524 data[3] = 0x00; /* block selector */ 525 526 rsp = intf->sendrecv(intf, &req); 527 if (rsp == NULL) { 528 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", 529 val2str(data[1], sol_parameter_vals)); 530 return (-1); 531 } 532 533 switch (rsp->ccode) { 534 case 0x00: 535 if (rsp->data_len == 3) { 536 params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8); 537 } else { 538 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 539 "for SOL parameter '%s'", 540 rsp->data_len, 541 val2str(data[1], sol_parameter_vals)); 542 } 543 break; 544 case 0x80: 545 if( intf->session != NULL ) { 546 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d", 547 val2str(data[1], sol_parameter_vals), intf->session->port); 548 params->payload_port = intf->session->port; 549 } else { 550 lprintf(LOG_ERR, 551 "Info: SOL parameter '%s' not supported - can't determine which " 552 "payload port to use on NULL session", 553 val2str(data[1], sol_parameter_vals)); 554 return (-1); 555 } 556 break; 557 default: 558 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", 559 val2str(data[1], sol_parameter_vals), 560 val2str(rsp->ccode, completion_code_vals)); 561 return (-1); 562 } 563 564 return 0; 565 } 566 567 568 569 /* 570 * ipmi_print_sol_info 571 */ 572 static int 573 ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel) 574 { 575 struct sol_config_parameters params = {0}; 576 if (ipmi_get_sol_info(intf, channel, ¶ms)) 577 return -1; 578 579 if (csv_output) 580 { 581 printf("%s,", 582 val2str(params.set_in_progress & 0x03, 583 ipmi_set_in_progress_vals)); 584 printf("%s,", params.enabled?"true": "false"); 585 printf("%s,", params.force_encryption?"true":"false"); 586 printf("%s,", params.force_encryption?"true":"false"); 587 printf("%s,", 588 val2str(params.privilege_level, ipmi_privlvl_vals)); 589 printf("%d,", params.character_accumulate_level * 5); 590 printf("%d,", params.character_send_threshold); 591 printf("%d,", params.retry_count); 592 printf("%d,", params.retry_interval * 10); 593 594 printf("%s,", 595 val2str(params.volatile_bit_rate, ipmi_bit_rate_vals)); 596 597 printf("%s,", 598 val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals)); 599 600 printf("%d,", params.payload_channel); 601 printf("%d\n", params.payload_port); 602 } 603 else 604 { 605 printf("Set in progress : %s\n", 606 val2str(params.set_in_progress & 0x03, 607 ipmi_set_in_progress_vals)); 608 printf("Enabled : %s\n", 609 params.enabled?"true": "false"); 610 printf("Force Encryption : %s\n", 611 params.force_encryption?"true":"false"); 612 printf("Force Authentication : %s\n", 613 params.force_authentication?"true":"false"); 614 printf("Privilege Level : %s\n", 615 val2str(params.privilege_level, ipmi_privlvl_vals)); 616 printf("Character Accumulate Level (ms) : %d\n", 617 params.character_accumulate_level * 5); 618 printf("Character Send Threshold : %d\n", 619 params.character_send_threshold); 620 printf("Retry Count : %d\n", 621 params.retry_count); 622 printf("Retry Interval (ms) : %d\n", 623 params.retry_interval * 10); 624 625 printf("Volatile Bit Rate (kbps) : %s\n", 626 val2str(params.volatile_bit_rate, ipmi_bit_rate_vals)); 627 628 printf("Non-Volatile Bit Rate (kbps) : %s\n", 629 val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals)); 630 631 printf("Payload Channel : %d (0x%02x)\n", 632 params.payload_channel, params.payload_channel); 633 printf("Payload Port : %d\n", 634 params.payload_port); 635 } 636 637 return 0; 638 } 639 640 641 642 /* 643 * Small function to validate that user-supplied SOL 644 * configuration parameter values we store in uint8_t 645 * data type falls within valid range. With minval 646 * and maxval parameters we can use the same function 647 * to validate parameters that have different ranges 648 * of values. 649 * 650 * function will return -1 if value is not valid, or 651 * will return 0 if valid. 652 */ 653 int ipmi_sol_set_param_isvalid_uint8_t( const char *strval, 654 const char *name, 655 int base, 656 uint8_t minval, 657 uint8_t maxval, 658 uint8_t *out_value) 659 { 660 if (str2uchar(strval, out_value) != 0 || (*out_value < minval) 661 || (*out_value > maxval)) { 662 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 663 strval, name); 664 lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval); 665 return -1; 666 } 667 return 0; 668 } 669 670 671 /* 672 * ipmi_sol_set_param 673 * 674 * Set the specified Serial Over LAN value to the specified 675 * value 676 * 677 * return 0 on success, 678 * -1 on failure 679 */ 680 static int 681 ipmi_sol_set_param(struct ipmi_intf * intf, 682 uint8_t channel, 683 const char * param, 684 const char * value, 685 uint8_t guarded) 686 { 687 struct ipmi_rs * rsp; 688 struct ipmi_rq req; 689 uint8_t data[4]; 690 int bGuarded = guarded; /* Use set-in-progress indicator? */ 691 692 memset(&req, 0, sizeof(req)); 693 req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */ 694 req.msg.cmd = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */ 695 req.msg.data = data; 696 697 data[0] = channel; 698 699 /* 700 * set-in-progress 701 */ 702 if (! strcmp(param, "set-in-progress")) 703 { 704 bGuarded = 0; /* We _ARE_ the set-in-progress indicator */ 705 req.msg.data_len = 3; 706 data[1] = SOL_PARAMETER_SET_IN_PROGRESS; 707 708 if (! strcmp(value, "set-complete")) 709 data[2] = 0x00; 710 else if (! strcmp(value, "set-in-progress")) 711 data[2] = 0x01; 712 else if (! strcmp(value, "commit-write")) 713 data[2] = 0x02; 714 else 715 { 716 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 717 value, param); 718 lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress " 719 "and commit-write"); 720 return -1; 721 } 722 } 723 724 725 /* 726 * enabled 727 */ 728 else if (! strcmp(param, "enabled")) 729 { 730 req.msg.data_len = 3; 731 data[1] = SOL_PARAMETER_SOL_ENABLE; 732 733 if (! strcmp(value, "true")) 734 data[2] = 0x01; 735 else if (! strcmp(value, "false")) 736 data[2] = 0x00; 737 else 738 { 739 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 740 value, param); 741 lprintf(LOG_ERR, "Valid values are true and false"); 742 return -1; 743 } 744 } 745 746 747 /* 748 * force-payload-encryption 749 */ 750 else if (! strcmp(param, "force-encryption")) 751 { 752 struct sol_config_parameters params; 753 754 req.msg.data_len = 3; 755 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; 756 757 if (! strcmp(value, "true")) 758 data[2] = 0x80; 759 else if (! strcmp(value, "false")) 760 data[2] = 0x00; 761 else 762 { 763 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 764 value, param); 765 lprintf(LOG_ERR, "Valid values are true and false"); 766 return -1; 767 } 768 769 770 /* We need other values to complete the request */ 771 if (ipmi_get_sol_info(intf, channel, ¶ms)) 772 { 773 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 774 param); 775 return -1; 776 } 777 778 data[2] |= params.force_authentication? 0x40 : 0x00; 779 data[2] |= params.privilege_level; 780 } 781 782 783 /* 784 * force-payload-authentication 785 */ 786 else if (! strcmp(param, "force-authentication")) 787 { 788 struct sol_config_parameters params; 789 790 req.msg.data_len = 3; 791 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; 792 793 if (! strcmp(value, "true")) 794 data[2] = 0x40; 795 else if (! strcmp(value, "false")) 796 data[2] = 0x00; 797 else 798 { 799 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 800 value, param); 801 lprintf(LOG_ERR, "Valid values are true and false"); 802 return -1; 803 } 804 805 806 /* We need other values to complete the request */ 807 if (ipmi_get_sol_info(intf, channel, ¶ms)) 808 { 809 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 810 param); 811 return -1; 812 } 813 814 data[2] |= params.force_encryption? 0x80 : 0x00; 815 data[2] |= params.privilege_level; 816 } 817 818 819 /* 820 * privilege-level 821 */ 822 else if (! strcmp(param, "privilege-level")) 823 { 824 struct sol_config_parameters params; 825 826 req.msg.data_len = 3; 827 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; 828 829 if (! strcmp(value, "user")) 830 data[2] = 0x02; 831 else if (! strcmp(value, "operator")) 832 data[2] = 0x03; 833 else if (! strcmp(value, "admin")) 834 data[2] = 0x04; 835 else if (! strcmp(value, "oem")) 836 data[2] = 0x05; 837 else 838 { 839 lprintf(LOG_ERR, "Invalid value %s for parameter %s", 840 value, param); 841 lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem"); 842 return -1; 843 } 844 845 846 /* We need other values to complete the request */ 847 if (ipmi_get_sol_info(intf, channel, ¶ms)) 848 { 849 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 850 param); 851 return -1; 852 } 853 854 data[2] |= params.force_encryption? 0x80 : 0x00; 855 data[2] |= params.force_authentication? 0x40 : 0x00; 856 } 857 858 859 /* 860 * character-accumulate-level 861 */ 862 else if (! strcmp(param, "character-accumulate-level")) 863 { 864 struct sol_config_parameters params; 865 866 req.msg.data_len = 4; 867 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; 868 869 /* validate user-supplied input */ 870 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2])) 871 return -1; 872 873 /* We need other values to complete the request */ 874 if (ipmi_get_sol_info(intf, channel, ¶ms)) 875 { 876 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 877 param); 878 return -1; 879 } 880 881 data[3] = params.character_send_threshold; 882 } 883 884 885 /* 886 * character-send-threshold 887 */ 888 else if (! strcmp(param, "character-send-threshold")) 889 { 890 struct sol_config_parameters params; 891 892 req.msg.data_len = 4; 893 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; 894 895 /* validate user-supplied input */ 896 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3])) 897 return -1; 898 899 /* We need other values to complete the request */ 900 if (ipmi_get_sol_info(intf, channel, ¶ms)) 901 { 902 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 903 param); 904 return -1; 905 } 906 907 data[2] = params.character_accumulate_level; 908 } 909 910 911 /* 912 * retry-count 913 */ 914 else if (! strcmp(param, "retry-count")) 915 { 916 struct sol_config_parameters params; 917 918 req.msg.data_len = 4; 919 data[1] = SOL_PARAMETER_SOL_RETRY; 920 921 /* validate user input, 7 is max value */ 922 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2])) 923 return -1; 924 925 /* We need other values to complete the request */ 926 if (ipmi_get_sol_info(intf, channel, ¶ms)) 927 { 928 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 929 param); 930 return -1; 931 } 932 933 data[3] = params.retry_interval; 934 } 935 936 937 /* 938 * retry-interval 939 */ 940 else if (! strcmp(param, "retry-interval")) 941 { 942 struct sol_config_parameters params; 943 944 req.msg.data_len = 4; 945 data[1] = SOL_PARAMETER_SOL_RETRY; 946 947 /* validate user-supplied input */ 948 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3])) 949 return -1; 950 951 /* We need other values to complete the request */ 952 if (ipmi_get_sol_info(intf, channel, ¶ms)) 953 { 954 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", 955 param); 956 return -1; 957 } 958 959 data[2] = params.retry_count; 960 } 961 962 963 /* 964 * non-volatile-bit-rate 965 */ 966 else if (! strcmp(param, "non-volatile-bit-rate")) 967 { 968 req.msg.data_len = 3; 969 data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; 970 971 if (!strcmp(value, "serial")) 972 { 973 data[2] = 0x00; 974 } 975 else if (!strcmp(value, "9.6")) 976 { 977 data[2] = 0x06; 978 } 979 else if (!strcmp(value, "19.2")) 980 { 981 data[2] = 0x07; 982 } 983 else if (!strcmp(value, "38.4")) 984 { 985 data[2] = 0x08; 986 } 987 else if (!strcmp(value, "57.6")) 988 { 989 data[2] = 0x09; 990 } 991 else if (!strcmp(value, "115.2")) 992 { 993 data[2] = 0x0A; 994 } 995 else 996 { 997 lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"", 998 value, 999 param); 1000 lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2"); 1001 return -1; 1002 } 1003 } 1004 1005 1006 /* 1007 * volatile-bit-rate 1008 */ 1009 else if (! strcmp(param, "volatile-bit-rate")) 1010 { 1011 req.msg.data_len = 3; 1012 data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; 1013 1014 if (!strcmp(value, "serial")) 1015 { 1016 data[2] = 0x00; 1017 } 1018 else if (!strcmp(value, "9.6")) 1019 { 1020 data[2] = 0x06; 1021 } 1022 else if (!strcmp(value, "19.2")) 1023 { 1024 data[2] = 0x07; 1025 } 1026 else if (!strcmp(value, "38.4")) 1027 { 1028 data[2] = 0x08; 1029 } 1030 else if (!strcmp(value, "57.6")) 1031 { 1032 data[2] = 0x09; 1033 } 1034 else if (!strcmp(value, "115.2")) 1035 { 1036 data[2] = 0x0A; 1037 } 1038 else 1039 { 1040 lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"", 1041 value, 1042 param); 1043 lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2"); 1044 return -1; 1045 } 1046 } 1047 else 1048 { 1049 lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param); 1050 return -1; 1051 } 1052 1053 1054 /* 1055 * Execute the request 1056 */ 1057 if (bGuarded && 1058 (ipmi_sol_set_param(intf, 1059 channel, 1060 "set-in-progress", 1061 "set-in-progress", 1062 bGuarded))) 1063 { 1064 lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param); 1065 return -1; 1066 } 1067 1068 1069 /* The command proper */ 1070 rsp = intf->sendrecv(intf, &req); 1071 1072 if (rsp == NULL) { 1073 lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param); 1074 return -1; 1075 } 1076 1077 if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) && 1078 rsp->ccode > 0) { 1079 switch (rsp->ccode) { 1080 case 0x80: 1081 lprintf(LOG_ERR, "Error setting SOL parameter '%s': " 1082 "Parameter not supported", param); 1083 break; 1084 case 0x81: 1085 lprintf(LOG_ERR, "Error setting SOL parameter '%s': " 1086 "Attempt to set set-in-progress when not in set-complete state", 1087 param); 1088 break; 1089 case 0x82: 1090 lprintf(LOG_ERR, "Error setting SOL parameter '%s': " 1091 "Attempt to write read-only parameter", param); 1092 break; 1093 case 0x83: 1094 lprintf(LOG_ERR, "Error setting SOL parameter '%s': " 1095 "Attempt to read write-only parameter", param); 1096 break; 1097 default: 1098 lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s", 1099 param, value, val2str(rsp->ccode, completion_code_vals)); 1100 break; 1101 } 1102 1103 if (bGuarded && 1104 (ipmi_sol_set_param(intf, 1105 channel, 1106 "set-in-progress", 1107 "set-complete", 1108 bGuarded))) 1109 { 1110 lprintf(LOG_ERR, "Error could not set \"set-in-progress\" " 1111 "to \"set-complete\""); 1112 } 1113 1114 return -1; 1115 } 1116 1117 1118 /* 1119 * The commit write could very well fail, but that's ok. 1120 * It may not be implemented. 1121 */ 1122 if (bGuarded) 1123 ipmi_sol_set_param(intf, 1124 channel, 1125 "set-in-progress", 1126 "commit-write", 1127 bGuarded); 1128 1129 1130 if (bGuarded && 1131 ipmi_sol_set_param(intf, 1132 channel, 1133 "set-in-progress", 1134 "set-complete", 1135 bGuarded)) 1136 { 1137 lprintf(LOG_ERR, "Error could not set \"set-in-progress\" " 1138 "to \"set-complete\""); 1139 return -1; 1140 } 1141 1142 return 0; 1143 } 1144 1145 1146 1147 void 1148 leave_raw_mode(void) 1149 { 1150 if (!_in_raw_mode) 1151 return; 1152 if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) 1153 perror("tcsetattr"); 1154 else 1155 _in_raw_mode = 0; 1156 } 1157 1158 1159 1160 void 1161 enter_raw_mode(void) 1162 { 1163 struct termios tio; 1164 if (tcgetattr(fileno(stdin), &tio) == -1) { 1165 perror("tcgetattr"); 1166 return; 1167 } 1168 _saved_tio = tio; 1169 tio.c_iflag |= IGNPAR; 1170 tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); 1171 tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); 1172 // #ifdef IEXTEN 1173 tio.c_lflag &= ~IEXTEN; 1174 // #endif 1175 tio.c_oflag &= ~OPOST; 1176 tio.c_cc[VMIN] = 1; 1177 tio.c_cc[VTIME] = 0; 1178 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) 1179 perror("tcsetattr"); 1180 else 1181 _in_raw_mode = 1; 1182 } 1183 1184 1185 static void 1186 sendBreak(struct ipmi_intf * intf) 1187 { 1188 struct ipmi_v2_payload v2_payload; 1189 1190 memset(&v2_payload, 0, sizeof(v2_payload)); 1191 1192 v2_payload.payload.sol_packet.character_count = 0; 1193 v2_payload.payload.sol_packet.generate_break = 1; 1194 1195 intf->send_sol(intf, &v2_payload); 1196 } 1197 1198 1199 1200 /* 1201 * suspendSelf 1202 * 1203 * Put ourself in the background 1204 * 1205 * param bRestoreTty specifies whether we will put our self back 1206 * in raw mode when we resume 1207 */ 1208 static void 1209 suspendSelf(int bRestoreTty) 1210 { 1211 leave_raw_mode(); 1212 kill(getpid(), SIGTSTP); 1213 1214 if (bRestoreTty) 1215 enter_raw_mode(); 1216 } 1217 1218 1219 1220 /* 1221 * printSolEscapeSequences 1222 * 1223 * Send some useful documentation to the user 1224 */ 1225 static void 1226 printSolEscapeSequences(struct ipmi_intf * intf) 1227 { 1228 printf( 1229 "%c?\n\ 1230 Supported escape sequences:\n\ 1231 %c. - terminate connection\n\ 1232 %c^Z - suspend ipmitool\n\ 1233 %c^X - suspend ipmitool, but don't restore tty on restart\n\ 1234 %cB - send break\n\ 1235 %c? - this message\n\ 1236 %c%c - send the escape character by typing it twice\n\ 1237 (Note that escapes are only recognized immediately after newline.)\n", 1238 intf->session->sol_escape_char, 1239 intf->session->sol_escape_char, 1240 intf->session->sol_escape_char, 1241 intf->session->sol_escape_char, 1242 intf->session->sol_escape_char, 1243 intf->session->sol_escape_char, 1244 intf->session->sol_escape_char, 1245 intf->session->sol_escape_char); 1246 } 1247 1248 1249 1250 /* 1251 * output 1252 * 1253 * Send the specified data to stdout 1254 */ 1255 static void 1256 output(struct ipmi_rs * rsp) 1257 { 1258 /* Add checks to make sure it is actually SOL data, in general I see 1259 * outside code mostly trying to guard against this happening, but 1260 * some places fail to do so, so I do so here to make sure nothing gets 1261 * through. If non-sol data comes through here, there is probably 1262 * a packet that won't get processed somewhere else, but the alternative 1263 * of outputting corrupt data is worse. Generally I see the get device 1264 * id response make it here somehow. I assume it is a heartbeat and the 1265 * other code will retry if it cares about the response and misses it. 1266 */ 1267 if (rsp && 1268 (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && 1269 (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)) 1270 { 1271 int i; 1272 1273 for (i = 0; i < rsp->data_len; ++i) 1274 putc(rsp->data[i], stdout); 1275 1276 fflush(stdout); 1277 } 1278 } 1279 1280 1281 1282 /* 1283 * ipmi_sol_deactivate 1284 */ 1285 static int 1286 ipmi_sol_deactivate(struct ipmi_intf * intf, int instance) 1287 { 1288 struct ipmi_rs * rsp; 1289 struct ipmi_rq req; 1290 uint8_t data[6]; 1291 1292 if ((instance <= 0) || (instance > 15)) { 1293 lprintf(LOG_ERR, "Error: Instance must range from 1 to 15"); 1294 return -1; 1295 } 1296 1297 memset(&req, 0, sizeof(req)); 1298 req.msg.netfn = IPMI_NETFN_APP; 1299 req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD; 1300 req.msg.data_len = 6; 1301 req.msg.data = data; 1302 1303 memset(data, 0, sizeof(data)); 1304 data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */ 1305 data[1] = instance; /* payload instance. */ 1306 1307 /* Lots of important data */ 1308 data[2] = 0; 1309 data[3] = 0; 1310 data[4] = 0; 1311 data[5] = 0; 1312 1313 rsp = intf->sendrecv(intf, &req); 1314 1315 if (NULL != rsp) { 1316 switch (rsp->ccode) { 1317 case 0x00: 1318 return 0; 1319 case 0x80: 1320 lprintf(LOG_ERR, "Info: SOL payload already de-activated"); 1321 break; 1322 case 0x81: 1323 lprintf(LOG_ERR, "Info: SOL payload type disabled"); 1324 break; 1325 default: 1326 lprintf(LOG_ERR, "Error de-activating SOL payload: %s", 1327 val2str(rsp->ccode, completion_code_vals)); 1328 break; 1329 } 1330 } else { 1331 lprintf(LOG_ERR, "Error: No response de-activating SOL payload"); 1332 } 1333 1334 return -1; 1335 } 1336 1337 1338 1339 /* 1340 * processSolUserInput 1341 * 1342 * Act on user input into the SOL session. The only reason this 1343 * is complicated is that we have to process escape sequences. 1344 * 1345 * return 0 on success 1346 * 1 if we should exit 1347 * < 0 on error (BMC probably closed the session) 1348 */ 1349 static int 1350 processSolUserInput( 1351 struct ipmi_intf * intf, 1352 uint8_t * input, 1353 uint16_t buffer_length) 1354 { 1355 static int escape_pending = 0; 1356 static int last_was_cr = 1; 1357 struct ipmi_v2_payload v2_payload; 1358 int length = 0; 1359 int retval = 0; 1360 char ch; 1361 int i; 1362 1363 memset(&v2_payload, 0, sizeof(v2_payload)); 1364 1365 /* 1366 * Our first order of business is to check the input for escape 1367 * sequences to act on. 1368 */ 1369 for (i = 0; i < buffer_length; ++i) 1370 { 1371 ch = input[i]; 1372 1373 if (escape_pending){ 1374 escape_pending = 0; 1375 1376 /* 1377 * Process a possible escape sequence. 1378 */ 1379 switch (ch) { 1380 case '.': 1381 printf("%c. [terminated ipmitool]\n", 1382 intf->session->sol_escape_char); 1383 retval = 1; 1384 break; 1385 1386 case 'Z' - 64: 1387 printf("%c^Z [suspend ipmitool]\n", 1388 intf->session->sol_escape_char); 1389 suspendSelf(1); /* Restore tty back to raw */ 1390 continue; 1391 1392 case 'X' - 64: 1393 printf("%c^Z [suspend ipmitool]\n", 1394 intf->session->sol_escape_char); 1395 suspendSelf(0); /* Don't restore to raw mode */ 1396 continue; 1397 1398 case 'B': 1399 printf("%cB [send break]\n", 1400 intf->session->sol_escape_char); 1401 sendBreak(intf); 1402 continue; 1403 1404 case '?': 1405 printSolEscapeSequences(intf); 1406 continue; 1407 1408 default: 1409 if (ch != intf->session->sol_escape_char) 1410 v2_payload.payload.sol_packet.data[length++] = 1411 intf->session->sol_escape_char; 1412 v2_payload.payload.sol_packet.data[length++] = ch; 1413 } 1414 } 1415 1416 else 1417 { 1418 if (last_was_cr && (ch == intf->session->sol_escape_char)) { 1419 escape_pending = 1; 1420 continue; 1421 } 1422 1423 v2_payload.payload.sol_packet.data[length++] = ch; 1424 } 1425 1426 1427 /* 1428 * Normal character. Record whether it was a newline. 1429 */ 1430 last_was_cr = (ch == '\r' || ch == '\n'); 1431 } 1432 1433 1434 /* 1435 * If there is anything left to process we dispatch it to the BMC, 1436 * send intf->session->sol_data.max_outbound_payload_size bytes 1437 * at a time. 1438 */ 1439 if (length) 1440 { 1441 struct ipmi_rs * rsp = NULL; 1442 int try = 0; 1443 1444 while (try < intf->session->retry) { 1445 1446 v2_payload.payload.sol_packet.character_count = length; 1447 1448 rsp = intf->send_sol(intf, &v2_payload); 1449 1450 if (rsp) 1451 { 1452 break; 1453 } 1454 1455 usleep(5000); 1456 try++; 1457 } 1458 1459 if (! rsp) 1460 { 1461 lprintf(LOG_ERR, "Error sending SOL data: FAIL"); 1462 retval = -1; 1463 } 1464 1465 /* If the sequence number is set we know we have new data */ 1466 if (retval == 0) 1467 if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && 1468 (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) && 1469 (rsp->payload.sol_packet.packet_sequence_number)) 1470 output(rsp); 1471 } 1472 1473 return retval; 1474 } 1475 1476 static int 1477 ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf) 1478 { 1479 struct ipmi_v2_payload v2_payload; 1480 struct timeval end; 1481 1482 if (_disable_keepalive) 1483 return 0; 1484 1485 gettimeofday(&end, 0); 1486 1487 if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) { 1488 memset(&v2_payload, 0, sizeof(v2_payload)); 1489 v2_payload.payload.sol_packet.character_count = 0; 1490 if (intf->send_sol(intf, &v2_payload) == NULL) 1491 return -1; 1492 /* good return, reset start time */ 1493 gettimeofday(&_start_keepalive, 0); 1494 } 1495 return 0; 1496 } 1497 1498 static int 1499 ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf) 1500 { 1501 struct timeval end; 1502 1503 if (_disable_keepalive) 1504 return 0; 1505 1506 gettimeofday(&end, 0); 1507 1508 if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) { 1509 if (intf->keepalive(intf) != 0) 1510 return -1; 1511 /* good return, reset start time */ 1512 gettimeofday(&_start_keepalive, 0); 1513 } 1514 return 0; 1515 } 1516 1517 1518 1519 /* 1520 * ipmi_sol_red_pill 1521 */ 1522 static int 1523 ipmi_sol_red_pill(struct ipmi_intf * intf, int instance) 1524 { 1525 char * buffer; 1526 int numRead; 1527 int bShouldExit = 0; 1528 int bBmcClosedSession = 0; 1529 fd_set read_fds; 1530 struct timeval tv; 1531 int retval; 1532 int buffer_size = intf->session->sol_data.max_inbound_payload_size; 1533 int keepAliveRet = 0; 1534 int retrySol = 0; 1535 1536 /* Subtract SOL header from max_inbound_payload_size */ 1537 if (buffer_size > 4) 1538 buffer_size -= 4; 1539 1540 buffer = (char*)malloc(buffer_size); 1541 if (buffer == NULL) { 1542 lprintf(LOG_ERR, "ipmitool: malloc failure"); 1543 return -1; 1544 } 1545 1546 /* Initialize keepalive start time */ 1547 gettimeofday(&_start_keepalive, 0); 1548 1549 enter_raw_mode(); 1550 1551 while (! bShouldExit) 1552 { 1553 FD_ZERO(&read_fds); 1554 FD_SET(0, &read_fds); 1555 FD_SET(intf->fd, &read_fds); 1556 1557 if (!ipmi_oem_active(intf,"i82571spt")) 1558 { 1559 /* Send periodic keepalive packet */ 1560 if(_use_sol_for_keepalive == 0) 1561 { 1562 keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf); 1563 } 1564 else 1565 { 1566 keepAliveRet = ipmi_sol_keepalive_using_sol(intf); 1567 } 1568 1569 if (keepAliveRet != 0) 1570 { 1571 /* 1572 * Retrying the keep Alive before declaring a communication 1573 * lost state with the IPMC. Helpful when the payload is 1574 * reset and brings down the connection temporarily. Otherwise, 1575 * if we send getDevice Id to check the status of IPMC during 1576 * this down time when the connection is restarting, SOL will 1577 * exit even though the IPMC is available and the session is open. 1578 */ 1579 if (retrySol == MAX_SOL_RETRY) 1580 { 1581 /* no response to Get Device ID keepalive message */ 1582 bShouldExit = 1; 1583 continue; 1584 } 1585 else 1586 { 1587 retrySol++; 1588 } 1589 } 1590 else 1591 { 1592 /* if the keep Alive is successful reset retries to zero */ 1593 retrySol = 0; 1594 } 1595 } /* !oem="i82571spt" */ 1596 /* Wait up to half a second */ 1597 tv.tv_sec = 0; 1598 tv.tv_usec = 500000; 1599 1600 retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv); 1601 1602 if (retval) 1603 { 1604 if (retval == -1) 1605 { 1606 /* ERROR */ 1607 perror("select"); 1608 return -1; 1609 } 1610 1611 1612 /* 1613 * Process input from the user 1614 */ 1615 if (FD_ISSET(0, &read_fds)) 1616 { 1617 memset(buffer, 0, buffer_size); 1618 numRead = read(fileno(stdin), 1619 buffer, 1620 buffer_size); 1621 1622 if (numRead > 0) 1623 { 1624 int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead); 1625 1626 if (rc) 1627 { 1628 if (rc < 0) 1629 bShouldExit = bBmcClosedSession = 1; 1630 else 1631 bShouldExit = 1; 1632 } 1633 } 1634 else 1635 { 1636 bShouldExit = 1; 1637 } 1638 } 1639 1640 1641 /* 1642 * Process input from the BMC 1643 */ 1644 else if (FD_ISSET(intf->fd, &read_fds)) 1645 { 1646 struct ipmi_rs * rs =intf->recv_sol(intf); 1647 if ( rs) 1648 { 1649 output(rs); 1650 } 1651 /* 1652 * Should recv_sol come back null, the incoming packet was not ours. 1653 * Just fall through, the keepalive logic will determine if 1654 * the BMC has dropped the session. 1655 */ 1656 } 1657 1658 1659 /* 1660 * ERROR in select 1661 */ 1662 else 1663 { 1664 lprintf(LOG_ERR, "Error: Select returned with nothing to read"); 1665 bShouldExit = 1; 1666 } 1667 } 1668 } 1669 1670 leave_raw_mode(); 1671 1672 if (keepAliveRet != 0) 1673 { 1674 lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session"); 1675 /* attempt to clean up anyway */ 1676 ipmi_sol_deactivate(intf, instance); 1677 exit(1); 1678 } 1679 1680 if (bBmcClosedSession) 1681 { 1682 lprintf(LOG_ERR, "SOL session closed by BMC"); 1683 exit(1); 1684 } 1685 else 1686 ipmi_sol_deactivate(intf, instance); 1687 1688 return 0; 1689 } 1690 1691 1692 1693 1694 /* 1695 * ipmi_sol_activate 1696 */ 1697 static int 1698 ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval, 1699 int instance) 1700 { 1701 struct ipmi_rs * rsp; 1702 struct ipmi_rq req; 1703 struct activate_payload_rsp ap_rsp; 1704 uint8_t data[6]; 1705 uint8_t bSolEncryption = 1; 1706 uint8_t bSolAuthentication = 1; 1707 1708 /* 1709 * This command is only available over RMCP+ (the lanplus 1710 * interface). 1711 */ 1712 if (strncmp(intf->name, "lanplus", 7) != 0) 1713 { 1714 lprintf(LOG_ERR, "Error: This command is only available over the " 1715 "lanplus interface"); 1716 return -1; 1717 } 1718 1719 if ((instance <= 0) || (instance > 15)) { 1720 lprintf(LOG_ERR, "Error: Instance must range from 1 to 15"); 1721 return -1; 1722 } 1723 1724 1725 /* 1726 * Setup a callback so that the lanplus processing knows what 1727 * to do with packets that come unexpectedly (while waiting for 1728 * an ACK, perhaps. 1729 */ 1730 intf->session->sol_data.sol_input_handler = output; 1731 1732 1733 memset(&req, 0, sizeof(req)); 1734 req.msg.netfn = IPMI_NETFN_APP; 1735 req.msg.cmd = IPMI_ACTIVATE_PAYLOAD; 1736 req.msg.data_len = 6; 1737 req.msg.data = data; 1738 1739 data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */ 1740 data[1] = instance; /* payload instance */ 1741 1742 /* Lots of important data. Most is default */ 1743 data[2] = bSolEncryption? 0x80 : 0; 1744 data[2] |= bSolAuthentication? 0x40 : 0; 1745 data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED; 1746 1747 if (ipmi_oem_active(intf, "intelplus")) { 1748 data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE; 1749 } else if (ipmi_oem_active(intf, "i82571spt")) { 1750 /* 1751 * A quote from Intel: "Engineering believes the problem 1752 * lies within the Auxiliary data being sent with the 1753 * 'Activate Payload' command from IPMITool. IPMITool 1754 * sends a C6h which sets some bits having to do with 1755 * encryption and some behavior dealing with CTS DCD/DSR. 1756 * I recommend that the customer modify this request 1757 * to send 08h instead. This is what our internal utility 1758 * sends and it works without issue. I will work with 1759 * engineering to ensure the settings that IPMITool uses 1760 * (C6h) are supported in the future. 1761 */ 1762 data[2] = 0x08; 1763 } else { 1764 data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE; 1765 } 1766 1767 data[3] = 0x00; /* reserved */ 1768 data[4] = 0x00; /* reserved */ 1769 data[5] = 0x00; /* reserved */ 1770 1771 rsp = intf->sendrecv(intf, &req); 1772 1773 if (NULL != rsp) { 1774 switch (rsp->ccode) { 1775 case 0x00: 1776 if (rsp->data_len == 12) { 1777 break; 1778 } else { 1779 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " 1780 "in payload activation response", 1781 rsp->data_len); 1782 return -1; 1783 } 1784 break; 1785 case 0x80: 1786 lprintf(LOG_ERR, "Info: SOL payload already active on another session"); 1787 return -1; 1788 case 0x81: 1789 lprintf(LOG_ERR, "Info: SOL payload disabled"); 1790 return -1; 1791 case 0x82: 1792 lprintf(LOG_ERR, "Info: SOL payload activation limit reached"); 1793 return -1; 1794 case 0x83: 1795 lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption"); 1796 return -1; 1797 case 0x84: 1798 lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption"); 1799 return -1; 1800 default: 1801 lprintf(LOG_ERR, "Error activating SOL payload: %s", 1802 val2str(rsp->ccode, completion_code_vals)); 1803 return -1; 1804 } 1805 } else { 1806 lprintf(LOG_ERR, "Error: No response activating SOL payload"); 1807 return -1; 1808 } 1809 1810 1811 memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp)); 1812 1813 intf->session->sol_data.max_inbound_payload_size = 1814 (ap_rsp.inbound_payload_size[1] << 8) | 1815 ap_rsp.inbound_payload_size[0]; 1816 1817 intf->session->sol_data.max_outbound_payload_size = 1818 (ap_rsp.outbound_payload_size[1] << 8) | 1819 ap_rsp.outbound_payload_size[0]; 1820 1821 intf->session->sol_data.port = 1822 (ap_rsp.payload_udp_port[1] << 8) | 1823 ap_rsp.payload_udp_port[0]; 1824 1825 intf->session->timeout = 1; 1826 1827 1828 /* NOTE: the spec does allow for SOL traffic to be sent on 1829 * a different port. we do not yet support that feature. */ 1830 if (intf->session->sol_data.port != intf->session->port) 1831 { 1832 /* try byteswapping port in case BMC sent it incorrectly */ 1833 uint16_t portswap = BSWAP_16(intf->session->sol_data.port); 1834 1835 if (portswap == intf->session->port) { 1836 intf->session->sol_data.port = portswap; 1837 } 1838 else { 1839 lprintf(LOG_ERR, "Error: BMC requests SOL session on different port"); 1840 return -1; 1841 } 1842 } 1843 1844 printf("[SOL Session operational. Use %c? for help]\n", 1845 intf->session->sol_escape_char); 1846 1847 if(looptest == 1) 1848 { 1849 ipmi_sol_deactivate(intf, instance); 1850 usleep(interval*1000); 1851 return 0; 1852 } 1853 1854 /* 1855 * At this point we are good to go with our SOL session. We 1856 * need to listen to 1857 * 1) STDIN for user input 1858 * 2) The FD for incoming SOL packets 1859 */ 1860 if (ipmi_sol_red_pill(intf, instance)) 1861 { 1862 lprintf(LOG_ERR, "Error in SOL session"); 1863 return -1; 1864 } 1865 1866 return 0; 1867 } 1868 1869 1870 1871 /* 1872 * print_sol_usage 1873 */ 1874 static void 1875 print_sol_usage(void) 1876 { 1877 lprintf(LOG_NOTICE, "SOL Commands: info [<channel number>]"); 1878 lprintf(LOG_NOTICE, " set <parameter> <value> [channel]"); 1879 lprintf(LOG_NOTICE, " payload <enable|disable|status> [channel] [userid]"); 1880 lprintf(LOG_NOTICE, " activate [<usesolkeepalive|nokeepalive>] [instance=<number>]"); 1881 lprintf(LOG_NOTICE, " deactivate [instance=<number>]"); 1882 lprintf(LOG_NOTICE, " looptest [<loop times> [<loop interval(in ms)> [<instance>]]]"); 1883 } 1884 1885 1886 1887 /* 1888 * print_sol_set_usage 1889 */ 1890 static void 1891 print_sol_set_usage(void) 1892 { 1893 lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n"); 1894 lprintf(LOG_NOTICE, " set-in-progress set-complete | " 1895 "set-in-progress | commit-write"); 1896 lprintf(LOG_NOTICE, " enabled true | false"); 1897 lprintf(LOG_NOTICE, " force-encryption true | false"); 1898 lprintf(LOG_NOTICE, " force-authentication true | false"); 1899 lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem"); 1900 lprintf(LOG_NOTICE, " character-accumulate-level <in 5 ms increments>"); 1901 lprintf(LOG_NOTICE, " character-send-threshold N"); 1902 lprintf(LOG_NOTICE, " retry-count N"); 1903 lprintf(LOG_NOTICE, " retry-interval <in 10 ms increments>"); 1904 lprintf(LOG_NOTICE, " non-volatile-bit-rate " 1905 "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2"); 1906 lprintf(LOG_NOTICE, " volatile-bit-rate " 1907 "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2"); 1908 lprintf(LOG_NOTICE, ""); 1909 } 1910 1911 1912 1913 /* ipmi_sol_main */ 1914 int 1915 ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) 1916 { 1917 int retval = 0; 1918 if (!argc || !strncmp(argv[0], "help", 4)) { 1919 /* Help */ 1920 print_sol_usage(); 1921 } else if (!strncmp(argv[0], "info", 4)) { 1922 /* Info */ 1923 uint8_t channel; 1924 if (argc == 1) { 1925 /* Ask about the current channel */ 1926 channel = 0x0E; 1927 } else if (argc == 2) { 1928 if (is_ipmi_channel_num(argv[1], &channel) != 0) { 1929 return (-1); 1930 } 1931 } else { 1932 print_sol_usage(); 1933 return -1; 1934 } 1935 retval = ipmi_print_sol_info(intf, channel); 1936 } else if (!strncmp(argv[0], "payload", 7)) { 1937 /* Payload enable or disable */ 1938 uint8_t channel = 0xe; 1939 uint8_t userid = 1; 1940 int enable = -1; 1941 if (argc == 1 || argc > 4) { 1942 print_sol_usage(); 1943 return -1; 1944 } 1945 if (argc >= 3) { 1946 if (is_ipmi_channel_num(argv[2], &channel) != 0) { 1947 return (-1); 1948 } 1949 } 1950 if (argc == 4) { 1951 if (is_ipmi_user_id(argv[3], &userid) != 0) { 1952 return (-1); 1953 } 1954 } 1955 if (!strncmp(argv[1], "enable", 6)) { 1956 enable = 1; 1957 } else if (!strncmp(argv[1], "disable", 7)) { 1958 enable = 0; 1959 } else if (!strncmp(argv[1], "status", 6)) { 1960 return ipmi_sol_payload_access_status(intf, channel, userid); 1961 } else { 1962 print_sol_usage(); 1963 return -1; 1964 } 1965 retval = ipmi_sol_payload_access(intf, channel, userid, enable); 1966 } else if (!strncmp(argv[0], "set", 3)) { 1967 /* Set a parameter value */ 1968 uint8_t channel = 0xe; 1969 uint8_t guard = 1; 1970 if (argc == 3) { 1971 channel = 0xe; 1972 } else if (argc == 4) { 1973 if (!strncmp(argv[3], "noguard", 7)) { 1974 guard = 0; 1975 } else { 1976 if (is_ipmi_channel_num(argv[3], &channel) != 0) { 1977 return (-1); 1978 } 1979 } 1980 } else if (argc == 5) { 1981 if (is_ipmi_channel_num(argv[3], &channel) != 0) { 1982 return (-1); 1983 } 1984 if (!strncmp(argv[4], "noguard", 7)) { 1985 guard = 0; 1986 } 1987 } else { 1988 print_sol_set_usage(); 1989 return -1; 1990 } 1991 retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard); 1992 } else if (!strncmp(argv[0], "activate", 8)) { 1993 /* Activate */ 1994 int i; 1995 uint8_t instance = 1; 1996 for (i = 1; i < argc; i++) { 1997 if (!strncmp(argv[i], "usesolkeepalive", 15)) { 1998 _use_sol_for_keepalive = 1; 1999 } else if (!strncmp(argv[i], "nokeepalive", 11)) { 2000 _disable_keepalive = 1; 2001 } else if (!strncmp(argv[i], "instance=", 9)) { 2002 if (str2uchar(argv[i] + 9, &instance) != 0) { 2003 lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9); 2004 print_sol_usage(); 2005 return -1; 2006 } 2007 } else { 2008 print_sol_usage(); 2009 return -1; 2010 } 2011 } 2012 retval = ipmi_sol_activate(intf, 0, 0, instance); 2013 } else if (!strncmp(argv[0], "deactivate", 10)) { 2014 /* Dectivate */ 2015 int i; 2016 uint8_t instance = 1; 2017 for (i = 1; i < argc; i++) { 2018 if (!strncmp(argv[i], "instance=", 9)) { 2019 if (str2uchar(argv[i] + 9, &instance) != 0) { 2020 lprintf(LOG_ERR, 2021 "Given instance '%s' is invalid.", 2022 argv[i] + 9); 2023 print_sol_usage(); 2024 return -1; 2025 } 2026 } else { 2027 print_sol_usage(); 2028 return -1; 2029 } 2030 } 2031 retval = ipmi_sol_deactivate(intf, instance); 2032 } else if (!strncmp(argv[0], "looptest", 8)) { 2033 /* SOL loop test: Activate and then Dectivate */ 2034 int cnt = 200; 2035 int interval = 100; /* Unit is: ms */ 2036 uint8_t instance = 1; 2037 if (argc > 4) { 2038 print_sol_usage(); 2039 return -1; 2040 } 2041 if (argc != 1) { 2042 /* at least 2 */ 2043 if (str2int(argv[1], &cnt) != 0) { 2044 lprintf(LOG_ERR, "Given cnt '%s' is invalid.", 2045 argv[1]); 2046 return (-1); 2047 } 2048 if (cnt <= 0) { 2049 cnt = 200; 2050 } 2051 } 2052 if (argc >= 3) { 2053 if (str2int(argv[2], &interval) != 0) { 2054 lprintf(LOG_ERR, "Given interval '%s' is invalid.", 2055 argv[2]); 2056 return (-1); 2057 } 2058 if (interval < 0) { 2059 interval = 0; 2060 } 2061 } 2062 if (argc >= 4) { 2063 if (str2uchar(argv[3], &instance) != 0) { 2064 lprintf(LOG_ERR, "Given instance '%s' is invalid.", 2065 argv[3]); 2066 print_sol_usage(); 2067 return -1; 2068 } 2069 } 2070 2071 while (cnt > 0) { 2072 printf("remain loop test counter: %d\n", cnt); 2073 retval = ipmi_sol_activate(intf, 1, interval, instance); 2074 if (retval) { 2075 printf("SOL looptest failed: %d\n", 2076 retval); 2077 break; 2078 } 2079 cnt -= 1; 2080 } 2081 } else { 2082 print_sol_usage(); 2083 retval = -1; 2084 } 2085 return retval; 2086 } 2087