aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorGus Bourg <gus@bourg.net>2011-12-02 10:18:17 +0100
committerHarald Welte <laforge@gnumonks.org>2011-12-02 10:18:17 +0100
commit1c5dd2c9bbc26902cdad0487e090e97e983b0787 (patch)
tree0d9fec784cb5d1a06c49f18b7561131895fd9c04 /openbsc/src
parent6b8a56c365baa65119cc9bc827b971f2362b12a0 (diff)
Add NITZ (timezone) support as part of MM INFO
The UTC offset from the operating system will be used by default to calculate the NITZ in MM INFO. However, a "timezone" vty command is added at the BTS level, allowing BTS-specific overrides, e.g. in case BTSs are distributed accross multiple timezones.
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/libbsc/bsc_vty.c29
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c74
2 files changed, 81 insertions, 22 deletions
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 724486ff7..ed74397ec 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -448,6 +448,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+ if (bts->tz_bts_specific != 0)
+ vty_out(vty, " timezone %d %d%s", bts->tzhr, bts->tzmn, VTY_NEWLINE);
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, " cell reselection hysteresis %u%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@@ -1495,6 +1497,31 @@ DEFUN(cfg_bts_bsic,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_timezone,
+ cfg_bts_timezone_cmd,
+ "timezone <-19-19> (0|15|30|45)",
+ "Set the Timezone Offset of this BTS\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int tzhr = atoi(argv[0]);
+ int tzmn = atoi(argv[1]);
+
+ bts->tzhr = tzhr;
+ bts->tzmn = tzmn;
+ bts->tz_bts_specific=1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_timezone,
+ cfg_bts_no_timezone_cmd,
+ "no timezone",
+ "disable bts specific timezone\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->tz_bts_specific=0;
+ return CMD_SUCCESS;
+}
DEFUN(cfg_bts_unit_id,
cfg_bts_unit_id_cmd,
@@ -2691,6 +2718,8 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_tsc_cmd);
install_element(BTS_NODE, &cfg_bts_bsic_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
+ install_element(BTS_NODE, &cfg_bts_timezone_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_serno_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
install_element(BTS_NODE, &cfg_bts_stream_id_cmd);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 7bf62b784..7c0d62895 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -610,12 +610,17 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
return gsm0408_authorize(conn, msg);
}
-#if 0
-static uint8_t to_bcd8(uint8_t val)
+/* Turn int into semi-octet representation: 98 => 0x89 */
+static uint8_t bcdify(uint8_t value)
{
- return ((val / 10) << 4) | (val % 10);
+ uint8_t ret;
+
+ ret = value / 10;
+ ret |= (value % 10) << 4;
+
+ return ret;
}
-#endif
+
/* Section 9.2.15a */
int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
@@ -623,13 +628,14 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
struct gsm_network *net = conn->bts->network;
+ struct gsm_bts *bts = conn->bts;
uint8_t *ptr8;
int name_len, name_pad;
-#if 0
+
time_t cur_t;
- struct tm* cur_time;
- int tz15min;
-#endif
+ struct tm* gmt_time;
+ struct tm* local_time;
+ int tzunits;
msg->lchan = conn->lchan;
@@ -696,24 +702,48 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
}
-#if 0
/* Section 10.5.3.9 */
cur_t = time(NULL);
- cur_time = gmtime(&cur_t);
+ gmt_time = gmtime(&cur_t);
+
ptr8 = msgb_put(msg, 8);
ptr8[0] = GSM48_IE_NET_TIME_TZ;
- ptr8[1] = to_bcd8(cur_time->tm_year % 100);
- ptr8[2] = to_bcd8(cur_time->tm_mon);
- ptr8[3] = to_bcd8(cur_time->tm_mday);
- ptr8[4] = to_bcd8(cur_time->tm_hour);
- ptr8[5] = to_bcd8(cur_time->tm_min);
- ptr8[6] = to_bcd8(cur_time->tm_sec);
- /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
- tz15min = (cur_time->tm_gmtoff)/(60*15);
- ptr8[7] = to_bcd8(tz15min);
- if (tz15min < 0)
- ptr8[7] |= 0x80;
-#endif
+ ptr8[1] = bcdify(gmt_time->tm_year % 100);
+ ptr8[2] = bcdify(gmt_time->tm_mon + 1);
+ ptr8[3] = bcdify(gmt_time->tm_mday);
+ ptr8[4] = bcdify(gmt_time->tm_hour);
+ ptr8[5] = bcdify(gmt_time->tm_min);
+ ptr8[6] = bcdify(gmt_time->tm_sec);
+
+ if (bts->tz_bts_specific) {
+ /* Convert tzhr and tzmn to units */
+ if (bts->tzhr < 0) {
+ tzunits = ((bts->tzhr/-1)*4);
+ tzunits = tzunits + (bts->tzmn/15);
+ ptr8[7] = bcdify(tzunits);
+ /* Set negative time */
+ ptr8[7] |= 0x08;
+ }
+ else {
+ tzunits = bts->tzhr*4;
+ tzunits = tzunits + (bts->tzmn/15);
+ ptr8[7] = bcdify(tzunits);
+ }
+ }
+ else {
+ /* Need to get GSM offset and convert into 15 min units */
+ /* This probably breaks if gmtoff returns a value not evenly divisible by 15? */
+ local_time = localtime(&cur_t);
+ tzunits = (local_time->tm_gmtoff/60)/15;
+ if (tzunits < 0) {
+ tzunits = tzunits/-1;
+ ptr8[7] = bcdify(tzunits);
+ /* Flip it to negative */
+ ptr8[7] |= 0x08;
+ }
+ else
+ ptr8[7] = bcdify(tzunits);
+ }
DEBUGP(DMM, "-> MM INFO\n");