aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h3
-rw-r--r--openbsc/src/gsm_04_08.c2
-rw-r--r--openbsc/src/gsm_04_08_utils.c37
-rw-r--r--openbsc/src/paging.c2
-rw-r--r--openbsc/tests/gsm0408/gsm0408_test.c40
5 files changed, 78 insertions, 6 deletions
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 8f0e4658c..6f367864f 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -708,7 +708,8 @@ int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand);
int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
struct msgb *gsm48_msgb_alloc(void);
int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
-int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
+int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
+int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char* imsi);
int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index abb6e86bf..eeabc0fce 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -899,7 +899,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
bts->network->network_code, bts->location_area_code);
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
- generate_mid_from_tmsi(mid, tmsi);
+ gsm48_generate_mid_from_tmsi(mid, tmsi);
DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index e771ea3b2..c62f04d57 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -164,6 +164,12 @@ static char bcd2char(u_int8_t bcd)
return 'A' + (bcd - 0xa);
}
+/* only works for numbers in ascci */
+static u_int8_t char2bcd(char c)
+{
+ return c - 0x30;
+}
+
void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
u_int16_t mnc, u_int16_t lac)
@@ -187,7 +193,7 @@ void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
lai48->lac = htons(lac);
}
-int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
+int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
{
u_int32_t *tptr = (u_int32_t *) &buf[3];
@@ -199,6 +205,35 @@ int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
return 7;
}
+int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char *imsi)
+{
+ unsigned int length = strlen(imsi), i, off = 0;
+ u_int8_t odd = (length & 0x1) == 1;
+
+ buf[0] = GSM48_IE_MOBILE_ID;
+ buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
+
+ /* if the length is even we will fill half of the last octet */
+ if (odd)
+ buf[1] = (length + 1) >> 1;
+ else
+ buf[1] = (length + 2) >> 1;
+
+ for (i = 1; i < buf[1]; ++i) {
+ u_int8_t lower, upper;
+
+ lower = char2bcd(imsi[++off]);
+ if (!odd && off + 1 == length)
+ upper = 0x0f;
+ else
+ upper = char2bcd(imsi[++off]) & 0x0f;
+
+ buf[2 + i] = (upper << 4) | lower;
+ }
+
+ return 2 + buf[1];
+}
+
/* Section 9.1.8 / Table 9.9 */
struct chreq {
u_int8_t val;
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index c79356e50..fd0611a14 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -99,7 +99,7 @@ static void page_ms(struct gsm_paging_request *request)
page_group = calculate_group(request->bts, request->subscr);
tmsi = strtoul(request->subscr->tmsi, NULL, 10);
- mi_len = generate_mid_from_tmsi(mi, tmsi);
+ mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
rsl_paging_cmd(request->bts, page_group, mi_len, mi,
request->chan_type);
}
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index c99766a72..bbf812965 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -24,13 +24,20 @@
#include <stdlib.h>
#include <openbsc/gsm_04_08.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
#define COMPARE(result, op, value) \
if (!((result) op (value))) {\
fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \
exit(-1); \
}
-
+
+#define COMPARE_STR(result, value) \
+ if (strcmp(result, value) != 0) { \
+ fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \
+ exit(-1); \
+ }
/*
* Test Location Area Identifier formatting. Table 10.5.3 of 04.08
@@ -58,9 +65,38 @@ static void test_location_area_identifier(void)
COMPARE(lai48.lac, ==, htons(0x000f));
}
+static void test_mi_functionality(void)
+{
+ const char *imsi_odd = "987654321098763";
+ const char *imsi_even = "9876543210987654";
+ const u_int32_t tmsi = 0xfabeacd0;
+ u_int8_t mi[128];
+ unsigned int mi_len;
+ char mi_parsed[GSM48_MI_SIZE];
+
+ printf("Testing parsing and generating TMSI/IMSI\n");
+
+ /* tmsi code */
+ mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
+ gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len - 2);
+ COMPARE((u_int32_t)strtoul(mi_parsed, NULL, 10), ==, tmsi);
+
+ /* imsi code */
+ mi_len = gsm48_generate_mid_from_imsi(mi, imsi_odd);
+ gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2);
+ printf("hex: %s\n", hexdump(mi, mi_len));
+ COMPARE_STR(mi_parsed, imsi_odd);
+
+ mi_len = gsm48_generate_mid_from_imsi(mi, imsi_even);
+ gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2);
+ printf("hex: %s\n", hexdump(mi, mi_len));
+ COMPARE_STR(mi_parsed, imsi_even);
+}
+
int main(int argc, char** argv)
{
- test_location_area_identifier();
+ test_location_area_identifier();
+ test_mi_functionality();
}