This adds a per BTS control command 'timezone' which expects a value of the format '<hours>,<mins>,<dst>' or 'off' to set the value of bts->tz. It has the same functionality like the existing VTY command 'timezone' in network/bts.
Sponsored-by: On-Waves ehf Ticket: OW#978 --- openbsc/src/osmo-bsc/osmo_bsc_ctrl.c | 113 ++++++++++++++++++++++++++++++++++ openbsc/tests/ctrl_test_runner.py | 26 ++++++++ 2 files changed, 139 insertions(+)
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c index 39859d6..42f4672 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c @@ -376,6 +376,116 @@ err: return 1; }
+CTRL_CMD_DEFINE(bts_timezone, "timezone"); +static int get_bts_timezone(struct ctrl_cmd *cmd, void *data) +{ + struct gsm_bts *bts = (struct gsm_bts *) cmd->node; + if (!bts) { + cmd->reply = "bts not found."; + return CTRL_CMD_ERROR; + } + + if (bts->tz.override) + cmd->reply = talloc_asprintf(cmd, "%d,%d,%d", + bts->tz.hr, bts->tz.mn, bts->tz.dst); + else + cmd->reply = talloc_asprintf(cmd, "off"); + + if (!cmd->reply) { + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; + } + + return CTRL_CMD_REPLY; +} + +static int set_bts_timezone(struct ctrl_cmd *cmd, void *data) +{ + char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0; + int override; + struct gsm_bts *bts = (struct gsm_bts *) cmd->node; + if (!bts) { + cmd->reply = "bts not found."; + return CTRL_CMD_ERROR; + } + + tmp = talloc_strdup(cmd, cmd->value); + if (!tmp) + goto oom; + + hourstr = strtok_r(tmp, ",", &saveptr); + minstr = strtok_r(NULL, ",", &saveptr); + dststr = strtok_r(NULL, ",", &saveptr); + + override = 0; + + if (hourstr != NULL) + override = strcasecmp(hourstr, "off") != 0; + + bts->tz.override = override; + + if (override) { + bts->tz.hr = hourstr ? atol(hourstr) : 0; + bts->tz.mn = minstr ? atol(minstr) : 0; + bts->tz.dst = dststr ? atol(dststr) : 0; + } + + talloc_free(tmp); + tmp = NULL; + + return get_bts_timezone(cmd, data); + +oom: + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; +} + +static int verify_bts_timezone(struct ctrl_cmd *cmd, const char *value, void *data) +{ + char *saveptr, *hourstr, *minstr, *dststr, *tmp; + time_t tstamp; + int valid; + int override, tz_hours, tz_mins, tz_dst; + + tmp = talloc_strdup(cmd, value); + if (!tmp) + return 1; + + hourstr = strtok_r(tmp, ",", &saveptr); + minstr = strtok_r(NULL, ",", &saveptr); + dststr = strtok_r(NULL, ",", &saveptr); + + if (hourstr == NULL) + goto err; + + override = strcasecmp(hourstr, "off") != 0; + + if (! override) + return 0; + + if (minstr == NULL || dststr == NULL) + goto err; + + tz_hours = atol(hourstr); + tz_mins = atol(minstr); + tz_dst = atol(dststr); + + talloc_free(tmp); + tmp = NULL; + + if ((tz_hours < -19) || (tz_hours > 19) || + (tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) || + (tz_dst < 0) || (tz_dst > 2)) + goto err; + + return 0; + +err: + talloc_free(tmp); + cmd->reply = talloc_strdup(cmd, "The format is <hours>,<mins>,<dst> or 'off' where -19 <= hours <= 19, mins in {0, 15, 30, 45}, and 0 <= dst <= 2"); + return 1; +} + CTRL_CMD_DEFINE(bts_rf_state, "rf_state"); static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) { @@ -495,6 +605,9 @@ int bsc_ctrl_cmds_install(struct gsm_network *net) rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc); if (rc) goto end; + rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_timezone); + if (rc) + goto end; rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock); if (rc) goto end; diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py index dfdec40..306722b 100644 --- a/openbsc/tests/ctrl_test_runner.py +++ b/openbsc/tests/ctrl_test_runner.py @@ -201,6 +201,32 @@ class TestCtrlBSC(TestCtrlBase): self.assertEquals(r['var'], 'bts.0.rf_state') self.assertEquals(r['value'], 'inoperational,unlocked,on')
+ def testTimezone(self): + r = self.do_get('bts.0.timezone') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'bts.0.timezone') + self.assertEquals(r['value'], 'off') + + r = self.do_set('bts.0.timezone', '-2,15,2') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'bts.0.timezone') + self.assertEquals(r['value'], '-2,15,2') + + r = self.do_get('bts.0.timezone') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'bts.0.timezone') + self.assertEquals(r['value'], '-2,15,2') + + r = self.do_set('bts.0.timezone', 'off') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'bts.0.timezone') + self.assertEquals(r['value'], 'off') + + r = self.do_get('bts.0.timezone') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'bts.0.timezone') + self.assertEquals(r['value'], 'off') + def add_bsc_test(suite, workdir): if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")): print("Skipping the BSC test")
On Tue, Oct 01, 2013 at 01:26:42PM +0200, Jacob Erlbeck wrote:
Dear Jacob,
thank you for the patch.
- struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
- if (!bts) {
I added an empty line between the two
- if (! override)
return 0;
I removed the extrap space and added a talloc_free(tmp);
r = self.do_set('bts.0.timezone', '-2,15,2')self.assertEquals(r['mtype'], 'SET_REPLY')self.assertEquals(r['var'], 'bts.0.timezone')self.assertEquals(r['value'], '-2,15,2')
I added two commands with invalid input.. one with longer input (where the extra data is just ignored) and one with a shorter one.
applying it now and push it to master (then backport)
Jacob Erlbeck wrote:
- if ((tz_hours < -19) || (tz_hours > 19) ||
(tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) ||(tz_dst < 0) || (tz_dst > 2))goto err;
No need for all these parentheses, but oh well.
More importantly - are you sure that daylight savings is only ever 0, 1 or 2 hours? I seem to remember that this isn't true for some odd place, but unfortunately I don't remember where, so this would need a bit of research.. :\
//Peter
On 10/01/2013 11:00 PM, Peter Stuge wrote:
Jacob Erlbeck wrote:
- if ((tz_hours < -19) || (tz_hours > 19) ||
(tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) ||(tz_dst < 0) || (tz_dst > 2))goto err;No need for all these parentheses, but oh well.
It's at least consistent to the style already present in that file.
More importantly - are you sure that daylight savings is only ever 0, 1 or 2 hours? I seem to remember that this isn't true for some odd place, but unfortunately I don't remember where, so this would need a bit of research.. :\
That reflects the possible values for the "Daylight Saving Time" information element being described in 3GPP TS 24.008, 10.5.3.12. So even if there were countries with e.g. 3 hours DST we couldn't encode it:
Daylight Saving Time value (octet 3) Bits 2 1 0 0 No adjustment for Daylight Saving Time 0 1 +1 hour adjustment for Daylight Saving Time 1 0 +2 hours adjustment for Daylight Saving Time 1 1 Reserved (Quoted from Table 10.5.97a/3GPP TS 24.008)
Jacob