The power profile configuration options added in commit 7059a05a3fb2
("Introduce the power profile.") specify their maximum range as INT_MAX.
The values are stored as UInteger32 values and the default value is
0xFFFFFFFF. On most platforms, a signed integer cannot hold 0xFFFFFFFF, and
on these platforms ptp4l is unable to read the default configuration file:

  $ ./ptp4l -f configs/default.cfg -i eno0
  0xFFFFFFFF is an out of range value for option 
power_profile.2011.grandmasterTimeInaccuracy at line 44
  failed to parse configuration file configs/default.cfg

Fix this by modifying the configuration code to store the integer values
internally as long longs, which are required by the C standard, and all
platforms that Linux supports, to be at least 64bits long.

To avoid casting issues, also introduce config_get_uint to obtain these
UInteger32 values from the configuration code properly as unsigned values.

Signed-off-by: Jacob Keller <jacob.e.kel...@intel.com>
---
 config.c | 40 +++++++++++++++++++++++++++++++---------
 config.h |  3 +++
 port.c   |  6 +++---
 util.c   | 15 +++++++++++++++
 util.h   | 16 ++++++++++++++++
 5 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/config.c b/config.c
index cb4421f572c7..b3ba4e8bb7aa 100644
--- a/config.c
+++ b/config.c
@@ -62,7 +62,7 @@ struct config_enum {
 };
 
 typedef union {
-       int i;
+       long long i;
        double d;
        char *s;
 } any_t;
