diff --git a/ipmitool/include/ipmitool/ipmi_sel.h b/ipmitool/include/ipmitool/ipmi_sel.h index 0e8eefc..2c82125 100644 --- a/ipmitool/include/ipmitool/ipmi_sel.h +++ b/ipmitool/include/ipmitool/ipmi_sel.h @@ -530,6 +530,7 @@ typedef enum IPMI_OEM { IPMI_OEM_TYAN = 6653, IPMI_OEM_NEWISYS = 9237, IPMI_OEM_SUPERMICRO = 10876, + IPMI_OEM_GOOGLE = 11129, IPMI_OEM_KONTRON = 15000, } IPMI_OEM; diff --git a/ipmitool/lib/helper.c b/ipmitool/lib/helper.c index e596cc9..e68f1b0 100644 --- a/ipmitool/lib/helper.c +++ b/ipmitool/lib/helper.c @@ -97,13 +97,13 @@ void printbuf(const uint8_t * buf, int len, const char * desc) if (verbose < 1) return; - fprintf(stderr, "%s (%d bytes)\n", desc, len); + fprintf(stderr, "%s (%d bytes)\r\n", desc, len); for (i=0; isendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->set_in_progress = rsp->data[1]; } else { @@ -137,12 +137,12 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", - val2str(data[1], sol_parameter_vals), + val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return -1; } @@ -159,12 +159,12 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->enabled = rsp->data[1]; } else { @@ -175,7 +175,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -197,11 +197,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0); params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0); @@ -214,7 +214,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -236,11 +236,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 3) { params->character_accumulate_level = rsp->data[1]; params->character_send_threshold = rsp->data[2]; @@ -252,7 +252,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -274,14 +274,14 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 3) { params->retry_count = rsp->data[1]; - params->retry_interval = rsp->data[2]; + params->retry_interval = rsp->data[2]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", @@ -290,7 +290,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -312,11 +312,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->non_volatile_bit_rate = rsp->data[1] & 0x0F; } else { @@ -327,7 +327,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -349,11 +349,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->volatile_bit_rate = rsp->data[1] & 0x0F; } else { @@ -364,7 +364,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: @@ -386,11 +386,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 2) { params->payload_channel = rsp->data[1]; } else { @@ -401,7 +401,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x", val2str(data[1], sol_parameter_vals), channel); params->payload_channel = channel; break; @@ -424,11 +424,11 @@ ipmi_get_sol_info( data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ - + rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: if (rsp->data_len == 3) { params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8); } else { @@ -439,7 +439,7 @@ ipmi_get_sol_info( } break; case 0x80: - lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d", + lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d", val2str(data[1], sol_parameter_vals), intf->session->port); params->payload_port = intf->session->port; break; @@ -468,7 +468,7 @@ ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel) struct sol_config_parameters params = {0}; if (ipmi_get_sol_info(intf, channel, ¶ms)) return -1; - + if (csv_output) { printf("%s,", @@ -549,16 +549,15 @@ ipmi_sol_set_param(struct ipmi_intf * intf, { struct ipmi_rs * rsp; struct ipmi_rq req; - uint8_t data[4]; + uint8_t data[4]; int bGuarded = 1; /* Use set-in-progress indicator? */ - memset(&req, 0, sizeof(req)); - req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */ req.msg.cmd = IMPI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */ req.msg.data = data; - + data[0] = channel; - /* * set-in-progress @@ -638,11 +637,11 @@ ipmi_sol_set_param(struct ipmi_intf * intf, param); return -1; } - + data[2] |= params.force_authentication? 0x40 : 0x00; - data[2] |= params.privilege_level; + data[2] |= params.privilege_level; } - + /* * force-payload-authentication @@ -676,9 +675,9 @@ ipmi_sol_set_param(struct ipmi_intf * intf, } data[2] |= params.force_encryption? 0x80 : 0x00; - data[2] |= params.privilege_level; + data[2] |= params.privilege_level; } - + /* * privilege-level @@ -738,7 +737,7 @@ ipmi_sol_set_param(struct ipmi_intf * intf, param); return -1; } - + data[3] = params.character_send_threshold; } @@ -764,7 +763,7 @@ ipmi_sol_set_param(struct ipmi_intf * intf, data[2] = params.character_accumulate_level; } - + /* * retry-count @@ -807,11 +806,11 @@ ipmi_sol_set_param(struct ipmi_intf * intf, param); return -1; } - + data[2] = params.retry_count; } - + /* * non-volatile-bit-rate */ @@ -853,7 +852,7 @@ ipmi_sol_set_param(struct ipmi_intf * intf, return -1; } } - + /* * volatile-bit-rate @@ -896,7 +895,6 @@ ipmi_sol_set_param(struct ipmi_intf * intf, return -1; } } - else { lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param); @@ -924,7 +922,7 @@ ipmi_sol_set_param(struct ipmi_intf * intf, if (rsp == NULL) { lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param); return -1; - } + } if (rsp->ccode > 0) { lprintf(LOG_ERR, "Error setting SOL parameter '%s': %s", @@ -938,9 +936,8 @@ ipmi_sol_set_param(struct ipmi_intf * intf, { lprintf(LOG_ERR, "Error could not set \"set-in-progress\" " "to \"set-complete\""); - return -1; } - + return -1; } @@ -1084,9 +1081,21 @@ printSolEscapeSequences(struct ipmi_intf * intf) static void output(struct ipmi_rs * rsp) { - if (rsp) + /* Add checks to make sure it is actually SOL data, in general I see + * outside code mostly trying to guard against this happening, but + * some places fail to do so, so I do so here to make sure nothing gets + * through. If non-sol data comes through here, there is probably + * a packet that won't get processed somewhere else, but the alternative + * of outputting corrupt data is worse. Generally I see the get device + * id response make it here somehow. I assume it is a heartbeat and the + * other code will retry if it cares about the response and misses it. + */ + if (rsp && + (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)) { int i; + for (i = 0; i < rsp->data_len; ++i) putc(rsp->data[i], stdout); @@ -1104,9 +1113,9 @@ ipmi_sol_deactivate(struct ipmi_intf * intf) { struct ipmi_rs * rsp; struct ipmi_rq req; - uint8_t data[6]; + uint8_t data[6]; - memset(&req, 0, sizeof(req)); + memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD; req.msg.data_len = 6; @@ -1126,7 +1135,7 @@ ipmi_sol_deactivate(struct ipmi_intf * intf) if (NULL != rsp) { switch (rsp->ccode) { - case 0x00: + case 0x00: return 0; case 0x80: lprintf(LOG_ERR, "Info: SOL payload already de-activated"); @@ -1144,7 +1153,7 @@ ipmi_sol_deactivate(struct ipmi_intf * intf) } return -1; -} +} @@ -1184,7 +1193,7 @@ processSolUserInput( if (escape_pending){ escape_pending = 0; - + /* * Process a possible escape sequence. */ @@ -1242,7 +1251,7 @@ processSolUserInput( last_was_cr = (ch == '\r' || ch == '\n'); } - + /* * If there is anything left to process we dispatch it to the BMC, * send intf->session->sol_data.max_outbound_payload_size bytes @@ -1254,8 +1263,9 @@ processSolUserInput( int try = 0; while (try < intf->session->retry) { - + v2_payload.payload.sol_packet.character_count = length; + rsp = intf->send_sol(intf, &v2_payload); if (rsp) @@ -1308,7 +1318,6 @@ ipmi_sol_keepalive(struct ipmi_intf * intf) static int ipmi_sol_red_pill(struct ipmi_intf * intf) { - char * buffer; int numRead; int bShouldExit = 0; @@ -1326,7 +1335,7 @@ ipmi_sol_red_pill(struct ipmi_intf * intf) } /* Initialize keepalive start time */ - gettimeofday(&_start_keepalive, 0); + gettimeofday(&_start_keepalive, 0); enter_raw_mode(); @@ -1370,11 +1379,11 @@ ipmi_sol_red_pill(struct ipmi_intf * intf) numRead = read(fileno(stdin), buffer, buffer_size); - + if (numRead > 0) { int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead); - + if (rc) { if (rc < 0) @@ -1401,7 +1410,9 @@ ipmi_sol_red_pill(struct ipmi_intf * intf) bShouldExit = bBmcClosedSession = 1; } else + { output(rs); + } } @@ -1449,7 +1460,7 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) struct ipmi_rs * rsp; struct ipmi_rq req; struct activate_payload_rsp ap_rsp; - uint8_t data[6]; + uint8_t data[6]; uint8_t bSolEncryption = 1; uint8_t bSolAuthentication = 1; @@ -1497,7 +1508,7 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) data[4] = 0x00; /* reserved */ data[5] = 0x00; /* reserved */ - G_u8ActiveSOL = 1; + G_u8ActiveSOL = 1; rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { @@ -1539,7 +1550,7 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp)); - + intf->session->sol_data.max_inbound_payload_size = (ap_rsp.inbound_payload_size[1] << 8) | ap_rsp.inbound_payload_size[0]; @@ -1551,7 +1562,6 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) intf->session->sol_data.port = (ap_rsp.payload_udp_port[1] << 8) | ap_rsp.payload_udp_port[0]; - #if WORDS_BIGENDIAN @@ -1564,7 +1574,7 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) #endif - intf->session->timeout = 3; + intf->session->timeout = 1; /* NOTE: the spec does allow for SOL traffic to be sent on @@ -1582,7 +1592,6 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) return -1; } } - printf("[SOL Session operational. Use %c? for help]\r\n", intf->session->sol_escape_char); @@ -1592,7 +1601,7 @@ ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval) ipmi_sol_deactivate(intf); usleep(interval*1000); return 0; - } + } /* * At this point we are good to go with our SOL session. We @@ -1678,7 +1687,7 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) channel = (uint8_t)strtol(argv[1], NULL, 0); else { - print_sol_usage(); + print_sol_usage(); return -1; } @@ -1701,13 +1710,13 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) print_sol_set_usage(); return -1; } - + retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2]); } - + /* * Activate @@ -1715,12 +1724,13 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) else if (!strncmp(argv[0], "activate", 8)) retval = ipmi_sol_activate(intf, 0, 0); + /* * Dectivate */ else if (!strncmp(argv[0], "deactivate", 10)) retval = ipmi_sol_deactivate(intf); - + /* * SOL loop test: Activate and then Dectivate @@ -1730,9 +1740,9 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) int cnt = 200; int interval = 100; /* Unit is: ms */ - if(argc > 3) + if (argc > 3) { - print_sol_usage(); + print_sol_usage(); return -1; } if (argc != 1) /* at least 2 */ @@ -1745,12 +1755,12 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) interval = strtol(argv[2], NULL, 10); if(interval < 0) interval = 0; } - - while(cnt > 0) + + while (cnt > 0) { printf("remain loop test counter: %d\n", cnt); retval = ipmi_sol_activate(intf, 1, interval); - if(retval) + if (retval) { printf("SOL looptest failed: %d\n", retval); break; diff --git a/ipmitool/lib/ipmi_strings.c b/ipmitool/lib/ipmi_strings.c index e8e875f..bc21dd8 100644 --- a/ipmitool/lib/ipmi_strings.c +++ b/ipmitool/lib/ipmi_strings.c @@ -44,6 +44,7 @@ const struct valstr ipmi_oem_info[] = { { IPMI_OEM_TYAN, "Tyan Computer Corporation" }, { IPMI_OEM_NEWISYS, "Newisys" }, { IPMI_OEM_SUPERMICRO, "Supermicro" }, + { IPMI_OEM_GOOGLE, "Google" }, { IPMI_OEM_KONTRON, "Kontron" }, { 0xffff , NULL }, }; diff --git a/ipmitool/src/plugins/lan/lan.c b/ipmitool/src/plugins/lan/lan.c index 8930387..1c309da 100644 --- a/ipmitool/src/plugins/lan/lan.c +++ b/ipmitool/src/plugins/lan/lan.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include diff --git a/ipmitool/src/plugins/lanplus/lanplus.c b/ipmitool/src/plugins/lanplus/lanplus.c index 19f6dd0..11672f7 100644 --- a/ipmitool/src/plugins/lanplus/lanplus.c +++ b/ipmitool/src/plugins/lanplus/lanplus.c @@ -40,9 +40,8 @@ #include #include #include -#include -#include #include +#include #include #include @@ -76,9 +75,6 @@ static struct ipmi_rq_entry * ipmi_req_entries; static struct ipmi_rq_entry * ipmi_req_entries_tail; -static sigjmp_buf jmpbuf; - - static int ipmi_lanplus_setup(struct ipmi_intf * intf); static int ipmi_lanplus_keepalive(struct ipmi_intf * intf); static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len); @@ -265,13 +261,6 @@ void lanplus_swap( -static void -query_alarm(int signo) -{ - siglongjmp(jmpbuf, 1); -} - - static const struct valstr plus_payload_types_vals[] = { { IPMI_PAYLOAD_TYPE_IPMI, "IPMI (0)" }, // IPMI Message { IPMI_PAYLOAD_TYPE_SOL, "SOL (1)" }, // SOL (Serial over LAN) @@ -384,7 +373,7 @@ ipmi_lan_send_packet( uint8_t * data, int data_len) { - if (verbose >= 2) + if (verbose >= 5) printbuf(data, data_len, ">> sending packet"); return send(intf->fd, data, data_len, 0); @@ -396,17 +385,22 @@ struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf) { static struct ipmi_rs rsp; - int rc; + fd_set read_set, err_set; + struct timeval tmout; + int ret; - /* setup alarm timeout */ - if (sigsetjmp(jmpbuf, 1) != 0) { - alarm(0); + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) return NULL; - } - - alarm(intf->session->timeout); - rc = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); - alarm(0); /* the first read may return ECONNREFUSED because the rmcp ping * packet--sent to UDP port 623--will be processed by both the @@ -415,25 +409,40 @@ ipmi_lan_recv_packet(struct ipmi_intf * intf) * The problem with this is that the ECONNREFUSED takes * priority over any other received datagram; that means that * the Connection Refused shows up _before_ the response packet, - * regardless of the order they were sent out. (unless the + * regardless of the order they were sent out. (unless the * response is read before the connection refused is returned) */ - if (rc < 0) { - alarm(intf->session->timeout); - rc = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); - alarm(0); - if (rc < 0) { - perror("recv failed"); - return NULL; + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + + if (ret < 0) { + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0) { + if (FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + if (ret < 0) + return NULL; } } - rsp.data[rc] = '\0'; - rsp.data_len = rc; - if (verbose >= 2) - { - printbuf(rsp.data, rsp.data_len, "<< Received data"); - } + if (ret == 0) + return NULL; + + rsp.data[ret] = '\0'; + rsp.data_len = ret; + + if (verbose >= 5) + printbuf(rsp.data, rsp.data_len, "<< received packet"); return &rsp; } @@ -1247,6 +1256,7 @@ void read_ipmi_response(struct ipmi_rs * rsp, int * offset) */ void read_sol_packet(struct ipmi_rs * rsp, int * offset) { + /* * The data here should be decrypted by now. */ @@ -1265,38 +1275,34 @@ void read_sol_packet(struct ipmi_rs * rsp, int * offset) rsp->payload.sol_packet.transfer_unavailable = rsp->data[*offset] & 0x20; - rsp->payload.sol_packet.sol_inactive = + rsp->payload.sol_packet.sol_inactive = rsp->data[*offset] & 0x10; rsp->payload.sol_packet.transmit_overrun = rsp->data[*offset] & 0x08; - + rsp->payload.sol_packet.break_detected = rsp->data[(*offset)++] & 0x04; - lprintf(LOG_DEBUG, "SOL sequence number : 0x%02x", + lprintf(LOG_DEBUG, "< SOL sequence number : 0x%02x", rsp->payload.sol_packet.packet_sequence_number); - - lprintf(LOG_DEBUG, "SOL acked packet : 0x%02x", + lprintf(LOG_DEBUG, "< SOL acked packet : 0x%02x", rsp->payload.sol_packet.acked_packet_number); - - lprintf(LOG_DEBUG, "SOL accepted char count : 0x%02x", + lprintf(LOG_DEBUG, "< SOL accepted char count : 0x%02x", rsp->payload.sol_packet.accepted_character_count); - - lprintf(LOG_DEBUG, "SOL is nack : %s", + lprintf(LOG_DEBUG, "< SOL is nack : %s", rsp->payload.sol_packet.is_nack? "true" : "false"); - - lprintf(LOG_DEBUG, "SOL xfer unavailable : %s", + lprintf(LOG_DEBUG, "< SOL xfer unavailable : %s", rsp->payload.sol_packet.transfer_unavailable? "true" : "false"); - - lprintf(LOG_DEBUG, "SOL inactive : %s", + lprintf(LOG_DEBUG, "< SOL inactive : %s", rsp->payload.sol_packet.sol_inactive? "true" : "false"); - - lprintf(LOG_DEBUG, "SOL transmit overrun : %s", + lprintf(LOG_DEBUG, "< SOL transmit overrun : %s", rsp->payload.sol_packet.transmit_overrun? "true" : "false"); - - lprintf(LOG_DEBUG, "SOL break detected : %s", + lprintf(LOG_DEBUG, "< SOL break detected : %s", rsp->payload.sol_packet.break_detected? "true" : "false"); + + if (verbose >= 5) + printbuf(rsp->data + *offset - 4, 4, "SOL MSG FROM BMC"); } @@ -1409,10 +1415,31 @@ void getSolPayloadWireRep( { int i = 0; + lprintf(LOG_DEBUG, "> SOL sequence number : 0x%02x", + payload->payload.sol_packet.packet_sequence_number); + lprintf(LOG_DEBUG, "> SOL acked packet : 0x%02x", + payload->payload.sol_packet.acked_packet_number); + lprintf(LOG_DEBUG, "> SOL accepted char count : 0x%02x", + payload->payload.sol_packet.accepted_character_count); + lprintf(LOG_DEBUG, "> SOL is nack : %s", + payload->payload.sol_packet.is_nack ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL assert ring wor : %s", + payload->payload.sol_packet.assert_ring_wor ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL generate break : %s", + payload->payload.sol_packet.generate_break ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL deassert cts : %s", + payload->payload.sol_packet.deassert_cts ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL deassert dcd dsr : %s", + payload->payload.sol_packet.deassert_dcd_dsr ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL flush inbound : %s", + payload->payload.sol_packet.flush_inbound ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL flush outbound : %s", + payload->payload.sol_packet.flush_outbound ? "true" : "false"); + msg[i++] = payload->payload.sol_packet.packet_sequence_number; msg[i++] = payload->payload.sol_packet.acked_packet_number; msg[i++] = payload->payload.sol_packet.accepted_character_count; - + msg[i] = payload->payload.sol_packet.is_nack ? 0x40 : 0; msg[i] |= payload->payload.sol_packet.assert_ring_wor ? 0x20 : 0; msg[i] |= payload->payload.sol_packet.generate_break ? 0x10 : 0; @@ -1426,6 +1453,12 @@ void getSolPayloadWireRep( payload->payload.sol_packet.data, payload->payload.sol_packet.character_count); + lprintf(LOG_DEBUG, "> SOL character count : %d", + payload->payload.sol_packet.character_count); + + if (payload->payload.sol_packet.character_count) + printbuf(payload->payload.sol_packet.data, payload->payload.sol_packet.character_count, "SOL SEND DATA"); + /* * At this point, the payload length becomes the whole payload * length, including the 4 bytes at the beginning of the SOL @@ -1489,7 +1522,6 @@ ipmi_lanplus_build_v2x_msg( /* msg will hold the entire message to be sent */ uint8_t * msg; - int len = 0; @@ -1531,7 +1563,6 @@ ipmi_lanplus_build_v2x_msg( /* Payload Type -- also specifies whether were authenticated/encyrpted */ msg[IMPI_LANPLUS_OFFSET_PAYLOAD_TYPE] = payload->payload_type; - if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE) { msg[IMPI_LANPLUS_OFFSET_PAYLOAD_TYPE] |= @@ -1554,17 +1585,16 @@ ipmi_lanplus_build_v2x_msg( msg[IMPI_LANPLUS_OFFSET_SEQUENCE_NUM + 2] = (session->out_seq >> 16) & 0xff; msg[IMPI_LANPLUS_OFFSET_SEQUENCE_NUM + 3] = (session->out_seq >> 24) & 0xff; } - + /* * Payload Length is set below (we don't know how big the payload is until after * encryption). */ - /* * Payload * - * At this point we are ready to slam the payload in. + * At this point we are ready to slam the payload in. * This includes: * 1) The confidentiality header * 2) The payload proper (possibly encrypted) @@ -1586,6 +1616,10 @@ ipmi_lanplus_build_v2x_msg( getSolPayloadWireRep(intf, msg + IPMI_LANPLUS_OFFSET_PAYLOAD, payload); + + if (verbose >= 5) + printbuf(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, 4, "SOL MSG TO BMC"); + len += payload->payload_length; break; @@ -1640,14 +1674,12 @@ ipmi_lanplus_build_v2x_msg( } - /* Now we know the payload length */ msg[IMPI_LANPLUS_OFFSET_PAYLOAD_SIZE ] = payload->payload_length & 0xff; msg[IMPI_LANPLUS_OFFSET_PAYLOAD_SIZE + 1] = (payload->payload_length >> 8) & 0xff; - /* *------------------------------------------ @@ -1684,11 +1716,10 @@ ipmi_lanplus_build_v2x_msg( if (length_before_authcode % 4) integrity_pad_size = 4 - (length_before_authcode % 4); - + for (i = 0; i < integrity_pad_size; ++i) msg[start_of_session_trailer + i] = 0xFF; - /* Pad length */ msg[start_of_session_trailer + integrity_pad_size] = integrity_pad_size; @@ -1696,7 +1727,6 @@ ipmi_lanplus_build_v2x_msg( msg[start_of_session_trailer + integrity_pad_size + 1] = 0x07; /* Hardcoded per the spec, table 13-8 */ - hmac_input_size = 12 + payload->payload_length + @@ -1771,9 +1801,9 @@ ipmi_lanplus_build_v2x_ipmi_cmd( * representation far below. */ static uint8_t curr_seq = 0; - - curr_seq += 1; - + + curr_seq += 1; + if (curr_seq >= 64) curr_seq = 0; @@ -1786,12 +1816,12 @@ ipmi_lanplus_build_v2x_ipmi_cmd( v2_payload.payload_length = req->msg.data_len + 7; v2_payload.payload.ipmi_request.request = req; v2_payload.payload.ipmi_request.rq_seq = curr_seq; - - ipmi_lanplus_build_v2x_msg(intf, // in - &v2_payload, // in - &(entry->msg_len), // out - &(entry->msg_data), // out - curr_seq); // in + + ipmi_lanplus_build_v2x_msg(intf, // in + &v2_payload, // in + &(entry->msg_len), // out + &(entry->msg_data), // out + curr_seq); // in return entry; } @@ -1975,132 +2005,137 @@ ipmi_lanplus_send_payload( struct ipmi_v2_payload * payload) { struct ipmi_rs * rsp = NULL; - uint8_t * msg_data; + uint8_t * msg_data; int msg_length; struct ipmi_session * session = intf->session; int try = 0; + int xmit = 1; + time_t ltime; if (!intf->opened && intf->open && intf->open(intf) < 0) return NULL; - if (payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) - { - /* - * Build an IPMI v1.5 or v2 command - */ - struct ipmi_rq_entry * entry; - struct ipmi_rq * ipmi_request = payload->payload.ipmi_request.request; - - lprintf(LOG_DEBUG, ""); - lprintf(LOG_DEBUG, ">> Sending IPMI command payload"); - lprintf(LOG_DEBUG, ">> netfn : 0x%02x", ipmi_request->msg.netfn); - lprintf(LOG_DEBUG, ">> command : 0x%02x", ipmi_request->msg.cmd); - - if (verbose > 1) - { - uint16_t i; - fprintf(stderr, ">> data : "); - for (i = 0; i < ipmi_request->msg.data_len; ++i) - fprintf(stderr, "0x%02x ", ipmi_request->msg.data[i]); - fprintf(stderr, "\n\n"); - } - - - /* - * If we are presession, and the command is GET CHANNEL AUTHENTICATION - * CAPABILITIES, we will build the command in v1.5 format. This is so - * that we can ask any server whether it supports IPMI v2 / RMCP+ - * before we attempt to open a v2.x session. - */ - if ((ipmi_request->msg.netfn == IPMI_NETFN_APP) && - (ipmi_request->msg.cmd == IPMI_GET_CHANNEL_AUTH_CAP) && - (session->v2_data.bmc_id == 0)) // jme - check - { - lprintf(LOG_DEBUG+1, "BUILDING A v1.5 COMMAND"); - entry = ipmi_lanplus_build_v15_ipmi_cmd(intf, ipmi_request); - } - else - { - lprintf(LOG_DEBUG+1, "BUILDING A v2 COMMAND"); - entry = ipmi_lanplus_build_v2x_ipmi_cmd(intf, ipmi_request); - } - - if (entry == NULL) { - lprintf(LOG_ERR, "Aborting send command, unable to build"); - return NULL; - } - - msg_data = entry->msg_data; - msg_length = entry->msg_len; - } - - else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST) - { - lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n"); - assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION); - - ipmi_lanplus_build_v2x_msg(intf, /* in */ - payload, /* in */ - &msg_length, /* out */ - &msg_data, /* out */ - 0); /* irrelevant for this msg*/ - - } - - else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_1) - { - lprintf(LOG_DEBUG, ">> SENDING A RAKP 1 MESSAGE\n"); - assert(session->v2_data.session_state == - LANPLUS_STATE_OPEN_SESSION_RECEIEVED); - - ipmi_lanplus_build_v2x_msg(intf, /* in */ - payload, /* in */ - &msg_length, /* out */ - &msg_data, /* out */ - 0); /* irrelevant for this msg*/ - - } - - else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_3) - { - lprintf(LOG_DEBUG, ">> SENDING A RAKP 3 MESSAGE\n"); - assert(session->v2_data.session_state == - LANPLUS_STATE_RAKP_2_RECEIVED); - - ipmi_lanplus_build_v2x_msg(intf, /* in */ - payload, /* in */ - &msg_length, /* out */ - &msg_data, /* out */ - 0); /* irrelevant for this msg*/ - - } - - else if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) - { - lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n"); - assert(session->v2_data.session_state == LANPLUS_STATE_ACTIVE); - - ipmi_lanplus_build_v2x_msg(intf, /* in */ - payload, /* in */ - &msg_length, /* out */ - &msg_data, /* out */ - 0); /* irrelevant for this msg*/ - } - - else - { - lprintf(LOG_ERR, "Payload type 0x%0x is unsupported!", - payload->payload_type); - assert(0); - } - - while (try < session->retry) { + ltime = time(NULL); + + if (xmit) { + + if (payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) + { + /* + * Build an IPMI v1.5 or v2 command + */ + struct ipmi_rq_entry * entry; + struct ipmi_rq * ipmi_request = payload->payload.ipmi_request.request; + + lprintf(LOG_DEBUG, ""); + lprintf(LOG_DEBUG, ">> Sending IPMI command payload"); + lprintf(LOG_DEBUG, ">> netfn : 0x%02x", ipmi_request->msg.netfn); + lprintf(LOG_DEBUG, ">> command : 0x%02x", ipmi_request->msg.cmd); + + if (verbose > 1) + { + uint16_t i; + fprintf(stderr, ">> data : "); + for (i = 0; i < ipmi_request->msg.data_len; ++i) + fprintf(stderr, "0x%02x ", ipmi_request->msg.data[i]); + fprintf(stderr, "\n\n"); + } - if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) { - lprintf(LOG_ERR, "IPMI LAN send command failed"); - return NULL; + /* + * If we are presession, and the command is GET CHANNEL AUTHENTICATION + * CAPABILITIES, we will build the command in v1.5 format. This is so + * that we can ask any server whether it supports IPMI v2 / RMCP+ + * before we attempt to open a v2.x session. + */ + if ((ipmi_request->msg.netfn == IPMI_NETFN_APP) && + (ipmi_request->msg.cmd == IPMI_GET_CHANNEL_AUTH_CAP) && + (session->v2_data.bmc_id == 0)) // jme - check + { + lprintf(LOG_DEBUG+1, "BUILDING A v1.5 COMMAND"); + entry = ipmi_lanplus_build_v15_ipmi_cmd(intf, ipmi_request); + } + else + { + lprintf(LOG_DEBUG+1, "BUILDING A v2 COMMAND"); + entry = ipmi_lanplus_build_v2x_ipmi_cmd(intf, ipmi_request); + } + + if (entry == NULL) { + lprintf(LOG_ERR, "Aborting send command, unable to build"); + return NULL; + } + + msg_data = entry->msg_data; + msg_length = entry->msg_len; + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST) + { + lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n"); + assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_1) + { + lprintf(LOG_DEBUG, ">> SENDING A RAKP 1 MESSAGE\n"); + assert(session->v2_data.session_state == + LANPLUS_STATE_OPEN_SESSION_RECEIEVED); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_3) + { + lprintf(LOG_DEBUG, ">> SENDING A RAKP 3 MESSAGE\n"); + assert(session->v2_data.session_state == + LANPLUS_STATE_RAKP_2_RECEIVED); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) + { + lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n"); + assert(session->v2_data.session_state == LANPLUS_STATE_ACTIVE); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + } + + else + { + lprintf(LOG_ERR, "Payload type 0x%0x is unsupported!", + payload->payload_type); + assert(0); + } + + + if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) { + lprintf(LOG_ERR, "IPMI LAN send command failed"); + return NULL; + } } /* if we are set to noanswer we do not expect response */ @@ -2173,11 +2208,17 @@ ipmi_lanplus_send_payload( rsp = ipmi_lan_poll_recv(intf); if (rsp) break; - } + xmit = ((time(NULL) - ltime) >= intf->session->timeout); + usleep(5000); + if (xmit) { + /* incremet session timeout each retry */ + intf->session->timeout++; + } + try++; } @@ -2205,6 +2246,7 @@ ipmi_lanplus_send_payload( * 0 if this isn't an ACK or we don't need to resend anything */ int is_sol_partial_ack( + struct ipmi_intf * intf, struct ipmi_v2_payload * v2_payload, struct ipmi_rs * rs) { @@ -2217,6 +2259,10 @@ int is_sol_partial_ack( (rs->payload.sol_packet.accepted_character_count < v2_payload->payload.sol_packet.character_count)) { + if (ipmi_oem_active(intf, "intelplus") && + rs->payload.sol_packet.accepted_character_count == 0) + return 0; + chars_to_resend = v2_payload->payload.sol_packet.character_count - rs->payload.sol_packet.accepted_character_count; @@ -2277,16 +2323,17 @@ ipmi_lanplus_send_sol( v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */ set_sol_packet_sequence_number(intf, v2_payload); - + v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */ rs = ipmi_lanplus_send_payload(intf, v2_payload); /* Determine if we need to resend some of our data */ - chars_to_resend = is_sol_partial_ack(v2_payload, rs); + chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs); - - while (chars_to_resend) + while (rs && !rs->payload.sol_packet.transfer_unavailable && + !rs->payload.sol_packet.is_nack && + chars_to_resend) { /* * We first need to handle any new data we might have @@ -2296,7 +2343,7 @@ ipmi_lanplus_send_sol( intf->session->sol_data.sol_input_handler(rs); set_sol_packet_sequence_number(intf, v2_payload); - + /* Just send the required data */ memmove(v2_payload->payload.sol_packet.data, v2_payload->payload.sol_packet.data + @@ -2309,7 +2356,7 @@ ipmi_lanplus_send_sol( rs = ipmi_lanplus_send_payload(intf, v2_payload); - chars_to_resend = is_sol_partial_ack(v2_payload, rs); + chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs); } return rs; @@ -2533,7 +2580,7 @@ ipmi_get_auth_capabilities_cmd( } if (rsp->ccode > 0) { lprintf(LOG_INFO, "Get Auth Capabilities error: %s", - val2str(rsp->ccode, completion_code_vals)); + val2str(rsp->ccode, completion_code_vals)); return 1; } } @@ -3172,7 +3219,6 @@ int ipmi_lanplus_open(struct ipmi_intf * intf) { int rc; - struct sigaction act; struct get_channel_auth_cap_rsp auth_cap; struct sockaddr_in addr; struct ipmi_session *session; @@ -3250,16 +3296,6 @@ ipmi_lanplus_open(struct ipmi_intf * intf) return -1; } - /* setup alarm handler */ - act.sa_handler = query_alarm; - act.sa_flags = 0; - if (sigemptyset(&act.sa_mask) == 0 && - sigaction(SIGALRM, &act, NULL) < 0) { - lperror(LOG_ERR, "alarm signal"); - intf->close(intf); - return -1; - } - intf->opened = 1; diff --git a/ipmitool/src/plugins/lanplus/lanplus.h b/ipmitool/src/plugins/lanplus/lanplus.h index 80aa47a..7d9cba4 100644 --- a/ipmitool/src/plugins/lanplus/lanplus.h +++ b/ipmitool/src/plugins/lanplus/lanplus.h @@ -66,7 +66,7 @@ #define IPMI_LAN_CHANNEL_2 0x06 #define IPMI_LAN_CHANNEL_E 0x0e -#define IPMI_LAN_TIMEOUT 2 +#define IPMI_LAN_TIMEOUT 1 #define IPMI_LAN_RETRY 4 #define IPMI_PRIV_CALLBACK 1 diff --git a/ipmitool/src/plugins/lanplus/lanplus_crypt_impl.c b/ipmitool/src/plugins/lanplus/lanplus_crypt_impl.c index 7d6b46d..cde6c54 100644 --- a/ipmitool/src/plugins/lanplus/lanplus_crypt_impl.c +++ b/ipmitool/src/plugins/lanplus/lanplus_crypt_impl.c @@ -30,6 +30,7 @@ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ +#include "ipmitool/log.h" #include "ipmitool/ipmi_constants.h" #include "lanplus.h" #include "lanplus_crypt_impl.h" @@ -124,7 +125,7 @@ lanplus_HMAC(uint8_t mac, evp_md = EVP_sha1(); else { - fprintf(stderr, "Invalid mac type 0x%x in lanplus_HMAC\n", mac); + lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac); assert(0); } @@ -165,7 +166,7 @@ lanplus_encrypt_aes_cbc_128(const uint8_t * iv, if (input_length == 0) return; - if (verbose > 2) + if (verbose >= 5) { printbuf(iv, 16, "encrypting with this IV"); printbuf(key, 16, "encrypting with this key"); @@ -233,10 +234,9 @@ lanplus_decrypt_aes_cbc_128(const uint8_t * iv, EVP_CIPHER_CTX_init(&ctx); EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(&ctx, 0); - - if (verbose > 2) + if (verbose >= 5) { printbuf(iv, 16, "decrypting with this IV"); printbuf(key, 16, "decrypting with this key"); @@ -260,7 +260,7 @@ lanplus_decrypt_aes_cbc_128(const uint8_t * iv, if (!EVP_DecryptUpdate(&ctx, output, (int *)bytes_written, input, input_length)) { /* Error */ - fprintf(stderr, "ERROR: decrypt update failed"); + lprintf(LOG_DEBUG, "ERROR: decrypt update failed"); *bytes_written = 0; return; } @@ -272,8 +272,8 @@ lanplus_decrypt_aes_cbc_128(const uint8_t * iv, { char buffer[1000]; ERR_error_string(ERR_get_error(), buffer); - fprintf(stderr, "the ERR error %s", buffer); - fprintf(stderr, "ERROR: decrypt final failed"); + lprintf(LOG_DEBUG, "the ERR error %s", buffer); + lprintf(LOG_DEBUG, "ERROR: decrypt final failed"); *bytes_written = 0; return; /* Error */ } @@ -285,9 +285,9 @@ lanplus_decrypt_aes_cbc_128(const uint8_t * iv, } } - if (verbose > 1) + if (verbose >= 5) { - fprintf(stderr, "Decrypted %d encrypted bytes", input_length); + lprintf(LOG_DEBUG, "Decrypted %d encrypted bytes", input_length); printbuf(output, *bytes_written, "Decrypted this data"); } }