/* 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); }