static void _recvfrom (cbuf_t cbuf, int fd, struct sockaddr_in *srcaddr) { int n, rv, dropped = 0; uint8_t buf[IPMIPOWER_PACKET_BUFLEN]; struct sockaddr_in from; unsigned int fromlen = sizeof (struct sockaddr_in); do { /* For receive side, ipmi_lan_recvfrom and * ipmi_rmcpplus_recvfrom are identical. So we just use * ipmi_lan_recvfrom for both. * * In event of future change, should use util functions * ipmi_is_ipmi_1_5_packet or ipmi_is_ipmi_2_0_packet * appropriately. */ rv = ipmi_lan_recvfrom (fd, buf, IPMIPOWER_PACKET_BUFLEN, 0, (struct sockaddr *)&from, &fromlen); } while (rv < 0 && errno == EINTR); /* achu & hliebig: * * Premise from ipmitool (http://ipmitool.sourceforge.net/) * * On some OSes (it seems Unixes), the behavior is to not return * port denied errors up to the client for UDP responses (i.e. you * need to timeout). But on some OSes (it seems Windows), the * behavior is to return port denied errors up to the user for UDP * responses via ECONNRESET or ECONNREFUSED. * * If this were just the case, we could return or handle errors * properly and move on. However, it's not the case. * * According to Ipmitool, on some motherboards, both the OS and the * BMC are capable of responding to an IPMI request. That means you * can get an ECONNRESET or ECONNREFUSED, then later on, get your * real IPMI response. * * Our solution is copied from Ipmitool, we'll ignore some specific * errors and try to read again. * * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get * an IPMI response later, the recvfrom later on gets the packet we * want. * * If the ECONNREFUSED or ECONNRESET is from the OS but there is no * BMC (or IPMI disabled, etc.), just do the recvfrom again to * eventually get a timeout, which is the behavior we'd like. */ if (rv < 0 && (errno == ECONNRESET || errno == ECONNREFUSED)) { IPMIPOWER_DEBUG (("ipmi_lan_recvfrom: connection refused: %s", strerror (errno))); return; } if (rv < 0) { IPMIPOWER_ERROR (("ipmi_lan_recvfrom: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!rv) { IPMIPOWER_ERROR (("ipmi_lan_recvfrom: EOF")); exit (EXIT_FAILURE); } /* Don't store if this packet is strange for some reason */ if (from.sin_family != AF_INET || from.sin_addr.s_addr != srcaddr->sin_addr.s_addr) return; /* cbuf should be empty, but if it isn't, empty it */ if (!cbuf_is_empty (cbuf)) { IPMIPOWER_DEBUG (("cbuf not empty, draining")); do { uint8_t tempbuf[IPMIPOWER_PACKET_BUFLEN]; if (cbuf_read (cbuf, tempbuf, IPMIPOWER_PACKET_BUFLEN) < 0) { IPMIPOWER_ERROR (("cbuf_read: %s", strerror (errno))); exit (EXIT_FAILURE); } } while(!cbuf_is_empty (cbuf)); } if ((n = cbuf_write (cbuf, buf, rv, &dropped)) < 0) { IPMIPOWER_ERROR (("cbuf_write: %s", strerror (errno))); exit (EXIT_FAILURE); } if (n != rv) { IPMIPOWER_ERROR (("cbuf_write: rv=%d n=%d", rv, n)); exit (EXIT_FAILURE); } if (dropped) IPMIPOWER_DEBUG (("cbuf_write: read dropped %d bytes", dropped)); }
/* _poll_loop * - poll on all descriptors */ static void _poll_loop (int non_interactive) { int nfds = 0; struct pollfd *pfds = NULL; int extra_fds; /* number of fds for stdin and stdout we'll need when polling * * Right now, always poll stdout. When non-interactive, * don't need stdin */ extra_fds = 1 + (non_interactive ? 0 : 1); while (non_interactive || ipmipower_prompt_process_cmdline ()) { int i, num, timeout; int powercmd_timeout = -1; int ping_timeout = -1; /* If there are no pending commands before this call, * powercmd_timeout will not be set, leaving it at -1 */ num = ipmipower_powercmd_process_pending (&powercmd_timeout); if (non_interactive && !num) break; /* ping timeout is always set if cmd_args.ping_interval > 0 */ ipmipower_ping_process_pings (&ping_timeout); if (cmd_args.ping_interval) { if (powercmd_timeout == -1) timeout = ping_timeout; else timeout = (ping_timeout < powercmd_timeout) ? ping_timeout : powercmd_timeout; } else timeout = powercmd_timeout; /* achu: I always wonder if this poll() loop could be done far * more elegantly and efficiently without all this crazy * indexing, perhaps through a callback/event mechanism. It'd * probably be more efficient, since most callback/event based * models have min-heap like structures inside for determining * what things timed out. Overall though, I don't think the O(n) * (n being hosts/fds) processing is really that inefficient for * this particular application and is not worth going back and * changing. By going to a callback/event mechanism, there will * still be some O(n) activities within the code, so I am only * going to create a more efficient O(n) poll loop. */ /* Has the number of hosts changed? */ if (nfds != (ics_len*2) + extra_fds) { /* The "*2" is for each host's two fds, one for ipmi * (ipmi_fd) and one for rmcp (ping_fd). */ nfds = (ics_len*2) + extra_fds; free (pfds); if (!(pfds = (struct pollfd *)malloc (nfds * sizeof (struct pollfd)))) { IPMIPOWER_ERROR (("malloc: %s", strerror (errno))); exit (EXIT_FAILURE); } } for (i = 0; i < ics_len; i++) { pfds[i*2].fd = ics[i].ipmi_fd; pfds[i*2+1].fd = ics[i].ping_fd; pfds[i*2].events = pfds[i*2+1].events = 0; pfds[i*2].revents = pfds[i*2+1].revents = 0; pfds[i*2].events |= POLLIN; if (!cbuf_is_empty (ics[i].ipmi_out)) pfds[i*2].events |= POLLOUT; if (!cmd_args.ping_interval) continue; pfds[i*2+1].events |= POLLIN; if (!cbuf_is_empty (ics[i].ping_out)) pfds[i*2+1].events |= POLLOUT; } if (!non_interactive) { pfds[nfds-2].fd = STDIN_FILENO; pfds[nfds-2].events = POLLIN; pfds[nfds-2].revents = 0; } pfds[nfds-1].fd = STDOUT_FILENO; if (!cbuf_is_empty (ttyout)) pfds[nfds-1].events = POLLOUT; else pfds[nfds-1].events = 0; pfds[nfds-1].revents = 0; ipmipower_poll (pfds, nfds, timeout); for (i = 0; i < ics_len; i++) { if (pfds[i*2].revents & POLLERR) { IPMIPOWER_DEBUG (("host = %s; IPMI POLLERR", ics[i].hostname)); /* See comments in _ipmi_recvfrom() regarding ECONNRESET/ECONNREFUSED */ _recvfrom (ics[i].ipmi_in, ics[i].ipmi_fd, &(ics[i].destaddr)); } else { if (pfds[i*2].revents & POLLIN) _recvfrom (ics[i].ipmi_in, ics[i].ipmi_fd, &(ics[i].destaddr)); if (pfds[i*2].revents & POLLOUT) _sendto (ics[i].ipmi_out, ics[i].ipmi_fd, &(ics[i].destaddr)); } if (!cmd_args.ping_interval) continue; if (pfds[i*2+1].revents & POLLERR) { IPMIPOWER_DEBUG (("host = %s; PING_POLLERR", ics[i].hostname)); _recvfrom (ics[i].ping_in, ics[i].ping_fd, &(ics[i].destaddr)); } else { if (pfds[i*2+1].revents & POLLIN) _recvfrom (ics[i].ping_in, ics[i].ping_fd, &(ics[i].destaddr)); if (pfds[i*2+1].revents & POLLOUT) _sendto (ics[i].ping_out, ics[i].ping_fd, &(ics[i].destaddr)); } } if (!non_interactive && (pfds[nfds-2].revents & POLLIN)) { int n, dropped = 0; if ((n = cbuf_write_from_fd (ttyin, STDIN_FILENO, -1, &dropped)) < 0) { IPMIPOWER_ERROR (("cbuf_write_from_fd: %s", strerror (errno))); exit (EXIT_FAILURE); } /* achu: If you are running ipmipower in co-process mode * with powerman, this error condition will probably be hit * with the file descriptor STDIN_FILENO. The powerman * daemon is usually closed by /etc/init.d/powerman stop, * which kills a process through a signal. Thus, powerman * closes stdin and stdout pipes to ipmipower and the call * to cbuf_write_from_fd will give us an EOF reading. We'll * consider this EOF an "ok" error. No need to output an * error message. */ if (!n) exit (EXIT_FAILURE); if (dropped) IPMIPOWER_DEBUG (("cbuf_write_from_fd: read dropped %d bytes", dropped)); } if (!cbuf_is_empty (ttyout) && (pfds[nfds-1].revents & POLLOUT)) { if (cbuf_read_to_fd (ttyout, STDOUT_FILENO, -1) < 0) { IPMIPOWER_ERROR (("cbuf_read_to_fd: %s", strerror (errno))); exit (EXIT_FAILURE); } } } free (pfds); }
void ipmipower_ping_process_pings (int *timeout) { int i, send_pings_flag = 0; struct timeval cur_time, result; unsigned int ms_time; assert (timeout); if (!cmd_args.common_args.hostname) return; if (!cmd_args.ping_interval) return; if (gettimeofday (&cur_time, NULL) < 0) { IPMIPOWER_ERROR (("gettimeofday: %s", strerror (errno))); exit (EXIT_FAILURE); } if (timeval_gt (&cur_time, &next_ping_sends_time) || force_discovery_sweep) { force_discovery_sweep = 0; timeval_add_ms (&cur_time, cmd_args.ping_interval, &next_ping_sends_time); send_pings_flag++; } for (i = 0; i < ics_len; i++) { uint8_t buf[IPMIPOWER_PACKET_BUFLEN]; int ret, len; if (send_pings_flag) { int dropped = 0; memset (buf, '\0', IPMIPOWER_PACKET_BUFLEN); /* deal with packet heuristics */ if (cmd_args.ping_packet_count && cmd_args.ping_percent) { if (ics[i].ping_packet_count_send == cmd_args.ping_packet_count) { if ((((double)(ics[i].ping_packet_count_send - ics[i].ping_packet_count_recv))/ics[i].ping_packet_count_send) > ((double)cmd_args.ping_percent/100)) ics[i].link_state = IPMIPOWER_LINK_STATE_BAD; else ics[i].link_state = IPMIPOWER_LINK_STATE_GOOD; ics[i].ping_packet_count_send = 0; ics[i].ping_packet_count_recv = 0; } } if (cmd_args.ping_consec_count) { if (!ics[i].ping_last_packet_recv_flag) ics[i].ping_consec_count = 0; ics[i].ping_last_packet_recv_flag = 0; } /* must increment count before setting message tag, so we * can check sequence number correctly later on */ ics[i].ping_sequence_number_counter++; /* Workaround * * Some motherboards don't support RMCP ping/pong :-( * * Discovered on Intel Windmill, Quanta Winterfell, and Wiwynn Windmill */ if (cmd_args.common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING) { fiid_obj_t obj_rmcp_hdr = NULL; fiid_obj_t obj_lan_session_hdr = NULL; fiid_obj_t obj_lan_msg_hdr = NULL; fiid_obj_t obj_cmd = NULL; if (!(obj_rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_lan_session_hdr = fiid_obj_create (tmpl_lan_session_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_lan_msg_hdr = fiid_obj_create (tmpl_lan_msg_hdr_rq))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_cmd = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_rmcp_hdr_ipmi (obj_rmcp_hdr) < 0) { IPMIPOWER_ERROR (("fill_rmcp_hdr_ipmi: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_lan_session_hdr (IPMI_AUTHENTICATION_TYPE_NONE, 0, 0, obj_lan_session_hdr) < 0) { IPMIPOWER_ERROR (("fill_lan_session_hdr: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_lan_msg_hdr (IPMI_SLAVE_ADDRESS_BMC, IPMI_NET_FN_APP_RQ, IPMI_BMC_IPMB_LUN_BMC, (ics[i].ping_sequence_number_counter % (IPMI_RQ_SEQ_MAX + 1)), obj_lan_msg_hdr) < 0) { IPMIPOWER_ERROR (("fill_lan_msg_hdr: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_cmd_get_channel_authentication_capabilities (IPMI_CHANNEL_NUMBER_CURRENT_CHANNEL, IPMI_PRIVILEGE_LEVEL_USER, IPMI_GET_IPMI_V15_DATA, obj_cmd) < 0) { IPMIPOWER_ERROR (("fill_cmd_get_channel_authentication_capabilities: %s", strerror (errno))); exit (EXIT_FAILURE); } if ((len = assemble_ipmi_lan_pkt (obj_rmcp_hdr, obj_lan_session_hdr, obj_lan_msg_hdr, obj_cmd, NULL, 0, buf, IPMIPOWER_PACKET_BUFLEN, IPMI_INTERFACE_FLAGS_DEFAULT)) < 0) { IPMIPOWER_ERROR (("assemble_ipmi_lan_pkt: %s", strerror (errno))); exit (EXIT_FAILURE); } #ifndef NDEBUG if (cmd_args.rmcpdump) { char hdrbuf[DEBUG_UTIL_HDR_BUFLEN]; const char *str_cmd = NULL; str_cmd = ipmi_cmd_str (IPMI_NET_FN_APP_RQ, IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES); debug_hdr_str (DEBUG_UTIL_TYPE_IPMI_1_5, DEBUG_UTIL_DIRECTION_REQUEST, DEBUG_UTIL_FLAGS_DEFAULT, str_cmd, hdrbuf, DEBUG_UTIL_HDR_BUFLEN); if (ipmi_dump_lan_packet (STDERR_FILENO, ics[i].hostname, hdrbuf, NULL, buf, len, tmpl_lan_msg_hdr_rq, tmpl_cmd_get_channel_authentication_capabilities_rq) < 0) IPMIPOWER_DEBUG (("ipmi_dump_lan_packet: %s", strerror (errno))); } #endif /* NDEBUG */ fiid_obj_destroy (obj_rmcp_hdr); fiid_obj_destroy (obj_lan_session_hdr); fiid_obj_destroy (obj_lan_msg_hdr); fiid_obj_destroy (obj_cmd); } else /* !IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING */ { fiid_obj_t rmcp_hdr = NULL; fiid_obj_t rmcp_ping = NULL; if (!(rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(rmcp_ping = fiid_obj_create (tmpl_cmd_asf_presence_ping))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_rmcp_hdr_asf (rmcp_hdr) < 0) { IPMIPOWER_ERROR (("fill_rmcp_hdr_asf: %s", strerror (errno))); exit (EXIT_FAILURE); } if (fill_cmd_asf_presence_ping ((ics[i].ping_sequence_number_counter % (RMCP_ASF_MESSAGE_TAG_MAX + 1)), rmcp_ping) < 0) { IPMIPOWER_ERROR (("fill_cmd_asf_presence_ping: %s", strerror (errno))); exit (EXIT_FAILURE); } if ((len = assemble_rmcp_pkt (rmcp_hdr, rmcp_ping, buf, IPMIPOWER_PACKET_BUFLEN, IPMI_INTERFACE_FLAGS_DEFAULT)) < 0) { IPMIPOWER_ERROR (("assemble_rmcp_pkt: %s", strerror (errno))); exit (EXIT_FAILURE); } #ifndef NDEBUG if (cmd_args.rmcpdump) { char hdrbuf[DEBUG_UTIL_HDR_BUFLEN]; debug_hdr_str (DEBUG_UTIL_TYPE_NONE, DEBUG_UTIL_DIRECTION_NONE, DEBUG_UTIL_FLAGS_DEFAULT, DEBUG_UTIL_RMCPPING_STR, hdrbuf, DEBUG_UTIL_HDR_BUFLEN); if (ipmi_dump_rmcp_packet (STDERR_FILENO, ics[i].hostname, hdrbuf, NULL, buf, len, tmpl_cmd_asf_presence_ping) < 0) IPMIPOWER_DEBUG (("ipmi_dump_rmcp_packet: %s", strerror (errno))); } #endif /* NDEBUG */ fiid_obj_destroy (rmcp_hdr); fiid_obj_destroy (rmcp_ping); } /* !IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING */ if ((ret = cbuf_write (ics[i].ping_out, buf, len, &dropped)) < 0) { IPMIPOWER_ERROR (("cbuf_write: %s", strerror (errno))); exit (EXIT_FAILURE); } if (ret != len) { IPMIPOWER_ERROR (("cbuf_write: incorrect bytes written %d", ret)); exit (EXIT_FAILURE); } if (dropped) IPMIPOWER_DEBUG (("cbuf_write: dropped %d bytes", dropped)); ics[i].last_ping_send.tv_sec = cur_time.tv_sec; ics[i].last_ping_send.tv_usec = cur_time.tv_usec; if (cmd_args.ping_packet_count && cmd_args.ping_percent) ics[i].ping_packet_count_send++; } /* Did we receive something? */ memset (buf, '\0', IPMIPOWER_PACKET_BUFLEN); len = ipmipower_cbuf_peek_and_drop (ics[i].ping_in, buf, IPMIPOWER_PACKET_BUFLEN); if (len > 0) { uint8_t message_type = 0, ipmi_supported = 0; uint64_t val; /* Workaround * * Some motherboards don't support RMCP ping/pong :-( * * Discovered on Intel Windmill, Quanta Winterfell, and Wiwynn Windmill */ if (cmd_args.common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING) { fiid_obj_t obj_rmcp_hdr = NULL; fiid_obj_t obj_lan_session_hdr = NULL; fiid_obj_t obj_lan_msg_hdr = NULL; fiid_obj_t obj_cmd = NULL; fiid_obj_t obj_lan_msg_trlr = NULL; int checksum_ret = 0; int unassemble_ret = 0; int cmd_ret = 0; if (!(obj_rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_lan_session_hdr = fiid_obj_create (tmpl_lan_session_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_lan_msg_hdr = fiid_obj_create (tmpl_lan_msg_hdr_rs))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_cmd = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } #ifndef NDEBUG if (cmd_args.rmcpdump) { char hdrbuf[DEBUG_UTIL_HDR_BUFLEN]; const char *str_cmd = NULL; str_cmd = ipmi_cmd_str (IPMI_NET_FN_APP_RQ, IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES); debug_hdr_str (DEBUG_UTIL_TYPE_IPMI_1_5, DEBUG_UTIL_DIRECTION_RESPONSE, DEBUG_UTIL_FLAGS_DEFAULT, str_cmd, hdrbuf, DEBUG_UTIL_HDR_BUFLEN); if (ipmi_dump_lan_packet (STDERR_FILENO, ics[i].hostname, hdrbuf, NULL, buf, len, tmpl_lan_msg_hdr_rs, tmpl_cmd_get_channel_authentication_capabilities_rs) < 0) IPMIPOWER_DEBUG (("ipmi_dump_lan_packet: %s", strerror (errno))); } #endif /* NDEBUG */ if ((checksum_ret = ipmi_lan_check_packet_checksum (buf, len)) < 0) { IPMIPOWER_ERROR (("ipmi_lan_check_packet_checksum: %s", strerror (errno))); exit (EXIT_FAILURE); } if (checksum_ret && ((unassemble_ret = unassemble_ipmi_lan_pkt (buf, len, obj_rmcp_hdr, obj_lan_session_hdr, obj_lan_msg_hdr, obj_cmd, obj_lan_msg_trlr, IPMI_INTERFACE_FLAGS_DEFAULT)) < 0)) { IPMIPOWER_ERROR (("unassemble_ipmi_lan_pkt: %s", strerror (errno))); exit (EXIT_FAILURE); } /* achu: check for cmd type, but don't bother checking * sequence numbers or completion code. The fact it * returns is sufficient. We just need to make sure we * get something back from the BMC to ensure the machine * is still there. */ if (checksum_ret && unassemble_ret && ((cmd_ret = ipmi_check_cmd (obj_cmd, IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES)) < 0)) { IPMIPOWER_ERROR (("ipmi_check_cmd: %s", strerror (errno))); exit (EXIT_FAILURE); } if (checksum_ret && unassemble_ret && cmd_ret) { /* We'll say this is equivalent to what pong response from RMCP */ message_type = RMCP_ASF_MESSAGE_TYPE_PRESENCE_PONG; ipmi_supported = 1; } fiid_obj_destroy (obj_rmcp_hdr); fiid_obj_destroy (obj_lan_session_hdr); fiid_obj_destroy (obj_lan_msg_hdr); fiid_obj_destroy (obj_cmd); fiid_obj_destroy (obj_lan_msg_trlr); } else /* !IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING */ { fiid_obj_t rmcp_hdr = NULL; fiid_obj_t rmcp_pong = NULL; if (!(rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } if (!(rmcp_pong = fiid_obj_create (tmpl_cmd_asf_presence_pong))) { IPMIPOWER_ERROR (("fiid_obj_create: %s", strerror (errno))); exit (EXIT_FAILURE); } #ifndef NDEBUG if (cmd_args.rmcpdump) { char hdrbuf[DEBUG_UTIL_HDR_BUFLEN]; debug_hdr_str (DEBUG_UTIL_TYPE_NONE, DEBUG_UTIL_DIRECTION_NONE, DEBUG_UTIL_FLAGS_DEFAULT, DEBUG_UTIL_RMCPPING_STR, hdrbuf, DEBUG_UTIL_HDR_BUFLEN); if (ipmi_dump_rmcp_packet (STDERR_FILENO, ics[i].hostname, hdrbuf, NULL, buf, len, tmpl_cmd_asf_presence_pong) < 0) IPMIPOWER_DEBUG (("ipmi_dump_rmcp_packet: %s", strerror (errno))); } #endif /* NDEBUG */ if ((ret = unassemble_rmcp_pkt (buf, len, rmcp_hdr, rmcp_pong, IPMI_INTERFACE_FLAGS_DEFAULT)) < 0) { IPMIPOWER_ERROR (("unassemble_rmcp_pkt: %s", strerror (errno))); exit (EXIT_FAILURE); } if (ret) { /* achu: check for ipmi_support and pong type, but don't * check for message tag. On occassion, I have witnessed * BMCs send message tags "out of sync". For example, you * send 8, BMC returns 7. You send 9, BMC returns 8. We * really don't care if the BMC is out of sync. We just * need to make sure we get something back from the BMC to * ensure the machine is still there. */ if (FIID_OBJ_GET (rmcp_pong, "message_type", &val) < 0) { IPMIPOWER_ERROR (("FIID_OBJ_GET: 'message_type': %s", fiid_obj_errormsg (rmcp_pong))); exit (EXIT_FAILURE); } message_type = val; if (FIID_OBJ_GET (rmcp_pong, "supported_entities.ipmi_supported", &val) < 0) { IPMIPOWER_ERROR (("FIID_OBJ_GET: 'supported_entities.ipmi_supported': %s", fiid_obj_errormsg (rmcp_pong))); exit (EXIT_FAILURE); } ipmi_supported = val; } fiid_obj_destroy (rmcp_hdr); fiid_obj_destroy (rmcp_pong); } if (message_type == RMCP_ASF_MESSAGE_TYPE_PRESENCE_PONG && ipmi_supported) { if (cmd_args.ping_packet_count && cmd_args.ping_percent) ics[i].ping_packet_count_recv++; if (cmd_args.ping_consec_count) { /* Don't increment twice, its possible a previous pong * response was late, and we quickly receive two * pong responses */ if (!ics[i].ping_last_packet_recv_flag) ics[i].ping_consec_count++; ics[i].ping_last_packet_recv_flag++; } if (cmd_args.ping_packet_count && cmd_args.ping_percent) { if (ics[i].link_state == IPMIPOWER_LINK_STATE_GOOD) ics[i].discover_state = IPMIPOWER_DISCOVER_STATE_DISCOVERED; else { if (cmd_args.ping_consec_count && ics[i].ping_consec_count >= cmd_args.ping_consec_count) ics[i].discover_state = IPMIPOWER_DISCOVER_STATE_DISCOVERED; else ics[i].discover_state = IPMIPOWER_DISCOVER_STATE_BADCONNECTION; } } else { ics[i].discover_state = IPMIPOWER_DISCOVER_STATE_DISCOVERED; } ics[i].last_ping_recv.tv_sec = cur_time.tv_sec; ics[i].last_ping_recv.tv_usec = cur_time.tv_usec; } } /* !IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IPMIPING */ /* Is the node gone?? */ timeval_sub (&cur_time, &ics[i].last_ping_recv, &result); timeval_millisecond_calc (&result, &ms_time); if (ms_time >= cmd_args.ping_timeout) ics[i].discover_state = IPMIPOWER_DISCOVER_STATE_UNDISCOVERED; } timeval_sub (&next_ping_sends_time, &cur_time, &result); timeval_millisecond_calc (&result, &ms_time); *timeout = ms_time; }