@@ -309,9 +309,9 @@ struct config_item config_tab[] = {
        GLOB_ITEM_DBL("pi_proportional_norm_max", 0.7, DBL_MIN, 1.0),
        GLOB_ITEM_DBL("pi_proportional_scale", 0.0, 0.0, DBL_MAX),
        PORT_ITEM_ENU("power_profile.version", IEEE_C37_238_VERSION_NONE, 
ieee_c37_238_enu),
-       PORT_ITEM_INT("power_profile.2011.grandmasterTimeInaccuracy", 
0xFFFFFFFF, 0, INT_MAX),
-       PORT_ITEM_INT("power_profile.2011.networkTimeInaccuracy", 0, 0, 
INT_MAX),
-       PORT_ITEM_INT("power_profile.2017.totalTimeInaccuracy", 0xFFFFFFFF, 0, 
INT_MAX),
+       PORT_ITEM_INT("power_profile.2011.grandmasterTimeInaccuracy", 
0xFFFFFFFF, 0, UINT32_MAX),
+       PORT_ITEM_INT("power_profile.2011.networkTimeInaccuracy", 0, 0, 
UINT32_MAX),
+       PORT_ITEM_INT("power_profile.2017.totalTimeInaccuracy", 0xFFFFFFFF, 0, 
UINT32_MAX),
        PORT_ITEM_INT("power_profile.grandmasterID", 0, 0, 0xFFFF),
        GLOB_ITEM_INT("priority1", 128, 0, UINT8_MAX),
        GLOB_ITEM_INT("priority2", 128, 0, UINT8_MAX),
@@ -559,8 +559,8 @@ static enum parser_result parse_item(struct config *cfg,
        enum parser_result r;
        struct config_item *cgi, *dst;
        struct config_enum *cte;
+       long long val;
        double df;
-       int val;
 
        r = parse_fault_interval(cfg, section, option, value);
        if (r != NOT_PARSED)
@@ -576,7 +576,7 @@ static enum parser_result parse_item(struct config *cfg,
 
        switch (cgi->type) {
        case CFG_TYPE_INT:
-               r = get_ranged_int(value, &val, cgi->min.i, cgi->max.i);
+               r = get_ranged_ll(value, &val, cgi->min.i, cgi->max.i);
                break;
        case CFG_TYPE_DOUBLE:
                r = get_ranged_double(value, &df, cgi->min.d, cgi->max.d);
@@ -1021,10 +1021,32 @@ int config_get_int(struct config *cfg, const char 
*section, const char *option)
        case CFG_TYPE_ENUM:
                break;
        }
-       pr_debug("config item %s.%s is %d", section, option, ci->val.i);
+       pr_debug("config item %s.%s is %lld", section, option, ci->val.i);
        return ci->val.i;
 }
 
+unsigned int
+config_get_uint(struct config *cfg, const char *section, const char *option)
+{
+       struct config_item *ci = config_find_item(cfg, section, option);
+
+       if (!ci) {
+               pr_err("bug: config option %s missing!", option);
+               exit(-1);
+       }
+       switch (ci->type) {
+       case CFG_TYPE_DOUBLE:
+       case CFG_TYPE_STRING:
+               pr_err("bug: config option %s type mismatch!", option);
+               exit(-1);
+       case CFG_TYPE_INT:
+       case CFG_TYPE_ENUM:
+               break;
+       }
+       pr_debug("config item %s.%s is %lld", section, option, ci->val.i);
+       return (unsigned int)ci->val.i;
+}
+
 char *config_get_string(struct config *cfg, const char *section,
                        const char *option)
 {
@@ -1141,7 +1163,7 @@ int config_set_section_int(struct config *cfg, const char 
*section,
        if (!section) {
                cgi->flags |= CFG_ITEM_LOCKED;
                cgi->val.i = val;
-               pr_debug("locked item global.%s as %d", option, cgi->val.i);
+               pr_debug("locked item global.%s as %lld", option, cgi->val.i);
                return 0;
        }
        /* Create or update this port specific item. */
@@ -1153,7 +1175,7 @@ int config_set_section_int(struct config *cfg, const char 
*section,
                }
        }
        dst->val.i = val;
-       pr_debug("section item %s.%s now %d", section, option, dst->val.i);
+       pr_debug("section item %s.%s now %lld", section, option, dst->val.i);
        return 0;
 }
 
diff --git a/config.h b/config.h
index 14d2f64415dc..10de851ddc2f 100644
--- a/config.h
+++ b/config.h
@@ -61,6 +61,9 @@ double config_get_double(struct config *cfg, const char 
*section,
 int config_get_int(struct config *cfg, const char *section,
                   const char *option);
 
+unsigned int config_get_uint(struct config *cfg, const char *section,
+                            const char *option);
+
 char *config_get_string(struct config *cfg, const char *section,
                        const char *option);
 
diff --git a/port.c b/port.c
index 3453716f6020..697cf08ce421 100644
--- a/port.c
+++ b/port.c
@@ -3401,11 +3401,11 @@ struct port *port_open(const char *phc_device,
        p->pwr.grandmasterID =
                config_get_int(cfg, p->name, "power_profile.grandmasterID");
        p->pwr.grandmasterTimeInaccuracy =
-               config_get_int(cfg, p->name, 
"power_profile.2011.grandmasterTimeInaccuracy");
+               config_get_uint(cfg, p->name, 
"power_profile.2011.grandmasterTimeInaccuracy");
        p->pwr.networkTimeInaccuracy =
-               config_get_int(cfg, p->name, 
"power_profile.2011.networkTimeInaccuracy");
+               config_get_uint(cfg, p->name, 
"power_profile.2011.networkTimeInaccuracy");
        p->pwr.totalTimeInaccuracy =
-               config_get_int(cfg, p->name, 
"power_profile.2017.totalTimeInaccuracy");
+               config_get_uint(cfg, p->name, 
"power_profile.2017.totalTimeInaccuracy");
        p->slave_event_monitor = clock_slave_monitor(clock);
 
        if (!port_is_uds(p) && unicast_client_initialize(p)) {
diff --git a/util.c b/util.c
index e204c9cdb02a..d189701702ff 100644
--- a/util.c
+++ b/util.c
@@ -531,6 +531,21 @@ enum parser_result get_ranged_uint(const char *str_val, 
unsigned int *result,
        return PARSED_OK;
 }
 
+enum parser_result get_ranged_ll(const char *str_val, long long *result,
+                                long long min, long long max)
+{
+       long long parsed_val;
+       char *endptr = NULL;
+       errno = 0;
+       parsed_val = strtoll(str_val, &endptr, 0);
+       if (*endptr != '\0' || endptr == str_val)
+               return MALFORMED;
+       if (errno == ERANGE || parsed_val < min || parsed_val > max)
+               return OUT_OF_RANGE;
+       *result = parsed_val;
+       return PARSED_OK;
+}
+
 enum parser_result get_ranged_double(const char *str_val, double *result,
                                     double min, double max)
 {
diff --git a/util.h b/util.h
index 2bbde7186bce..ad772cc1d466 100644
--- a/util.h
+++ b/util.h
@@ -295,6 +295,22 @@ enum parser_result get_ranged_int(const char *str_val, int 
*result,
 enum parser_result get_ranged_uint(const char *str_val, unsigned int *result,
                                   unsigned int min, unsigned int max);
 
+/**
+ * get a long long integer value from string with error checking and range
+ * specification.
+ *
+ * @param str_val    string which contains an integer value.
+ * @param result     parsed value is stored in here.
+ * @param min        lower limit. return out_of_range if parsed value
+ *                   is less than min.
+ * @param max        upper limit. return out_of_range if parsed value
+ *                   is bigger than max.
+ * @return           parsed_ok on success, malformed if str_val is malformed,
+ *                   out_of_range if str_val is out of range.
+ */
+enum parser_result get_ranged_ll(const char *str_val, long long *result,
+                                long long min, long long max);
+
 /**
  * Get a double value from string with error checking and range
  * specification.
-- 
2.40.0.471.gbd7f14d9353b



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to