Ejemplo n.º 1
0
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));
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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 != 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);
}
Ejemplo n.º 4
0
static void
_receive_ping (int fd)
{
  struct sockaddr_in from;
  struct ipmidetectd_info *info;
  uint8_t buf[IPMIDETECTD_BUFLEN];
  int len;
  socklen_t fromlen = sizeof (struct sockaddr_in);
  char *tmpstr;

  /* We're happy as long as we receive something.  We don't bother
   * checking sequence numbers or anything like that.
   */

  len = ipmi_lan_recvfrom (fd,
                           buf,
                           IPMIDETECTD_BUFLEN,
                           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))
    return;
    
  if (len < 0)
    err_exit ("ipmi_lan_recvfrom: %s", strerror (errno));

  if (!(tmpstr = inet_ntoa (from.sin_addr)))
    err_exit ("inet_ntoa: %s", strerror (errno)); /* strerror? */

  if ((info = hash_find (nodes_index, tmpstr)))
    {
      if (gettimeofday (&(info->last_received), NULL) < 0)
        err_exit ("gettimeofday: %s", strerror (errno));

      if (cmd_args.debug)
        fprintf (stderr, "Ping Reply from %s\n", info->hostname);
    }
}
Ejemplo n.º 5
0
/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_ipmi_recvfrom (ipmiconsole_ctx_t c)
{
  char buffer[IPMICONSOLE_PACKET_BUFLEN];
  struct sockaddr_in from;
  unsigned int fromlen = sizeof (struct sockaddr_in);
  ssize_t len;
  int n, dropped = 0;
  int secure_malloc_flag;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  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.
       */
      len = ipmi_lan_recvfrom (c->connection.ipmi_fd,
                               buffer,
                               IPMICONSOLE_PACKET_BUFLEN,
                               0,
                               (struct sockaddr *)&from,
                               &fromlen);
    } while (len < 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 (len < 0
      && (errno == ECONNRESET
          || errno == ECONNREFUSED))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: connection refused: %s", strerror (errno)));
      return (0);
    }

  if (len < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  if (!len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: no data", strerror (errno)));
      /* Note: Not a fatal error, just return*/
      return (0);
    }

  /* Sanity Check */
  if (from.sin_family != AF_INET
      || from.sin_addr.s_addr != c->session.addr.sin_addr.s_addr)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("received from invalid address"));
      /* Note: Not a fatal error, just return */
      return (0);
    }

  /* Empty the scbuf if it's not empty */
  if (!scbuf_is_empty (c->connection.ipmi_from_bmc))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_from_bmc not empty, draining"));
      do {
        char tempbuf[IPMICONSOLE_PACKET_BUFLEN];
        if (scbuf_read (c->connection.ipmi_from_bmc, tempbuf, IPMICONSOLE_PACKET_BUFLEN) < 0)
          {
            IPMICONSOLE_CTX_DEBUG (c, ("scbuf_read: %s", strerror (errno)));
            break;
          }
      } while(!scbuf_is_empty (c->connection.ipmi_from_bmc));
    }

  if ((n = scbuf_write (c->connection.ipmi_from_bmc, buffer, len, &dropped, secure_malloc_flag)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (n != len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: invalid bytes written; n=%d; len=%d", n, len));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (dropped)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: dropped data: dropped=%d", dropped));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  return (0);
}