/* signal handlers + sleep(3) is a bad idea, so use select(3) */
static int
_sleep (unsigned int len)
{
  struct timeval tv;

  tv.tv_sec = len;
  tv.tv_usec = 0;

  if (select (1, NULL, NULL, NULL, &tv) < 0)
    ipmi_ping_err_exit ("select: %s", strerror (errno));

  return (0);
}
static void
_main_loop (Ipmi_Ping_CreatePacket create,
            Ipmi_Ping_ParsePacket parse,
            Ipmi_Ping_LatePacket late)
{
  unsigned int sequence_number = 0;
  time_t last_send = 0;
  int ret;

  assert (create);
  assert (parse);
  assert (late);
  assert (pingtool_progname);
  assert (pingtool_end_result);

  if (pingtool_initial_sequence_number < 0)
    {
      int len;

      if ((len = ipmi_get_random (&pingtool_initial_sequence_number,
                                  sizeof (pingtool_initial_sequence_number))) < 0)
        ipmi_ping_err_exit ("ipmi_get_random: %s", strerror (errno));
      if (len != sizeof (pingtool_initial_sequence_number))
        ipmi_ping_err_exit ("ipmi_get_random: invalid len returned");
    }

  sequence_number = pingtool_initial_sequence_number;

  printf ("%s %s (%s)\n", pingtool_progname, pingtool_dest, pingtool_dest_ip);

  while (pingtool_count == -1 || (pingtool_pkt_sent < pingtool_count))
    {
      int rv, len, received = 0;
      uint8_t buf[IPMI_PING_MAX_PKT_LEN];
      time_t now;

      /* wait if necessary */
      now = time (NULL);
      if ((now - last_send) < pingtool_interval)
        {
          if (_sleep ((last_send + pingtool_interval - now)) < 0)
            continue;
        }

      if ((len = create (pingtool_dest,
                         buf,
                         IPMI_PING_MAX_PKT_LEN,
                         sequence_number,
                         pingtool_version,
                         pingtool_debug)) < 0)
        ipmi_ping_err_exit ("_create failed: %s", strerror (errno));

      rv = ipmi_lan_sendto (pingtool_sockfd,
                            buf,
                            len,
                            0,
                            (struct sockaddr *)&pingtool_destaddr,
                            sizeof (pingtool_destaddr));
      if (rv < 0)
        ipmi_ping_err_exit ("ipmi_sendto: %s", strerror (errno));

      if (rv != len)
        ipmi_ping_err_exit ("ipmi_sendto: wrong bytes written");

      last_send = time (NULL);

      pingtool_pkt_sent++;

      while (((now = time (NULL)) - last_send) < pingtool_timeout)
        {
          fd_set rset;
          struct timeval tv;

          FD_ZERO (&rset);
          FD_SET (pingtool_sockfd, &rset);

          tv.tv_sec = (last_send + pingtool_timeout - now);
          tv.tv_usec = 0;

          if ((rv = select (pingtool_sockfd+1, &rset, NULL, NULL, &tv)) < 0)
            ipmi_ping_err_exit ("select: %s", strerror (errno));

          if (rv == 1)
            {
              struct sockaddr_in from;
              socklen_t fromlen;

              fromlen = sizeof (from);
              len = ipmi_lan_recvfrom (pingtool_sockfd,
                                       buf,
                                       IPMI_PING_MAX_PKT_LEN,
                                       0,
                                       (struct sockaddr *)&from,
                                       &fromlen);
              
              /* 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 (len < 0
                  && (errno == ECONNRESET
                      || errno == ECONNREFUSED))
                continue;

              if (len < 0)
                ipmi_ping_err_exit ("ipmi_recvfrom: %s", strerror (errno));

              if ((rv = parse (pingtool_dest,
                               buf,
                               len,
                               inet_ntoa (from.sin_addr),
                               sequence_number,
                               pingtool_verbose,
                               pingtool_version,
                               pingtool_debug)) < 0)
                ipmi_ping_err_exit ("_parse failed: %s", strerror (errno));

              /* If rv == 0, the sequence numbers don't match, so
               * we'll wait some more for the latest packet we sent
               * out.
               */
              if (!rv)
                continue;

              received++;
              pingtool_pkt_recv++;
              break;
            }
        }

      if (!received)
        late (sequence_number);

      sequence_number++;
    }

  ret = pingtool_end_result (pingtool_progname,
                             pingtool_dest,
                             pingtool_pkt_sent,
                             pingtool_pkt_recv);
  _cleanup ();
  exit (ret);
}
static void
_setup (void)
{
  struct hostent *hptr;
  char *temp;

  if (signal (SIGINT, _signal_handler) == SIG_ERR)
    ipmi_ping_err_exit ("signal setup failed");

  if ((pingtool_sockfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
    ipmi_ping_err_exit ("socket: %s", strerror (errno));

  memset (&pingtool_srcaddr, '\0', sizeof (pingtool_srcaddr));
  pingtool_srcaddr.sin_family = AF_INET;
  pingtool_srcaddr.sin_port = htons (0);

  if (!pingtool_interface)
    pingtool_srcaddr.sin_addr.s_addr = htonl (INADDR_ANY);
  else
    {
      /* If there is a period, assume user input an IP address.  No
       * period, assume user input an interface name
       */
      if (strchr (pingtool_interface, '.'))
        {
          int rv;

          if ((rv = inet_pton (AF_INET,
                               pingtool_interface,
                               &pingtool_srcaddr.sin_addr)) < 0)
            ipmi_ping_err_exit ("inet_pton: %s", strerror (errno));
          if (!rv)
            ipmi_ping_err_exit ("invalid interface address");
        }
      else
        {
          struct ifreq ifr;
          struct sockaddr_in temp_sockaddr;

          _strncpy (ifr.ifr_name, pingtool_interface, IFNAMSIZ);
          ifr.ifr_addr.sa_family = AF_INET;
          if (ioctl (pingtool_sockfd, SIOCGIFADDR, &ifr) < 0)
            ipmi_ping_err_exit ("ioctl: %s", strerror (errno));

          temp_sockaddr = *((struct sockaddr_in *)&ifr.ifr_addr);
          memcpy (&pingtool_srcaddr.sin_addr.s_addr,
                  &temp_sockaddr.sin_addr.s_addr,
                  sizeof (pingtool_srcaddr.sin_addr.s_addr));
        }
    }

  if (bind (pingtool_sockfd,
            (struct sockaddr *)&pingtool_srcaddr,
            sizeof (pingtool_srcaddr)) < 0)
    ipmi_ping_err_exit ("bind: %s", strerror (errno));

  memset (&pingtool_destaddr, '\0', sizeof (pingtool_destaddr));
  pingtool_destaddr.sin_family = AF_INET;
  pingtool_destaddr.sin_port = htons (RMCP_PRIMARY_RMCP_PORT);

  if (!(hptr = gethostbyname (pingtool_dest)))
    {
#if HAVE_HSTRERROR
      ipmi_ping_err_exit ("gethostbyname: %s", hstrerror (h_errno));
#else /* !HAVE_HSTRERROR */
      ipmi_ping_err_exit ("gethostbyname: h_errno = %d", h_errno);
#endif /* !HAVE_HSTRERROR */
    }
  pingtool_destaddr.sin_addr = *((struct in_addr *)hptr->h_addr);
  temp = inet_ntoa (pingtool_destaddr.sin_addr);
  _strncpy (pingtool_dest_ip, temp, INET_ADDRSTRLEN);

  srand (time (NULL));
}
static void
_cmdline_parse (int argc,
                char **argv,
                unsigned int min_sequence_number,
                unsigned int max_sequence_number,
                const char *options)
{
  char *endptr;
  int c;

  assert (argc >= 0);
  assert (argv);

  /* Turn off error messages */
  opterr = 0;

  while ((c = getopt (argc, argv, options)) != -1)
    {
      switch (c)
        {
        case 'h':
          _output_usage (options);
        case 'V':
          _output_version ();
        case 'r':
          if (!strcmp (optarg, IPMI_PING_VERSION_1_5_STR))
            pingtool_version = IPMI_PING_VERSION_1_5;
          else if (!strcmp (optarg, IPMI_PING_VERSION_2_0_STR))
            pingtool_version = IPMI_PING_VERSION_2_0;
          else
            ipmi_ping_err_exit ("invalid version");
          break;
        case 'c':
	  errno = 0;
          pingtool_count = strtol (optarg, &endptr, 10);
          if (errno || endptr[0] != '\0')
            ipmi_ping_err_exit ("count argument invalid");
          if (!pingtool_count)
            ipmi_ping_err_exit ("count must be > 0");
          break;
        case 'i':
	  errno = 0;
          pingtool_interval = strtol (optarg, &endptr, 10);
          if (errno || endptr[0] != '\0')
            ipmi_ping_err_exit ("interval argument invalid");
          if (!pingtool_interval)
            ipmi_ping_err_exit ("interval must be > 0");
          break;
        case 'I':
          pingtool_interface = optarg;
          break;
        case 't':
	  errno = 0;
          pingtool_timeout = strtol (optarg, &endptr, 10);
          if (errno || endptr[0] != '\0')
            ipmi_ping_err_exit ("timeout argument invalid");
          if (!pingtool_timeout)
            ipmi_ping_err_exit ("timeout must be > 0");
          break;
        case 'v':
          pingtool_verbose++;
          break;
        case 's':
	  errno = 0;
          pingtool_initial_sequence_number = strtol (optarg, &endptr, 10);
          if (errno || endptr[0] != '\0')
            ipmi_ping_err_exit ("initial sequence number invalid");
          if (pingtool_initial_sequence_number < min_sequence_number
              || pingtool_initial_sequence_number > max_sequence_number)
            ipmi_ping_err_exit ("initial sequence number out of range");
          break;
        case 'd':
          pingtool_debug++;
          break;
        default:
          ipmi_ping_err_exit ("Command line option error");
          break;
        }
    }

  /* last argument is destination */
  if (optind >= argc)
    ipmi_ping_err_exit ("destination must be specified");

  _strncpy (pingtool_dest, argv[optind], MAXHOSTNAMELEN);
}
Beispiel #5
0
int
createpacket (const char *destination,
              void *buf,
              unsigned int buflen,
              unsigned int sequence_number,
              int version,
              int debug)
{
  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;
  int len;

  assert (destination);
  assert (buf);
  assert (version == IPMI_PING_VERSION_1_5 || version == IPMI_PING_VERSION_2_0);

  if (!buflen)
    return (0);

  if (!(obj_rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_lan_session_hdr = fiid_obj_create (tmpl_lan_session_hdr)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_lan_msg_hdr = fiid_obj_create (tmpl_lan_msg_hdr_rq)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_cmd = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));

  if (fill_rmcp_hdr_ipmi (obj_rmcp_hdr) < 0)
    ipmi_ping_err_exit ("fill_rmcp_hdr_ipmi: %s", strerror (errno));

  if (fill_lan_session_hdr (IPMI_AUTHENTICATION_TYPE_NONE,
                            0,
                            0,
                            obj_lan_session_hdr) < 0)
    ipmi_ping_err_exit ("fill_lan_session_hdr: %s", strerror (errno));

  if (fill_lan_msg_hdr (IPMI_SLAVE_ADDRESS_BMC,
                        IPMI_NET_FN_APP_RQ,
                        IPMI_BMC_IPMB_LUN_BMC,
                        sequence_number % (IPMI_RQ_SEQ_MAX+1),
                        obj_lan_msg_hdr) < 0)
    ipmi_ping_err_exit ("fill_lan_msg_hdr: %s", strerror (errno));

  if (version == IPMI_PING_VERSION_1_5)
    {
      if (fill_cmd_get_channel_authentication_capabilities (IPMI_CHANNEL_NUMBER_CURRENT_CHANNEL,
                                                            IPMI_PRIVILEGE_LEVEL_USER,
                                                            IPMI_GET_IPMI_V15_DATA,
                                                            obj_cmd) < 0)
        ipmi_ping_err_exit ("fill_cmd_get_channel_authentication_capabilities: %s", strerror (errno));
    }
  else
    {
      if (fill_cmd_get_channel_authentication_capabilities (IPMI_CHANNEL_NUMBER_CURRENT_CHANNEL,
                                                            IPMI_PRIVILEGE_LEVEL_USER,
                                                            IPMI_GET_IPMI_V20_EXTENDED_DATA,
                                                            obj_cmd) < 0)
        ipmi_ping_err_exit ("fill_cmd_get_channel_authentication_capabilities: %s", strerror (errno));
    }

  if ((len = assemble_ipmi_lan_pkt (obj_rmcp_hdr,
                                    obj_lan_session_hdr,
                                    obj_lan_msg_hdr,
                                    obj_cmd,
                                    NULL,
                                    0,
                                    buf,
                                    buflen,
				    IPMI_INTERFACE_FLAGS_DEFAULT)) < 0)
    ipmi_ping_err_exit ("assemble_ipmi_lan_pkt: %s", strerror (errno));

  if (debug)
    {
      char hdrbuf[DEBUG_UTIL_HDR_BUFLEN];

      debug_hdr_cmd ((version == IPMI_PING_VERSION_1_5) ? DEBUG_UTIL_TYPE_IPMI_1_5 : DEBUG_UTIL_TYPE_IPMI_2_0,
                     DEBUG_UTIL_DIRECTION_REQUEST,
                     IPMI_NET_FN_APP_RQ,
                     IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES,
		     0,
                     hdrbuf,
                     DEBUG_UTIL_HDR_BUFLEN);

      if (ipmi_dump_lan_packet (STDERR_FILENO,
                                destination,
                                hdrbuf,
                                NULL,
                                buf,
                                len,
                                tmpl_lan_msg_hdr_rq,
                                tmpl_cmd_get_channel_authentication_capabilities_rq) < 0)
        ipmi_ping_err_exit ("ipmi_dump_lan_packet: %s", strerror (errno));
    }

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

  return (len);
}
Beispiel #6
0
int
parsepacket (const char *destination,
             const void *buf,
             unsigned int buflen,
             const char *from,
             unsigned int sequence_number,
             int verbose,
             int version,
             int debug)
{
  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;
  uint8_t req_seq, none, md2, md5, straight_password_key, oem,
    anonymous_login, null_username, non_null_username,
    user_level_authentication, per_message_authentication,
    k_g, ipmi_v20_extended_capabilities_available, ipmi_v15, ipmi_v20;
  uint64_t val;
  int ret, rv = -1;

  assert (destination);
  assert (buf);
  assert (from);
  assert (version == IPMI_PING_VERSION_1_5 || version == IPMI_PING_VERSION_2_0);

  if (!buflen)
    return (0);

  if (!(obj_rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_lan_session_hdr = fiid_obj_create (tmpl_lan_session_hdr)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_lan_msg_hdr = fiid_obj_create (tmpl_lan_msg_hdr_rs)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_cmd = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));
  if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr)))
    ipmi_ping_err_exit ("fiid_obj_create: %s", strerror (errno));

  if (debug)
    {
      char hdrbuf[DEBUG_UTIL_HDR_BUFLEN];

      debug_hdr_cmd ((version == IPMI_PING_VERSION_1_5) ? DEBUG_UTIL_TYPE_IPMI_1_5 : DEBUG_UTIL_TYPE_IPMI_2_0,
                     DEBUG_UTIL_DIRECTION_RESPONSE,
                     IPMI_NET_FN_APP_RQ,
                     IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES,
		     0,
                     hdrbuf,
                     DEBUG_UTIL_HDR_BUFLEN);

      if (ipmi_dump_lan_packet (STDERR_FILENO,
                                destination,
                                hdrbuf,
                                NULL,
                                buf,
                                buflen,
                                tmpl_lan_msg_hdr_rs,
                                tmpl_cmd_get_channel_authentication_capabilities_rs) < 0)
        ipmi_ping_err_exit ("ipmi_dump_lan_packet: %s", strerror (errno));
    }

  if ((ret = ipmi_lan_check_packet_checksum (buf, buflen)) < 0)
    ipmi_ping_err_exit ("ipmi_lan_check_checksum: %s", strerror (errno));

  if (!ret)
    {
      if (debug)
        fprintf (stderr, "%s(%d): checksum failed\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  if ((ret = unassemble_ipmi_lan_pkt (buf,
                                      buflen,
                                      obj_rmcp_hdr,
                                      obj_lan_session_hdr,
                                      obj_lan_msg_hdr,
                                      obj_cmd,
                                      obj_lan_msg_trlr,
				      IPMI_INTERFACE_FLAGS_DEFAULT)) < 0)
    ipmi_ping_err_exit ("unassemble_ipmi_lan_pkt: %s", strerror (errno));

  if (!ret)
    {
      if (debug)
        fprintf (stderr, "%s(%d): Could not unassemble packet\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  if ((ret = ipmi_lan_check_net_fn (obj_lan_msg_hdr, IPMI_NET_FN_APP_RS)) < 0)
    ipmi_ping_err_exit ("ipmi_lan_check_net_fn: %s", strerror (errno));

  if (!ret)
    {
      if (debug)
        fprintf (stderr, "%s(%d): net_fn failed\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  if ((ret = ipmi_check_cmd (obj_cmd, IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES)) < 0)
    ipmi_ping_err_exit ("ipmi_check_cmd: %s", strerror (errno));

  if (!ret)
    {
      if (debug)
        fprintf (stderr, "%s(%d): cmd failed\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  if ((ret = ipmi_check_completion_code_success (obj_cmd)) < 0)
    ipmi_ping_err_exit ("ipmi_check_comp_code: %s", strerror (errno));

  if (!ret)
    {
      if (debug)
        fprintf (stderr, "%s(%d): comp_code failed\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  if (FIID_OBJ_GET (obj_lan_msg_hdr,
                    "rq_seq",
                    &val) < 0)
    ipmi_ping_err_exit ("fiid_obj_get: 'rq_seq': %s",
                        fiid_obj_errormsg (obj_lan_msg_hdr));
  req_seq = val;

  if (req_seq != sequence_number % (IPMI_RQ_SEQ_MAX + 1))
    {
      if (debug)
        fprintf (stderr, "%s(%d): req_seq failed\n", __FUNCTION__, __LINE__);
      rv = 0;
      goto cleanup;
    }

  printf ("response received from %s: rq_seq=%u", from, req_seq);
  if (verbose)
    {
      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_type.none",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.none': %s",
                            fiid_obj_errormsg (obj_cmd));
      none = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_type.md2",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.md2': %s",
                            fiid_obj_errormsg (obj_cmd));
      md2 = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_type.md5",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.md5': %s",
                            fiid_obj_errormsg (obj_cmd));
      md5 = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_type.straight_password_key",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.straight_password_key': %s",
                            fiid_obj_errormsg (obj_cmd));
      straight_password_key = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_type.oem_prop",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.oem_prop': %s",
                            fiid_obj_errormsg (obj_cmd));
      oem = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.anonymous_login",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.anonymous_login': %s",
                            fiid_obj_errormsg (obj_cmd));
      anonymous_login = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.null_username",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.null_username': %s",
                            fiid_obj_errormsg (obj_cmd));
      null_username = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.non_null_username",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.non_null_username': %s",
                            fiid_obj_errormsg (obj_cmd));
      non_null_username = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.user_level_authentication",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.user_level_authentication': %s",
                            fiid_obj_errormsg (obj_cmd));
      user_level_authentication = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.per_message_authentication",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.per_message_authentication': %s",
                            fiid_obj_errormsg (obj_cmd));
      per_message_authentication = val;

      if (FIID_OBJ_GET (obj_cmd,
                        "authentication_status.per_message_authentication",
                        &val) < 0)
        ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.per_message_authentication': %s",
                            fiid_obj_errormsg (obj_cmd));
      per_message_authentication = val;

      printf (", auth: none=%s md2=%s md5=%s password=%s oem=%s anon=%s null=%s non-null=%s user=%s permsg=%s ",
              _setstr (none), _setstr (md2), _setstr (md5),
              _setstr (straight_password_key),_setstr (oem),
              _setstr (anonymous_login), _setstr (null_username),
              _setstr (non_null_username), _setstr (user_level_authentication),
              _setstr (per_message_authentication));

      if (version == IPMI_PING_VERSION_2_0)
        {
          if (FIID_OBJ_GET (obj_cmd,
                            "authentication_type.ipmi_v2.0_extended_capabilities_available",
                            &val) < 0)
            ipmi_ping_err_exit ("fiid_obj_get: 'authentication_type.ipmi_v2.0_extended_capabilities_available': %s",
                                fiid_obj_errormsg (obj_cmd));
          ipmi_v20_extended_capabilities_available = val;

          if (FIID_OBJ_GET (obj_cmd,
                            "authentication_status.k_g",
                            &val) < 0)
            ipmi_ping_err_exit ("fiid_obj_get: 'authentication_status.k_g': %s",
                                fiid_obj_errormsg (obj_cmd));
          k_g = val;

          printf ("k_g=%s ipmi_v2.0_extended_capabilities_available=%s ",
                  _setstr (k_g),
                  _setstr (ipmi_v20_extended_capabilities_available));

          if (ipmi_v20_extended_capabilities_available)
            {
              if (FIID_OBJ_GET (obj_cmd,
                                "channel_supports_ipmi_v1.5_connections",
                                &val) < 0)
                ipmi_ping_err_exit ("fiid_obj_get: 'channel_supports_ipmi_v1.5_connections': %s",
                                    fiid_obj_errormsg (obj_cmd));
              ipmi_v15 = val;

              if (FIID_OBJ_GET (obj_cmd,
                                "channel_supports_ipmi_v2.0_connections",
                                &val) < 0)
                ipmi_ping_err_exit ("fiid_obj_get: 'channel_supports_ipmi_v2.0_connections': %s",
                                    fiid_obj_errormsg (obj_cmd));
              ipmi_v20 = val;

              printf ("ipmi_v1.5=%s ipmi_v2.0=%s ", _setstr (ipmi_v15), _setstr (ipmi_v20));
            }
        }
    }
  printf ("\n");

  rv = 1;
 cleanup:
  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);
  return (rv);
}
static void 
_main_loop(Ipmi_Ping_CreatePacket _create, 
           Ipmi_Ping_ParsePacket _parse, 
           Ipmi_Ping_LatePacket _late) 
{
  unsigned int sequence_number = 0;
  time_t last_send = 0;
  int ret;

  assert(_create != NULL 
         && _parse != NULL 
         && _late != NULL
         && _progname != NULL 
         && _end_result != NULL);

  if (_initial_sequence_number < 0)
    {
      int len;

      if ((len = ipmi_get_random((uint8_t *)&_initial_sequence_number,
                                 sizeof(_initial_sequence_number))) < 0)
        ipmi_ping_err_exit("ipmi_get_random: %s", strerror(errno));
      if (len != sizeof(_initial_sequence_number))
        ipmi_ping_err_exit("ipmi_get_random: invalid len returned");
    }

  sequence_number = _initial_sequence_number;

  printf("%s %s (%s)\n", _progname, _dest, _dest_ip);

  while (_count == -1 || (_pkt_sent < _count)) 
    {
      int rv, len, received = 0;
      uint8_t buffer[IPMI_PING_MAX_PKT_LEN];
      time_t now;

      /* wait if necessary */
      now = time(NULL);
      if ((now - last_send) < _interval) 
        {
          if (_sleep((last_send + _interval - now)) < 0)
            continue;
        }
      
      if ((len = _create(_dest, (char *)buffer, IPMI_PING_MAX_PKT_LEN, 
                         sequence_number, _version, _debug)) < 0)
        ipmi_ping_err_exit("_create failed: %s", strerror(errno));
        
      rv = ipmi_lan_sendto(_sockfd, buffer, len, 0, 
                           (struct sockaddr *)&_destaddr, sizeof(_destaddr));
      if (rv < 0)
        ipmi_ping_err_exit("ipmi_sendto: %s", strerror(errno));
      
      if (rv != len)
        ipmi_ping_err_exit("ipmi_sendto: wrong bytes written"); 
      
      last_send = time(NULL);
      
      _pkt_sent++;

      while (((now = time(NULL)) - last_send) < _timeout) 
        {
          fd_set rset;
          struct timeval tv;
          
          FD_ZERO(&rset);
          FD_SET(_sockfd, &rset);

          tv.tv_sec = (last_send + _timeout - now);
          tv.tv_usec = 0;
        
          if ((rv = select(_sockfd+1, &rset, NULL, NULL, &tv)) < 0)
            ipmi_ping_err_exit("select: %s", strerror(errno));
        
          if (rv == 1) 
            {
              struct sockaddr_in from;
              socklen_t fromlen;
              
              fromlen = sizeof(from);
              len = ipmi_lan_recvfrom(_sockfd, buffer, IPMI_PING_MAX_PKT_LEN, 0,
                                      (struct sockaddr *)&from, &fromlen);
              if (len < 0)
                ipmi_ping_err_exit("ipmi_recvfrom: %s", strerror(errno));
              
              if ((rv = _parse(_dest, (char *)buffer, len, inet_ntoa(from.sin_addr), 
                               sequence_number, _verbose, _version, _debug)) < 0)
                ipmi_ping_err_exit("_parse failed: %s", strerror(errno));

              /* If rv == 0, the sequence numbers don't match, so
               * we'll wait some more for the latest packet we sent
               * out.
               */
              if (rv == 0)
                continue;

              received++;
              _pkt_recv++;
              break;
            }
        }
      
      if (received == 0)
        _late(sequence_number);
      
      sequence_number++;
    }
  
  ret = _end_result(_progname, _dest, _pkt_sent, _pkt_recv);
  _cleanup();
  exit(ret);
}