summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2019-09-17 13:13:52 +0200
committerpespin <pespin@sysmocom.de>2019-10-07 13:14:14 +0000
commit0cbe8f01003ca71209c12eacac3abaeb9a7df862 (patch)
tree7b867229dd5492857a010b3da4c850c47d887f31 /src
parent4ad3cb1044df8538f8014e8e2ac6d1dc0dc0c451 (diff)
tdef: Introduce min_val and max_val fields
This is useful for timers expected to have a range of valid or expected values. Validation is done at runtime when timer values are set by the app or by the user through the VTY. Related: OS#4190 Change-Id: I4661ac41c29a009a1d5fc57d87aaee6041c7d1b2
Diffstat (limited to 'src')
-rw-r--r--src/tdef.c56
-rw-r--r--src/vty/tdef_vty.c35
2 files changed, 81 insertions, 10 deletions
diff --git a/src/tdef.c b/src/tdef.c
index ab6a51b4..94d987fa 100644
--- a/src/tdef.c
+++ b/src/tdef.c
@@ -136,14 +136,22 @@ static unsigned long osmo_tdef_round(unsigned long val, enum osmo_tdef_unit from
/*! Set all osmo_tdef values to the default_val.
* It is convenient to define a tdefs array by setting only the default_val, and calling osmo_tdefs_reset() once for
- * program startup. (See also osmo_tdef_vty_init())
+ * program startup. (See also osmo_tdef_vty_init()).
+ * During call to this function, default values are verified to be inside valid range; process is aborted otherwise.
* \param[in] tdefs Array of timer definitions, last entry being fully zero.
*/
void osmo_tdefs_reset(struct osmo_tdef *tdefs)
{
struct osmo_tdef *t;
- osmo_tdef_for_each(t, tdefs)
+ osmo_tdef_for_each(t, tdefs) {
+ if (!osmo_tdef_val_in_range(t, t->default_val)) {
+ char range_str[64];
+ osmo_tdef_range_str_buf(range_str, sizeof(range_str), t);
+ osmo_panic("%s:%d Timer " OSMO_T_FMT " contains default value %lu not in range %s\n",
+ __FILE__, __LINE__, OSMO_T_FMT_ARGS(t->T), t->default_val, range_str);
+ }
t->val = t->default_val;
+ }
}
/*! Return the value of a T timer from a list of osmo_tdef, in the given unit.
@@ -221,13 +229,55 @@ struct osmo_tdef *osmo_tdef_get_entry(struct osmo_tdef *tdefs, int T)
*/
int osmo_tdef_set(struct osmo_tdef *tdefs, int T, unsigned long val, enum osmo_tdef_unit val_unit)
{
+ unsigned long new_val;
struct osmo_tdef *t = osmo_tdef_get_entry(tdefs, T);
if (!t)
return -EEXIST;
- t->val = osmo_tdef_round(val, val_unit, t->unit);
+
+ new_val = osmo_tdef_round(val, val_unit, t->unit);
+ if (!osmo_tdef_val_in_range(t, new_val))
+ return -ERANGE;
+
+ t->val = new_val;
return 0;
}
+/*! Check if value new_val is in range of valid possible values for timer entry tdef.
+ * \param[in] tdef Timer entry from a timer definition table.
+ * \param[in] new_val The value whose validity to check, in units as per this timer entry.
+ * \return true if inside range, false otherwise.
+ */
+bool osmo_tdef_val_in_range(struct osmo_tdef *tdef, unsigned long new_val)
+{
+ return new_val >= tdef->min_val && (!tdef->max_val || new_val <= tdef->max_val);
+}
+
+/*! Write string representation of osmo_tdef range into buf.
+ * \param[in] buf The buffer where the string representation is stored.
+ * \param[in] buf_len Length of buffer in bytes.
+ * \param[in] tdef Timer entry from a timer definition table.
+ * \return The number of characters printed on success, negative on error. See snprintf().
+ */
+int osmo_tdef_range_str_buf(char *buf, size_t buf_len, struct osmo_tdef *t)
+{
+ int ret, len = 0, offset = 0, rem = buf_len;
+
+ buf[0] = '\0';
+ ret = snprintf(buf + offset, rem, "[%lu .. ", t->min_val);
+ if (ret < 0)
+ return ret;
+ OSMO_SNPRINTF_RET(ret, rem, offset, len);
+
+ if (t->max_val)
+ ret = snprintf(buf + offset, rem, "%lu]", t->max_val);
+ else
+ ret = snprintf(buf + offset, rem, "inf]");
+ if (ret < 0)
+ return ret;
+ OSMO_SNPRINTF_RET(ret, rem, offset, len);
+ return ret;
+}
+
/*! Using osmo_tdef for osmo_fsm_inst: find a given state's osmo_tdef_state_timeout entry.
*
* The timeouts_array shall contain exactly 32 elements, regardless whether only some of them are actually populated
diff --git a/src/vty/tdef_vty.c b/src/vty/tdef_vty.c
index eb05c3c5..4549a61c 100644
--- a/src/vty/tdef_vty.c
+++ b/src/vty/tdef_vty.c
@@ -115,12 +115,22 @@ unsigned long osmo_tdef_vty_parse_val_arg(const char *val_arg, unsigned long def
*/
int osmo_tdef_vty_set_cmd(struct vty *vty, struct osmo_tdef *tdefs, const char **args)
{
+ unsigned long new_val;
const char *T_arg = args[0];
const char *val_arg = args[1];
struct osmo_tdef *t = osmo_tdef_vty_parse_T_arg(vty, tdefs, T_arg);
if (!t)
return CMD_WARNING;
- t->val = osmo_tdef_vty_parse_val_arg(val_arg, t->default_val);
+ new_val = osmo_tdef_vty_parse_val_arg(val_arg, t->default_val);
+
+ if (!osmo_tdef_val_in_range(t, new_val)) {
+ char range_str[64];
+ osmo_tdef_range_str_buf(range_str, sizeof(range_str), t);
+ vty_out(vty, "%% Timer " OSMO_T_FMT " value %lu is out of range %s%s",
+ OSMO_T_FMT_ARGS(t->T), new_val, range_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ t->val = new_val;
return CMD_SUCCESS;
}
@@ -161,18 +171,29 @@ int osmo_tdef_vty_show_cmd(struct vty *vty, struct osmo_tdef *tdefs, const char
*/
void osmo_tdef_vty_out_one_va(struct vty *vty, struct osmo_tdef *t, const char *prefix_fmt, va_list va)
{
+ char range_str[64];
+
if (!t) {
vty_out(vty, "%% Error: no such timer%s", VTY_NEWLINE);
return;
}
if (prefix_fmt)
vty_out_va(vty, prefix_fmt, va);
- vty_out(vty, OSMO_T_FMT " = %lu%s%s\t%s (default: %lu%s%s)%s",
- OSMO_T_FMT_ARGS(t->T), t->val,
- t->unit == OSMO_TDEF_CUSTOM ? "" : " ", t->unit == OSMO_TDEF_CUSTOM ? "" : osmo_tdef_unit_name(t->unit),
- t->desc, t->default_val,
- t->unit == OSMO_TDEF_CUSTOM ? "" : " ", t->unit == OSMO_TDEF_CUSTOM ? "" : osmo_tdef_unit_name(t->unit),
- VTY_NEWLINE);
+
+ vty_out(vty, OSMO_T_FMT " = %lu", OSMO_T_FMT_ARGS(t->T), t->val);
+ if (t->unit != OSMO_TDEF_CUSTOM)
+ vty_out(vty, " %s", osmo_tdef_unit_name(t->unit));
+
+ vty_out(vty, "\t%s (default: %lu", t->desc, t->default_val);
+ if (t->unit != OSMO_TDEF_CUSTOM)
+ vty_out(vty, " %s", osmo_tdef_unit_name(t->unit));
+
+ if (t->min_val || t->max_val) {
+ osmo_tdef_range_str_buf(range_str, sizeof(range_str), t);
+ vty_out(vty, ", range: %s", range_str);
+ }
+
+ vty_out(vty, ")%s", VTY_NEWLINE);
}
/*! Write to VTY the current status of one timer.