示例#1
0
/* http://tools.ietf.org/html/rfc7252#section-3
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |Ver| T |  TKL  |      Code     |          Message ID           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |   Token (if any, TKL bytes) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |   Options (if any) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |1 1 1 1 1 1 1 1|    Payload (if any) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
{
    uint8_t *urlpos = pkt->url;
    coap_hdr_t *hdr = (coap_hdr_t *)buf;

    pkt->hdr = hdr;

    uint8_t *pkt_pos = hdr->data;
    uint8_t *pkt_end = buf + len;

    memset(pkt->url, '\0', NANOCOAP_URL_MAX);
    pkt->payload_len = 0;
    pkt->observe_value = UINT32_MAX;

    /* token value (tkl bytes) */
    if (coap_get_token_len(pkt)) {
        pkt->token = pkt_pos;
        pkt_pos += coap_get_token_len(pkt);
    }
    else {
        pkt->token = NULL;
    }

    /* parse options */
    int option_nr = 0;
    while (pkt_pos != pkt_end) {
        uint8_t option_byte = *pkt_pos++;
        if (option_byte == 0xff) {
            pkt->payload = pkt_pos;
            pkt->payload_len = buf + len - pkt_pos;
            DEBUG("payload len = %u\n", pkt->payload_len);
            break;
        }
        else {
            int option_delta = _decode_value(option_byte >> 4, &pkt_pos, pkt_end);
            if (option_delta < 0) {
                DEBUG("bad op delta\n");
                return -EBADMSG;
            }
            int option_len = _decode_value(option_byte & 0xf, &pkt_pos, pkt_end);
            if (option_len < 0) {
                DEBUG("bad op len\n");
                return -EBADMSG;
            }
            option_nr += option_delta;
            DEBUG("option nr=%i len=%i\n", option_nr, option_len);

            switch (option_nr) {
                case COAP_OPT_URI_HOST:
                    DEBUG("nanocoap: ignoring Uri-Host option!\n");
                    break;
                case COAP_OPT_URI_PATH:
                    *urlpos++ = '/';
                    memcpy(urlpos, pkt_pos, option_len);
                    urlpos += option_len;
                    break;
                case COAP_OPT_CONTENT_FORMAT:
                    if (option_len == 0) {
                        pkt->content_type = 0;
                    }
                    else if (option_len == 1) {
                        pkt->content_type = *pkt_pos;
                    }
                    else if (option_len == 2) {
                        memcpy(&pkt->content_type, pkt_pos, 2);
                        pkt->content_type = ntohs(pkt->content_type);
                    }
                    break;
                case COAP_OPT_OBSERVE:
                    if (option_len < 4) {
                        pkt->observe_value = _decode_uint(pkt_pos, option_len);
                    }
                    else {
                        DEBUG("nanocoap: discarding packet with invalid option length.\n");
                        return -EBADMSG;
                    }
                    break;
                default:
                    DEBUG("nanocoap: unhandled option nr=%i len=%i critical=%u\n", option_nr, option_len, option_nr & 1);
                    if (option_nr & 1) {
                        DEBUG("nanocoap: discarding packet with unknown critical option.\n");
                        return -EBADMSG;
                    }
            }

            pkt_pos += option_len;
        }
    }

    DEBUG("coap pkt parsed. code=%u detail=%u payload_len=%u, 0x%02x\n",
          coap_get_code_class(pkt),
          coap_get_code_detail(pkt),
          pkt->payload_len, hdr->code);

    return 0;
}
static config_err_t
hysteresis_threshold_checkout (const char *section_name,
                               struct config_keyvalue *kv,
                               void *arg)
{
  ipmi_sensors_config_state_data_t *state_data;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  config_err_t ret;
  uint8_t positive_going_threshold_hysteresis_value;
  uint8_t negative_going_threshold_hysteresis_value;
  uint8_t value_raw;
  double value_calc;
  uint8_t hysteresis_support;
  uint8_t sensor_number;

  assert (section_name);
  assert (kv);
  assert (arg);
  
  state_data = (ipmi_sensors_config_state_data_t *)arg;

  if ((ret = seek_to_sdr_record (state_data,
				 section_name)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_capabilities (state_data->sdr_ctx,
					  NULL,
					  0,
                                          NULL,
                                          NULL,
                                          &hysteresis_support,
                                          NULL,
                                          NULL) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_sensor_capabilities: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  /* achu: shouldn't hit this, was calculated during section setup.
   * verbose mode should hit 'undefined' checkout
   */
  if (hysteresis_support != IPMI_SDR_READABLE_HYSTERESIS_SUPPORT
      && hysteresis_support != IPMI_SDR_READABLE_SETTABLE_HYSTERESIS_SUPPORT)
    {
      rv = CONFIG_ERR_NON_FATAL_ERROR;
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_number (state_data->sdr_ctx,
				    NULL,
				    0,
                                    &sensor_number) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_sensor_number: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if ((ret = _get_hysteresis (state_data,
                              sensor_number,
                              &positive_going_threshold_hysteresis_value,
                              &negative_going_threshold_hysteresis_value)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (!strcasecmp (kv->key->key_name, "Positive_Going_Threshold_Hysteresis"))
    value_raw = positive_going_threshold_hysteresis_value;
  else if (!strcasecmp (kv->key->key_name, "Negative_Going_Threshold_Hysteresis"))
    value_raw = negative_going_threshold_hysteresis_value;
  else
    /* unknown key_name - fatal error */
    goto cleanup;

  /* 0 means hysteresis is not used, so don't decode */
  if (value_raw == 0)
    {
      if (config_section_update_keyvalue_output (state_data->pstate,
                                                 kv,
                                                 "None") < 0)
        goto cleanup;
    }
  else
    {
      if ((ret = _decode_value (state_data,
                                value_raw,
                                &value_calc)) != CONFIG_ERR_SUCCESS)
        {
          rv = ret;
          goto cleanup;
        }

      if (config_section_update_keyvalue_output_double (state_data->pstate,
                                                        kv,
                                                        value_calc) < 0)
        goto cleanup;
    }

  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  return (rv);
}
/* achu:
 *
 * The range of potential inputs is limited by the sensor decoding
 * values and the "range" of values it can convert the threshold-raw
 * value into.  Also, the threshold raw data is a 1 byte field, which
 * may be signed or unsigned.
 *
 * Outside of some math I currently don't want to think about, there
 * is really no way to determine if the raw data that is calculated by
 * ipmi_sensor_decode_raw_value() is within range at the end.  So the
 * way that we'll check for a valid input range is to get the raw
 * value, then convert is back to a calculated value.  If we get a
 * value that is reasonably close to what the user input, we'll
 * consider the input from the user legit.
 */
static config_validate_t
_floating_point_in_range (const char *section_name,
                          const char *key_name,
                          const char *value,
                          double value_input,
                          void *arg)
{
  ipmi_sensors_config_state_data_t *state_data;
  config_validate_t rv = CONFIG_VALIDATE_FATAL_ERROR;
  config_err_t ret;
  uint8_t threshold_raw;
  uint8_t sensor_number;
  double threshold_calc;
  double threshold_range_min, threshold_range_max;

  assert (section_name);
  assert (key_name);
  assert (value);
  assert (arg);
  
  state_data = (ipmi_sensors_config_state_data_t *)arg;

  if ((ret = seek_to_sdr_record (state_data,
				 section_name)) != CONFIG_ERR_SUCCESS)
    {
      if (ret == CONFIG_ERR_NON_FATAL_ERROR)
        rv = CONFIG_VALIDATE_NON_FATAL_ERROR;
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_number (state_data->sdr_ctx,
				    NULL,
				    0,
                                    &sensor_number) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_sensor_number: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if ((ret = _decode_value_raw (state_data,
                                value,
                                &threshold_raw)) != CONFIG_ERR_SUCCESS)
    {
      if (ret == CONFIG_ERR_NON_FATAL_ERROR)
        rv = CONFIG_VALIDATE_NON_FATAL_ERROR;
      goto cleanup;
    }

  if ((ret = _decode_value (state_data,
                            threshold_raw,
                            &threshold_calc)) != CONFIG_ERR_SUCCESS)
    {
      if (ret == CONFIG_ERR_NON_FATAL_ERROR)
        rv = CONFIG_VALIDATE_NON_FATAL_ERROR;
      goto cleanup;
    }

  threshold_range_min = threshold_calc * THRESHOLD_RANGE_MIN_MULTIPLIER;
  threshold_range_max = threshold_calc * THRESHOLD_RANGE_MAX_MULTIPLIER;

  /* achu: technically shouldn't compare doubles to constants, but I
   * think its ok here.
   */
  if ((value_input >= 0.0
       && (value_input < threshold_range_min
           || value_input > threshold_range_max))
      || (value_input < 0.0
          && (value_input > threshold_range_min
              || value_input < threshold_range_max)))
    rv = CONFIG_VALIDATE_OUT_OF_RANGE_VALUE;
  else
    rv = CONFIG_VALIDATE_VALID_VALUE;

 cleanup:
  return (rv);
}
static config_err_t
threshold_checkout (const char *section_name,
                    struct config_keyvalue *kv,
                    void *arg)
{
  ipmi_sensors_config_state_data_t *state_data;
  fiid_obj_t obj_cmd_rs = NULL;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  config_err_t ret;
  char *readable_str;
  char *threshold_str;
  uint8_t readable;
  uint8_t threshold_raw;
  uint64_t val;
  double threshold_calc;
  uint8_t sensor_number;

  assert (section_name);
  assert (kv);
  assert (arg);
  
  state_data = (ipmi_sensors_config_state_data_t *)arg;

  if ((ret = seek_to_sdr_record (state_data,
				 section_name)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (ipmi_sdr_parse_sensor_number (state_data->sdr_ctx,
				    NULL,
				    0,
                                    &sensor_number) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_sensor_number: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sensor_thresholds_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if (ipmi_cmd_get_sensor_thresholds (state_data->ipmi_ctx,
                                      sensor_number,
                                      obj_cmd_rs) < 0)
    {
      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_get_sensor_thresholds: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      if (config_is_non_fatal_error (state_data->ipmi_ctx,
                                     obj_cmd_rs,
                                     &ret))
        rv = ret;

      /*
       * IPMI Workaround (achu)
       *
       * Discovered on HP DL585
       *
       * Seems that the HP machine doesn't support the "Get Sensor
       * Thresholds" command.  99% of the time if a command is invalid
       * on a remote machine, that's a fatal error and we should exit.
       * I suppose this is an exception though.  We can continue on
       * even if this command isn't supported.  The user just doesn't
       * get to configure these thresholds.
       */
      if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
          && ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INVALID_COMMAND) == 1)
        rv = CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }

  if (!strcasecmp (kv->key->key_name, "Lower_Non_Critical_Threshold"))
    {
      readable_str = "readable_thresholds.lower_non_critical_threshold";
      threshold_str = "lower_non_critical_threshold";
    }
  else if (!strcasecmp (kv->key->key_name, "Lower_Critical_Threshold"))
    {
      readable_str = "readable_thresholds.lower_critical_threshold";
      threshold_str = "lower_critical_threshold";
    }
  else if (!strcasecmp (kv->key->key_name, "Lower_Non_Recoverable_Threshold"))
    {
      readable_str = "readable_thresholds.lower_non_recoverable_threshold";
      threshold_str = "lower_non_recoverable_threshold";
    }
  else if (!strcasecmp (kv->key->key_name, "Upper_Non_Critical_Threshold"))
    {
      readable_str = "readable_thresholds.upper_non_critical_threshold";
      threshold_str = "upper_non_critical_threshold";
    }
  else if (!strcasecmp (kv->key->key_name, "Upper_Critical_Threshold"))
    {
      readable_str = "readable_thresholds.upper_critical_threshold";
      threshold_str = "upper_critical_threshold";
    }
  else if (!strcasecmp (kv->key->key_name, "Upper_Non_Recoverable_Threshold"))
    {
      readable_str = "readable_thresholds.upper_non_recoverable_threshold";
      threshold_str = "upper_non_recoverable_threshold";
    }
  else
    /* unknown key_name - fatal error */
    goto cleanup;

  if (FIID_OBJ_GET (obj_cmd_rs, readable_str, &val) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get: '%s': %s\n",
                       readable_str,
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }
  readable = val;

  if (!readable)
    {
      /* Inconsistency w/ the SDR, should be readable */
      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "%s:%s - threshold not readable\n",
                         section_name,
                         kv->key->key_name);
      rv = CONFIG_ERR_NON_FATAL_ERROR;
      goto cleanup;
    }

  if (FIID_OBJ_GET (obj_cmd_rs, threshold_str, &val) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get: '%s': %s\n",
                       threshold_str,
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }
  threshold_raw = val;

  if ((ret = _decode_value (state_data,
                            threshold_raw,
                            &threshold_calc)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (config_section_update_keyvalue_output_double (state_data->pstate,
                                                    kv,
                                                    threshold_calc) < 0)
    goto cleanup;

  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}