aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm48.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsm48.c')
-rw-r--r--src/gsm48.c142
1 files changed, 141 insertions, 1 deletions
diff --git a/src/gsm48.c b/src/gsm48.c
index 2ded2095a..ff989eaf6 100644
--- a/src/gsm48.c
+++ b/src/gsm48.c
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <string.h>
+#include <arpa/inet.h>
+
#include <osmocore/utils.h>
#include <osmocore/tlv.h>
#include <osmocore/gsm48.h>
@@ -93,7 +95,7 @@ static const char *rr_cause_names[] = {
[GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
};
-const char *cc_state_names[] = {
+const char *cc_state_names[32] = {
"NULL",
"INITIATED",
"illegal state 2",
@@ -128,6 +130,73 @@ const char *cc_state_names[] = {
"illegal state 31",
};
+const char *gsm48_cc_msg_names[0x40] = {
+ "unknown 0x00",
+ "ALERTING",
+ "CALL_PROC",
+ "PROGRESS",
+ "ESTAB",
+ "SETUP",
+ "ESTAB_CONF",
+ "CONNECT",
+ "CALL_CONF",
+ "START_CC",
+ "unknown 0x0a",
+ "RECALL",
+ "unknown 0x0c",
+ "unknown 0x0d",
+ "EMERG_SETUP",
+ "CONNECT_ACK",
+ "USER_INFO",
+ "unknown 0x11",
+ "unknown 0x12",
+ "MODIFY_REJECT",
+ "unknown 0x14",
+ "unknown 0x15",
+ "unknown 0x16",
+ "MODIFY",
+ "HOLD",
+ "HOLD_ACK",
+ "HOLD_REJ",
+ "unknown 0x1b",
+ "RETR",
+ "RETR_ACK",
+ "RETR_REJ",
+ "MODIFY_COMPL",
+ "unknown 0x20",
+ "unknown 0x21",
+ "unknown 0x22",
+ "unknown 0x23",
+ "unknown 0x24",
+ "DISCONNECT",
+ "unknown 0x26",
+ "unknown 0x27",
+ "unknown 0x28",
+ "unknown 0x29",
+ "RELEASE_COMPL",
+ "unknown 0x2b",
+ "unknown 0x2c",
+ "RELEASE",
+ "unknown 0x2e",
+ "unknown 0x2f",
+ "unknown 0x30",
+ "STOP_DTMF",
+ "STOP_DTMF_ACK",
+ "unknown 0x33",
+ "STATUS_ENQ",
+ "START_DTMF",
+ "START_DTMF_ACK",
+ "START_DTMF_REJ",
+ "unknown 0x38",
+ "CONG_CTRL",
+ "FACILITY",
+ "unknown 0x3b",
+ "STATUS",
+ "unknown 0x3d",
+ "NOTIFY",
+ "unknown 0x3f",
+};
+
static char strbuf[64];
const char *rr_cause_name(uint8_t cause)
@@ -140,4 +209,75 @@ const char *rr_cause_name(uint8_t cause)
return strbuf;
}
+static void to_bcd(uint8_t *bcd, uint16_t val)
+{
+ bcd[2] = val % 10;
+ val = val / 10;
+ bcd[1] = val % 10;
+ val = val / 10;
+ bcd[0] = val % 10;
+ val = val / 10;
+}
+
+void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
+ uint16_t mnc, uint16_t lac)
+{
+ uint8_t bcd[3];
+
+ to_bcd(bcd, mcc);
+ lai48->digits[0] = bcd[0] | (bcd[1] << 4);
+ lai48->digits[1] = bcd[2];
+
+ to_bcd(bcd, mnc);
+ /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
+#if 0
+ lai48->digits[1] |= bcd[2] << 4;
+ lai48->digits[2] = bcd[0] | (bcd[1] << 4);
+#else
+ lai48->digits[1] |= 0xf << 4;
+ lai48->digits[2] = bcd[1] | (bcd[2] << 4);
+#endif
+
+ lai48->lac = htons(lac);
+}
+
+int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi)
+{
+ uint32_t *tptr = (uint32_t *) &buf[3];
+
+ buf[0] = GSM48_IE_MOBILE_ID;
+ buf[1] = GSM48_TMSI_LEN;
+ buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
+ *tptr = htonl(tmsi);
+
+ return 7;
+}
+
+int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi)
+{
+ unsigned int length = strlen(imsi), i, off = 0;
+ uint8_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) {
+ uint8_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];
+}