summaryrefslogtreecommitdiffstats
path: root/Src/osmolib/src/host/layer23
diff options
context:
space:
mode:
authorroot2012-02-28 14:15:19 +0100
committerroot2012-02-28 14:15:19 +0100
commit1116885d96725ce064db04604e4d197a136b163c (patch)
tree22ba472d309f1ac66918f09cc63bb9be057cf579 /Src/osmolib/src/host/layer23
parentcompiled version added (diff)
downloadimsi-catcher-detection-1116885d96725ce064db04604e4d197a136b163c.tar.gz
imsi-catcher-detection-1116885d96725ce064db04604e4d197a136b163c.tar.xz
imsi-catcher-detection-1116885d96725ce064db04604e4d197a136b163c.zip
updated codebase to latest version of osmocombb
Diffstat (limited to 'Src/osmolib/src/host/layer23')
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/common/Makefile.am2
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/common/logging.h2
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/common/networks.h2
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/common/osmocom_data.h2
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/common/sim.h10
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/Makefile.am5
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm411_sms.h33
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm480_ss.h9
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h7
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h13
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/mncc.h11
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/settings.h4
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/subscriber.h4
-rw-r--r--Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/transaction.h19
-rw-r--r--Src/osmolib/src/host/layer23/src/common/Makefile.am2
-rw-r--r--Src/osmolib/src/host/layer23/src/common/gps.c23
-rw-r--r--Src/osmolib/src/host/layer23/src/common/l1ctl.c2
-rw-r--r--Src/osmolib/src/host/layer23/src/common/l1ctl_lapdm_glue.c2
-rw-r--r--Src/osmolib/src/host/layer23/src/common/l1l2_interface.c3
-rw-r--r--Src/osmolib/src/host/layer23/src/common/logging.c11
-rw-r--r--Src/osmolib/src/host/layer23/src/common/main.c1
-rw-r--r--Src/osmolib/src/host/layer23/src/common/networks.c2
-rw-r--r--Src/osmolib/src/host/layer23/src/common/sap_interface.c3
-rw-r--r--Src/osmolib/src/host/layer23/src/common/sim.c21
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/app_bcch_scan.c1
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/app_cbch_sniff.c1
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/app_ccch_scan.c34
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/app_echo_test.c1
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/bcch_scan.c3
-rwxr-xr-x[-rw-r--r--]Src/osmolib/src/host/layer23/src/misc/catcherbin951882 -> 1003279 bytes
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/catcher.c13
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/cell_log.c1
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/rslms.c2
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/Makefile.am4
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/app_mobile.c9
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm322.c12
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm411_sms.c941
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm480_ss.c1289
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm48_cc.c41
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm48_mm.c293
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/gsm48_rr.c590
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/main.c47
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/mnccms.c4
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/settings.c5
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/subscriber.c73
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/support.c2
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/transaction.c10
-rw-r--r--Src/osmolib/src/host/layer23/src/mobile/vty_interface.c148
48 files changed, 3408 insertions, 309 deletions
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/Makefile.am b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/Makefile.am
index 26e63cf..945c73d 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/Makefile.am
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/Makefile.am
@@ -1,2 +1,2 @@
-noinst_HEADERS = l1ctl.h l1l2_interface.h l23_app.h lapdm.h logging.h \
+noinst_HEADERS = l1ctl.h l1l2_interface.h l23_app.h logging.h \
networks.h gps.h sysinfo.h osmocom_data.h
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/logging.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/logging.h
index 554b767..3efa57a 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/logging.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/logging.h
@@ -12,11 +12,11 @@ enum {
DNB,
DMM,
DCC,
+ DSS,
DSMS,
DMNCC,
DMEAS,
DPAG,
- DLAPDM,
DL1C,
DSAP,
DSUM,
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/networks.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/networks.h
index e681216..d34f316 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/networks.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/networks.h
@@ -10,7 +10,7 @@ struct gsm_networks {
};
int gsm_match_mcc(uint16_t mcc, char *imsi);
-int gsm_match_mnc(uint16_t mcc, uint8_t mnc, char *imsi);
+int gsm_match_mnc(uint16_t mcc, uint16_t mnc, char *imsi);
const char *gsm_print_mcc(uint16_t mcc);
const char *gsm_print_mnc(uint16_t mcc);
const char *gsm_get_mcc(uint16_t mcc);
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
index 8f15007..ab7c250 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
@@ -11,7 +11,7 @@ struct osmocom_ms;
#include <osmocom/bb/mobile/support.h>
#include <osmocom/bb/mobile/settings.h>
#include <osmocom/bb/mobile/subscriber.h>
-#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/gsm/lapdm.h>
#include <osmocom/bb/common/sap_interface.h>
#include <osmocom/bb/mobile/gsm48_rr.h>
#include <osmocom/bb/common/sysinfo.h>
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/sim.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/sim.h
index a676b92..95d2147 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/common/sim.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/common/sim.h
@@ -266,6 +266,16 @@ struct gsm1111_ef_adn {
uint8_t ext_id;
} __attribute__ ((packed));
+/* Section 10.5.6 */
+struct gsm1111_ef_smsp {
+ uint8_t par_ind;
+ uint8_t tp_da[12];
+ uint8_t ts_sca[12];
+ uint8_t tp_proto;
+ uint8_t tp_dcs;
+ uint8_t tp_vp;
+} __attribute__ ((packed));
+
int sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg);
int gsm_sim_init(struct osmocom_ms *ms);
int gsm_sim_exit(struct osmocom_ms *ms);
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/Makefile.am b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/Makefile.am
index 65b7ce7..b58b952 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/Makefile.am
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/Makefile.am
@@ -1,2 +1,3 @@
-noinst_HEADERS = gsm322.h gsm48_cc.h gsm48_mm.h gsm48_rr.h mncc.h settings.h \
- subscriber.h support.h transaction.h vty.h mncc_sock.h
+noinst_HEADERS = gsm322.h gsm480_ss.h gsm411_sms.h gsm48_cc.h gsm48_mm.h \
+ gsm48_rr.h mncc.h settings.h subscriber.h support.h \
+ transaction.h vty.h mncc_sock.h
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm411_sms.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm411_sms.h
new file mode 100644
index 0000000..d14e6db
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm411_sms.h
@@ -0,0 +1,33 @@
+#ifndef _GSM411_SMS_H
+#define _GSM411_SMS_H
+
+#define SMS_HDR_SIZE 128
+#define SMS_TEXT_SIZE 256
+
+struct gsm_sms {
+ unsigned long validity_minutes;
+ uint8_t reply_path_req;
+ uint8_t status_rep_req;
+ uint8_t ud_hdr_ind;
+ uint8_t protocol_id;
+ uint8_t data_coding_scheme;
+ uint8_t msg_ref;
+ char address[20+1]; /* DA LV is 12 bytes max, i.e. 10 bytes
+ * BCD == 20 bytes string */
+ time_t time;
+ uint8_t user_data_len;
+ uint8_t user_data[SMS_TEXT_SIZE];
+
+ char text[SMS_TEXT_SIZE];
+};
+
+int gsm411_sms_init(struct osmocom_ms *ms);
+int gsm411_sms_exit(struct osmocom_ms *ms);
+struct gsm_sms *sms_alloc(void);
+void sms_free(struct gsm_sms *sms);
+struct gsm_sms *sms_from_text(const char *receiver, int dcs, const char *text);
+int gsm411_rcv_sms(struct osmocom_ms *ms, struct msgb *msg);
+int sms_send(struct osmocom_ms *ms, const char *sms_sca, const char *number,
+ const char *text);
+
+#endif /* _GSM411_SMS_H */
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm480_ss.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm480_ss.h
new file mode 100644
index 0000000..ecd778e
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm480_ss.h
@@ -0,0 +1,9 @@
+#ifndef _GSM480_SS_H
+#define _GSM480_SS_H
+
+int gsm480_ss_init(struct osmocom_ms *ms);
+int gsm480_ss_exit(struct osmocom_ms *ms);
+int gsm480_rcv_ss(struct osmocom_ms *ms, struct msgb *msg);
+int ss_send(struct osmocom_ms *ms, const char *code, int new_trans);
+
+#endif /* _GSM480_SS_H */
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h
index afdcf02..fb62aae 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h
@@ -58,6 +58,7 @@ struct gsm48_mmxx_hdr {
int msg_type; /* MMxx_* primitive */
uint32_t ref; /* reference to transaction */
uint32_t transaction_id; /* transaction identifier */
+ uint8_t sapi; /* sapi */
uint8_t emergency; /* emergency type of call */
uint8_t cause; /* cause used for release */
};
@@ -193,6 +194,9 @@ struct gsm48_mmlayer {
uint8_t est_cause; /* cause of establishment msg */
int mr_substate; /* rem most recent substate */
uint8_t power_off_idle; /* waits for IDLE before po */
+
+ /* sapi 3 */
+ int sapi3_link;
};
/* MM connection entry */
@@ -204,6 +208,7 @@ struct gsm48_mm_conn {
uint32_t ref; /* reference to trans */
uint8_t protocol;
uint8_t transaction_id;
+ uint8_t sapi;
int state;
};
@@ -221,7 +226,7 @@ int gsm48_mmr_dequeue(struct osmocom_ms *ms);
int gsm48_mmevent_dequeue(struct osmocom_ms *ms);
int gsm48_mmxx_downmsg(struct osmocom_ms *ms, struct msgb *msg);
struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref,
- uint8_t transaction_id);
+ uint8_t transaction_id, uint8_t sapi);
const char *get_mmr_name(int value);
const char *get_mmxx_name(int value);
extern const char *gsm48_mm_state_names[];
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
index 1af09f4..b7280fb 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
@@ -54,6 +54,7 @@
/* GSM 04.08 RR-SAP header */
struct gsm48_rr_hdr {
uint32_t msg_type; /* RR-* primitive */
+ uint8_t sapi;
uint8_t cause;
};
@@ -63,6 +64,12 @@ struct gsm48_rr_hdr {
#define GSM48_RR_ST_DEDICATED 2
#define GSM48_RR_ST_REL_PEND 3
+/* special states for SAPI 3 link */
+#define GSM48_RR_SAPI3ST_IDLE 0
+#define GSM48_RR_SAPI3ST_WAIT_EST 1
+#define GSM48_RR_SAPI3ST_ESTAB 2
+#define GSM48_RR_SAPI3ST_WAIT_REL 3
+
/* modify state */
#define GSM48_RR_MOD_NONE 0
#define GSM48_RR_MOD_IMM_ASS 1
@@ -79,7 +86,6 @@ struct gsm48_rr_cd {
uint8_t maio;
uint8_t hsn;
uint8_t chan_nr; /* type, slot, sub slot */
- uint8_t link_id;
uint8_t ind_tx_power; /* last indicated power */
uint8_t ind_ta; /* last indicated ta */
uint8_t mob_alloc_lv[9]; /* len + up to 64 bits */
@@ -133,6 +139,7 @@ struct gsm48_rrlayer {
uint8_t rr_est_req;
struct msgb *rr_est_msg;
uint8_t est_cause; /* cause used for establishment */
+ uint8_t paging_mi_type; /* how did we got paged? */
/* channel request states */
uint8_t wait_assign; /* waiting for assignment state */
@@ -175,6 +182,10 @@ struct gsm48_rrlayer {
/* audio flow */
uint8_t audio_mode;
+
+ /* sapi 3 */
+ uint8_t sapi3_state;
+ uint8_t sapi3_link_id;
};
const char *get_rr_name(int value);
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/mncc.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/mncc.h
index 1d7f779..cad1883 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/mncc.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/mncc.h
@@ -130,11 +130,11 @@ struct gsm_call {
struct gsm_mncc {
/* context based information */
- u_int32_t msg_type;
- u_int32_t callref;
+ uint32_t msg_type;
+ uint32_t callref;
/* which fields are present */
- u_int32_t fields;
+ uint32_t fields;
/* data derived informations (MNCC_F_ based) */
struct gsm_mncc_bearer_cap bearer_cap;
@@ -161,12 +161,13 @@ struct gsm_mncc {
int emergency;
char imsi[16];
+ unsigned char lchan_type;
unsigned char lchan_mode;
};
struct gsm_data_frame {
- u_int32_t msg_type;
- u_int32_t callref;
+ uint32_t msg_type;
+ uint32_t callref;
unsigned char data[0];
};
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/settings.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/settings.h
index cd1b800..6d44696 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/settings.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/settings.h
@@ -23,6 +23,9 @@ struct gsm_settings {
int sim_type; /* selects card on power on */
char emergency_imsi[16];
+ /* SMS */
+ char sms_sca[22];
+
/* test card simulator settings */
char test_imsi[16];
uint32_t test_tmsi;
@@ -84,6 +87,7 @@ struct gsm_settings {
/* radio */
uint16_t dsc_max;
+ uint8_t force_rekey;
/* dialing */
struct llist_head abbrev;
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/subscriber.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/subscriber.h
index cc0cfac..3e50e29 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/subscriber.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/subscriber.h
@@ -77,6 +77,9 @@ struct gsm_subscriber {
uint32_t sim_handle_query;
uint32_t sim_handle_update;
uint32_t sim_handle_key;
+
+ /* SMS */
+ char sms_sca[22];
};
int gsm_subscr_init(struct osmocom_ms *ms);
@@ -102,6 +105,7 @@ int gsm_subscr_dump_forbidden_plmn(struct osmocom_ms *ms,
void gsm_subscr_dump(struct gsm_subscriber *subscr,
void (*print)(void *, const char *, ...), void *priv);
char *gsm_check_imsi(const char *imsi);
+int gsm_subscr_get_key_seq(struct osmocom_ms *ms, struct gsm_subscriber *subscr);
#endif /* _SUBSCRIBER_H */
diff --git a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/transaction.h b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/transaction.h
index aa62f46..8c06d5d 100644
--- a/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/transaction.h
+++ b/Src/osmolib/src/host/layer23/include/osmocom/bb/mobile/transaction.h
@@ -2,6 +2,8 @@
#define _TRANSACT_H
#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm0411_smc.h>
+#include <osmocom/gsm/gsm0411_smr.h>
/* One transaction */
struct gsm_trans {
@@ -38,18 +40,21 @@ struct gsm_trans {
struct osmo_timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
} cc;
-#if 0
struct {
- uint8_t link_id; /* RSL Link ID to be used for this trans */
- int is_mt; /* is this a MO (0) or MT (1) transfer */
- enum gsm411_cp_state cp_state;
- struct osmo_timer_list cp_timer;
+ /* current supp.serv. state */
+ int state;
+
+ uint8_t invoke_id;
+ struct msgb *msg;
+ } ss;
+ struct {
+ uint8_t sapi; /* SAPI to be used for this trans */
- enum gsm411_rp_state rp_state;
+ struct gsm411_smc_inst smc_inst;
+ struct gsm411_smr_inst smr_inst;
struct gsm_sms *sms;
} sms;
-#endif
};
};
diff --git a/Src/osmolib/src/host/layer23/src/common/Makefile.am b/Src/osmolib/src/host/layer23/src/common/Makefile.am
index aca2eb4..73a0fc9 100644
--- a/Src/osmolib/src/host/layer23/src/common/Makefile.am
+++ b/Src/osmolib/src/host/layer23/src/common/Makefile.am
@@ -2,5 +2,5 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
noinst_LIBRARIES = liblayer23.a
-liblayer23_a_SOURCES = l1ctl.c l1l2_interface.c sap_interface.c lapdm.c \
+liblayer23_a_SOURCES = l1ctl.c l1l2_interface.c sap_interface.c \
logging.c networks.c sim.c sysinfo.c gps.c l1ctl_lapdm_glue.c
diff --git a/Src/osmolib/src/host/layer23/src/common/gps.c b/Src/osmolib/src/host/layer23/src/common/gps.c
index 38aae2c..e9aaa97 100644
--- a/Src/osmolib/src/host/layer23/src/common/gps.c
+++ b/Src/osmolib/src/host/layer23/src/common/gps.c
@@ -56,7 +56,12 @@ static struct osmo_fd gps_bfd;
#ifdef _HAVE_GPSD
-static struct gps_data_t* gdata;
+static struct gps_data_t* gdata = NULL;
+
+#if GPSD_API_MAJOR_VERSION >= 5
+static struct gps_data_t _gdata;
+#define gps_poll gps_read
+#endif
int osmo_gpsd_cb(struct osmo_fd *bfd, unsigned int what)
{
@@ -69,9 +74,15 @@ int osmo_gpsd_cb(struct osmo_fd *bfd, unsigned int what)
if (gdata->online)
goto gps_not_ready;
+#if GPSD_API_MAJOR_VERSION >= 5
+ /* gps has no data */
+ if (gps_waiting(gdata, 500))
+ goto gps_not_ready;
+#else
/* gps has no data */
if (gps_waiting(gdata))
goto gps_not_ready;
+#endif
/* polling returned an error */
if (gps_poll(gdata))
@@ -111,7 +122,14 @@ int osmo_gpsd_open(void)
gps_bfd.when = BSC_FD_READ;
gps_bfd.cb = osmo_gpsd_cb;
+#if GPSD_API_MAJOR_VERSION >= 5
+ if (gps_open(g.gpsd_host, g.gpsd_port, &_gdata) == -1)
+ gdata = NULL;
+ else
+ gdata = &_gdata;
+#else
gdata = gps_open(g.gpsd_host, g.gpsd_port);
+#endif
if (gdata == NULL) {
LOGP(DGPS, LOGL_ERROR, "Can't connect to gpsd\n");
return -1;
@@ -139,6 +157,9 @@ void osmo_gpsd_close(void)
osmo_fd_unregister(&gps_bfd);
+#if GPSD_API_MAJOR_VERSION >= 5
+ gps_stream(gdata, WATCH_DISABLE, NULL);
+#endif
gps_close(gdata);
gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
}
diff --git a/Src/osmolib/src/host/layer23/src/common/l1ctl.c b/Src/osmolib/src/host/layer23/src/common/l1ctl.c
index e3ab4c9..f998ebc 100644
--- a/Src/osmolib/src/host/layer23/src/common/l1ctl.c
+++ b/Src/osmolib/src/host/layer23/src/common/l1ctl.c
@@ -44,7 +44,7 @@
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/l1l2_interface.h>
-#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/gsm/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/codec/codec.h>
diff --git a/Src/osmolib/src/host/layer23/src/common/l1ctl_lapdm_glue.c b/Src/osmolib/src/host/layer23/src/common/l1ctl_lapdm_glue.c
index db071a3..0b2a8ed 100644
--- a/Src/osmolib/src/host/layer23/src/common/l1ctl_lapdm_glue.c
+++ b/Src/osmolib/src/host/layer23/src/common/l1ctl_lapdm_glue.c
@@ -27,7 +27,7 @@
#include <osmocom/gsm/prim.h>
#include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/gsm/lapdm.h>
/* LAPDm wants to send a PH-* primitive to the physical layer (L1) */
int l1ctl_ph_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
diff --git a/Src/osmolib/src/host/layer23/src/common/l1l2_interface.c b/Src/osmolib/src/host/layer23/src/common/l1l2_interface.c
index abaa64f..d89995d 100644
--- a/Src/osmolib/src/host/layer23/src/common/l1l2_interface.c
+++ b/Src/osmolib/src/host/layer23/src/common/l1l2_interface.c
@@ -45,7 +45,7 @@
static int layer2_read(struct osmo_fd *fd)
{
struct msgb *msg;
- u_int16_t len;
+ uint16_t len;
int rc;
msg = msgb_alloc_headroom(GSM_L2_LENGTH+GSM_L2_HEADROOM, GSM_L2_HEADROOM, "Layer2");
@@ -150,6 +150,7 @@ int layer2_close(struct osmocom_ms *ms)
close(ms->l2_wq.bfd.fd);
ms->l2_wq.bfd.fd = -1;
osmo_fd_unregister(&ms->l2_wq.bfd);
+ osmo_wqueue_clear(&ms->l2_wq);
return 0;
}
diff --git a/Src/osmolib/src/host/layer23/src/common/logging.c b/Src/osmolib/src/host/layer23/src/common/logging.c
index 82ce914..d8fd076 100644
--- a/Src/osmolib/src/host/layer23/src/common/logging.c
+++ b/Src/osmolib/src/host/layer23/src/common/logging.c
@@ -68,6 +68,12 @@ static const struct log_info_cat default_categories[] = {
.color = "\033[1;33m",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
+ [DSS] = {
+ .name = "DSS",
+ .description = "Supplenmentary Services",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_DEBUG,
+ },
[DSMS] = {
.name = "DSMS",
.description = "Short Message Service",
@@ -91,11 +97,6 @@ static const struct log_info_cat default_categories[] = {
.color = "\033[33m",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
- [DLAPDM] = {
- .name = "DLAPDM",
- .description = "LAPDm Layer2",
- .enabled = 1, .loglevel = LOGL_NOTICE,
- },
[DL1C] = {
.name = "DL1C",
.description = "Layer 1 Control",
diff --git a/Src/osmolib/src/host/layer23/src/common/main.c b/Src/osmolib/src/host/layer23/src/common/main.c
index 751f95e..eb47b26 100644
--- a/Src/osmolib/src/host/layer23/src/common/main.c
+++ b/Src/osmolib/src/host/layer23/src/common/main.c
@@ -26,7 +26,6 @@
#include <osmocom/bb/common/l1l2_interface.h>
#include <osmocom/bb/common/sap_interface.h>
#include <osmocom/bb/misc/layer3.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/l23_app.h>
diff --git a/Src/osmolib/src/host/layer23/src/common/networks.c b/Src/osmolib/src/host/layer23/src/common/networks.c
index 63221f0..40b70a1 100644
--- a/Src/osmolib/src/host/layer23/src/common/networks.c
+++ b/Src/osmolib/src/host/layer23/src/common/networks.c
@@ -1787,7 +1787,7 @@ int gsm_match_mcc(uint16_t mcc, char *imsi)
}
/* GSM 03.22 Annex A */
-int gsm_match_mnc(uint16_t mcc, uint8_t mnc, char *imsi)
+int gsm_match_mnc(uint16_t mcc, uint16_t mnc, char *imsi)
{
uint16_t sim_mnc;
diff --git a/Src/osmolib/src/host/layer23/src/common/sap_interface.c b/Src/osmolib/src/host/layer23/src/common/sap_interface.c
index fd5cdc3..1dad748 100644
--- a/Src/osmolib/src/host/layer23/src/common/sap_interface.c
+++ b/Src/osmolib/src/host/layer23/src/common/sap_interface.c
@@ -45,7 +45,7 @@
static int sap_read(struct osmo_fd *fd)
{
struct msgb *msg;
- u_int16_t len;
+ uint16_t len;
int rc;
struct osmocom_ms *ms = (struct osmocom_ms *) fd->data;
@@ -150,6 +150,7 @@ int sap_close(struct osmocom_ms *ms)
close(ms->sap_wq.bfd.fd);
ms->sap_wq.bfd.fd = -1;
osmo_fd_unregister(&ms->sap_wq.bfd);
+ osmo_wqueue_clear(&ms->sap_wq);
return 0;
}
diff --git a/Src/osmolib/src/host/layer23/src/common/sim.c b/Src/osmolib/src/host/layer23/src/common/sim.c
index 3aca693..8c89cf0 100644
--- a/Src/osmolib/src/host/layer23/src/common/sim.c
+++ b/Src/osmolib/src/host/layer23/src/common/sim.c
@@ -1045,8 +1045,25 @@ int sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg)
ntohs(ef->file_id), sim->file);
goto sim_error;
}
- /* get length of file */
- ef_len = ntohs(ef->file_size);
+ /* check for record */
+ if (length >= 15 && ef->length >= 2 && ef->structure != 0x00) {
+ /* get length of record */
+ ef_len = ntohs(ef->file_size);
+ if (ef_len < data[14]) {
+ LOGP(DSIM, LOGL_NOTICE, "total length is "
+ "smaller (%d) than record size (%d)\n",
+ ef_len, data[14]);
+ goto request_error;
+ }
+ ef_len = data[14];
+ LOGP(DSIM, LOGL_NOTICE, "selected record (len %d "
+ "structure %d)\n", ef_len, ef->structure);
+ } else {
+ /* get length of file */
+ ef_len = ntohs(ef->file_size);
+ LOGP(DSIM, LOGL_NOTICE, "selected file (len %d)\n",
+ ef_len);
+ }
/* do file command */
sim->job_state = SIM_JST_WAIT_FILE;
switch (sh->job_type) {
diff --git a/Src/osmolib/src/host/layer23/src/misc/app_bcch_scan.c b/Src/osmolib/src/host/layer23/src/misc/app_bcch_scan.c
index 4c31f1a..7b21ed7 100644
--- a/Src/osmolib/src/host/layer23/src/misc/app_bcch_scan.c
+++ b/Src/osmolib/src/host/layer23/src/misc/app_bcch_scan.c
@@ -23,7 +23,6 @@
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/l23_app.h>
#include <osmocom/bb/misc/layer3.h>
diff --git a/Src/osmolib/src/host/layer23/src/misc/app_cbch_sniff.c b/Src/osmolib/src/host/layer23/src/misc/app_cbch_sniff.c
index fb043db..2f45e48 100644
--- a/Src/osmolib/src/host/layer23/src/misc/app_cbch_sniff.c
+++ b/Src/osmolib/src/host/layer23/src/misc/app_cbch_sniff.c
@@ -24,7 +24,6 @@
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/l23_app.h>
#include <osmocom/bb/misc/layer3.h>
diff --git a/Src/osmolib/src/host/layer23/src/misc/app_ccch_scan.c b/Src/osmolib/src/host/layer23/src/misc/app_ccch_scan.c
index 2f60505..d301b7b 100644
--- a/Src/osmolib/src/host/layer23/src/misc/app_ccch_scan.c
+++ b/Src/osmolib/src/host/layer23/src/misc/app_ccch_scan.c
@@ -33,7 +33,6 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/misc/rslms.h>
#include <osmocom/bb/misc/layer3.h>
#include <osmocom/bb/common/osmocom_data.h>
@@ -162,7 +161,8 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
case GSM48_MT_RR_SYSINFO_5ter:
break;
default:
- fprintf(stderr, "\tUnknown SI");
+ LOGP(DRR, LOGL_ERROR, "Unknown SI: %d\n",
+ si_hdr->system_information);
break;
};
}
@@ -352,7 +352,7 @@ static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
chan_need(pag->cneed1), pag->tmsi1);
LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
pag_print_mode(pag->pag_mode),
- chan_need(pag->cneed1), pag->tmsi2);
+ chan_need(pag->cneed2), pag->tmsi2);
/* no optional element */
if (msgb_l3len(msg) < sizeof(*pag) + 3)
@@ -380,6 +380,32 @@ static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
return 0;
}
+static int gsm48_rx_paging_p3(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging3 *pag;
+
+ if (msgb_l3len(msg) < sizeof(*pag)) {
+ LOGP(DRR, LOGL_ERROR, "Paging3 message is too small.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi1);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2), pag->tmsi2);
+ LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ", pag->tmsi3);
+ LOGP(DRR, LOGL_NOTICE, "Paging4: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ", pag->tmsi4);
+
+ return 0;
+}
+
int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
{
struct gsm48_system_information_type_header *sih = msgb_l3(msg);
@@ -396,7 +422,7 @@ int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
gsm48_rx_paging_p2(msg, ms);
break;
case GSM48_MT_RR_PAG_REQ_3:
- LOGP(DRR, LOGL_ERROR, "PAGING of type 3 is not implemented.\n");
+ gsm48_rx_paging_p3(msg, ms);
break;
case GSM48_MT_RR_IMM_ASS:
gsm48_rx_imm_ass(msg, ms);
diff --git a/Src/osmolib/src/host/layer23/src/misc/app_echo_test.c b/Src/osmolib/src/host/layer23/src/misc/app_echo_test.c
index 3d937d2..3a0ee0f 100644
--- a/Src/osmolib/src/host/layer23/src/misc/app_echo_test.c
+++ b/Src/osmolib/src/host/layer23/src/misc/app_echo_test.c
@@ -23,7 +23,6 @@
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/l23_app.h>
#include <osmocom/bb/misc/layer3.h>
diff --git a/Src/osmolib/src/host/layer23/src/misc/bcch_scan.c b/Src/osmolib/src/host/layer23/src/misc/bcch_scan.c
index ddd0eea..4636c9a 100644
--- a/Src/osmolib/src/host/layer23/src/misc/bcch_scan.c
+++ b/Src/osmolib/src/host/layer23/src/misc/bcch_scan.c
@@ -40,7 +40,6 @@
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
/* somewhere in 05.08 */
@@ -275,7 +274,7 @@ static int bscan_sig_cb(unsigned int subsys, unsigned int signal,
rc = get_next_arfcn(&fps);
if (rc < 0) {
fps.state = BSCAN_S_DONE;
- return;
+ return 0;
}
_cinfo_start_arfcn(rc);
break;
diff --git a/Src/osmolib/src/host/layer23/src/misc/catcher b/Src/osmolib/src/host/layer23/src/misc/catcher
index 647207e..ef3d795 100644..100755
--- a/Src/osmolib/src/host/layer23/src/misc/catcher
+++ b/Src/osmolib/src/host/layer23/src/misc/catcher
Binary files differ
diff --git a/Src/osmolib/src/host/layer23/src/misc/catcher.c b/Src/osmolib/src/host/layer23/src/misc/catcher.c
index b97be3d..03bf442 100644
--- a/Src/osmolib/src/host/layer23/src/misc/catcher.c
+++ b/Src/osmolib/src/host/layer23/src/misc/catcher.c
@@ -39,7 +39,6 @@
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/networks.h>
#include <osmocom/bb/common/gps.h>
@@ -190,14 +189,16 @@ static void log_sysinfo(void)
// arfcn, gsm_print_mcc(s->mcc), gsm_print_mnc(s->mnc),
// gsm_get_mcc(s->mcc), gsm_get_mnc(s->mcc, s->mnc), ta_str);
LOGFILE("[SysInfo]\n");
- LOGFILE("country %s\n", gsm_get_mcc(s->mcc))
- LOGFILE("provider %s\n", gsm_get_mnc(s->mcc, s->mnc))
- LOGFILE("arfcn %d\n", s->arfcn);
+ LOGFILE("Country: %s\n", gsm_get_mcc(s->mcc));
+ LOGFILE("Provider: %s\n", gsm_get_mnc(s->mcc, s->mnc));
+ LOGFILE("ARFCN: %d\n", s->arfcn);
+ LOGFILE("Cell_ID: %d\n", s->cell_id);
+ LOGFILE("LAC: %d\n", s->lac);
//log_time();
//log_gps();
- //LOGFILE("bsic %d,%d\n", s->bsic >> 3, s->bsic & 7);
+ LOGFILE("BSIC: %d,%d\n", s->bsic >> 3, s->bsic & 7);
rxlev = meas->rxlev / meas->frames - 110;
- LOGFILE("rxlev %d\n", rxlev);
+ LOGFILE("rxlev: %d\n", rxlev);
//if (s->si1)
// log_frame("si1", s->si1_msg);
if (s->si2)
diff --git a/Src/osmolib/src/host/layer23/src/misc/cell_log.c b/Src/osmolib/src/host/layer23/src/misc/cell_log.c
index 1a9c33c..aa964f4 100644
--- a/Src/osmolib/src/host/layer23/src/misc/cell_log.c
+++ b/Src/osmolib/src/host/layer23/src/misc/cell_log.c
@@ -39,7 +39,6 @@
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/networks.h>
#include <osmocom/bb/common/gps.h>
diff --git a/Src/osmolib/src/host/layer23/src/misc/rslms.c b/Src/osmolib/src/host/layer23/src/misc/rslms.c
index 68956f9..455e663 100644
--- a/Src/osmolib/src/host/layer23/src/misc/rslms.c
+++ b/Src/osmolib/src/host/layer23/src/misc/rslms.c
@@ -30,7 +30,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/gsm/lapdm.h>
#include <osmocom/bb/misc/rslms.h>
#include <osmocom/bb/misc/layer3.h>
#include <osmocom/bb/common/osmocom_data.h>
diff --git a/Src/osmolib/src/host/layer23/src/mobile/Makefile.am b/Src/osmolib/src/host/layer23/src/mobile/Makefile.am
index 4cff9ef..f3365af 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/Makefile.am
+++ b/Src/osmolib/src/host/layer23/src/mobile/Makefile.am
@@ -3,8 +3,8 @@ AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS)
noinst_LIBRARIES = libmobile.a
-libmobile_a_SOURCES = gsm322.c gsm48_cc.c gsm48_mm.c gsm48_rr.c \
- mnccms.c settings.c subscriber.c support.c \
+libmobile_a_SOURCES = gsm322.c gsm480_ss.c gsm411_sms.c gsm48_cc.c gsm48_mm.c \
+ gsm48_rr.c mnccms.c settings.c subscriber.c support.c \
transaction.c vty_interface.c voice.c mncc_sock.c
bin_PROGRAMS = mobile
diff --git a/Src/osmolib/src/host/layer23/src/mobile/app_mobile.c b/Src/osmolib/src/host/layer23/src/mobile/app_mobile.c
index ada9480..da388b2 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/app_mobile.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/app_mobile.c
@@ -28,10 +28,11 @@
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/l1l2_interface.h>
#include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/gps.h>
#include <osmocom/bb/mobile/gsm48_rr.h>
+#include <osmocom/bb/mobile/gsm480_ss.h>
+#include <osmocom/bb/mobile/gsm411_sms.h>
#include <osmocom/bb/mobile/vty.h>
#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/mobile/mncc.h>
@@ -145,6 +146,8 @@ int mobile_exit(struct osmocom_ms *ms, int force)
gsm48_rr_exit(ms);
gsm_subscr_exit(ms);
gsm48_cc_exit(ms);
+ gsm480_ss_exit(ms);
+ gsm411_sms_exit(ms);
gsm_sim_exit(ms);
lapdm_channel_exit(&ms->lapdm_channel);
@@ -168,6 +171,8 @@ int mobile_init(struct osmocom_ms *ms)
gsm_sim_init(ms);
gsm48_cc_init(ms);
+ gsm480_ss_init(ms);
+ gsm411_sms_init(ms);
gsm_voice_init(ms);
gsm_subscr_init(ms);
gsm48_rr_init(ms);
@@ -334,6 +339,8 @@ int l23_app_exit(void)
osmo_gps_close();
+ telnet_exit();
+
return 0;
}
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm322.c b/Src/osmolib/src/host/layer23/src/mobile/gsm322.c
index 9384743..ce5e1e1 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/gsm322.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm322.c
@@ -1840,10 +1840,11 @@ static int gsm322_cs_select(struct osmocom_ms *ms, int index, uint16_t mcc,
/* loop through all scanned frequencies and select cell.
* if an index is given (arfci), we just check this cell only */
- if (index >= 0)
+ if (index >= 0) {
start = end = index;
- else
+ } else {
start = 0; end = 1023+299;
+ }
for (i = start; i <= end; i++) {
cs->list[i].flags &= ~GSM322_CS_FLAG_TEMP_AA;
s = cs->list[i].sysinfo;
@@ -3024,9 +3025,10 @@ int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
cs = &ms->cellsel;
LOGP(DCS, LOGL_INFO, "Loss of CCCH.\n");
if (cs->selected && cs->sel_arfcn == cs->arfcn) {
- LOGP(DCS, LOGL_INFO, "Unselect cell due to loss\n");
- /* unset selected cell */
- gsm322_unselect_cell(cs);
+ /* do not unselect cell */
+ LOGP(DCS, LOGL_INFO, "Keep cell selected after loss, "
+ "so we can use the Neighbour cell information "
+ "for cell re-selection.\n");
}
stop_cs_timer(cs);
gsm322_cs_loss(cs);
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm411_sms.c b/Src/osmolib/src/host/layer23/src/mobile/gsm411_sms.c
new file mode 100644
index 0000000..4347e86
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm411_sms.c
@@ -0,0 +1,941 @@
+/*
+ * Code based on work of:
+ * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
+ * (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010 by On-Waves
+ *
+ * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/transaction.h>
+#include <osmocom/bb/mobile/gsm411_sms.h>
+#include <osmocom/gsm/gsm0411_utils.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/bb/mobile/vty.h>
+
+#define UM_SAPI_SMS 3
+
+extern void *l23_ctx;
+static uint32_t new_callref = 0x40000001;
+
+static int gsm411_rl_recv(struct gsm411_smr_inst *inst, int msg_type,
+ struct msgb *msg);
+static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type,
+ struct msgb *msg);
+static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type,
+ struct msgb *msg, int cp_msg_type);
+static int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type,
+ struct msgb *msg);
+/*
+ * init / exit
+ */
+
+int gsm411_sms_init(struct osmocom_ms *ms)
+{
+ LOGP(DLSMS, LOGL_INFO, "init SMS\n");
+
+ return 0;
+}
+
+int gsm411_sms_exit(struct osmocom_ms *ms)
+{
+ struct gsm_trans *trans, *trans2;
+
+ LOGP(DLSMS, LOGL_INFO, "exit SMS processes for %s\n", ms->name);
+
+ llist_for_each_entry_safe(trans, trans2, &ms->trans_list, entry) {
+ if (trans->protocol == GSM48_PDISC_SMS) {
+ LOGP(DLSMS, LOGL_NOTICE, "Free pendig "
+ "SMS-transaction.\n");
+ trans_free(trans);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * SMS content
+ */
+
+struct gsm_sms *sms_alloc(void)
+{
+ return talloc_zero(l23_ctx, struct gsm_sms);
+}
+
+void sms_free(struct gsm_sms *sms)
+{
+ talloc_free(sms);
+}
+
+struct gsm_sms *sms_from_text(const char *receiver, int dcs, const char *text)
+{
+ struct gsm_sms *sms = sms_alloc();
+
+ if (!sms)
+ return NULL;
+
+ strncpy(sms->text, text, sizeof(sms->text)-1);
+
+ /* FIXME: don't use ID 1 static */
+ sms->reply_path_req = 0;
+ sms->status_rep_req = 0;
+ sms->ud_hdr_ind = 0;
+ sms->protocol_id = 0; /* implicit */
+ sms->data_coding_scheme = dcs;
+ strncpy(sms->address, receiver, sizeof(sms->address)-1);
+ /* Generate user_data */
+ sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
+
+ return sms;
+}
+
+static int gsm411_sms_report(struct osmocom_ms *ms, struct gsm_sms *sms,
+ uint8_t cause)
+{
+ vty_notify(ms, NULL);
+ if (!cause)
+ vty_notify(ms, "SMS to %s successfull\n", sms->address);
+ else
+ vty_notify(ms, "SMS to %s failed: %s\n", sms->address,
+ get_value_string(gsm411_rp_cause_strs, cause));
+
+ return 0;
+}
+/*
+ * transaction
+ */
+
+/* SMS Specific transaction release.
+ * gets called by trans_free, DO NOT CALL YOURSELF!
+ */
+void _gsm411_sms_trans_free(struct gsm_trans *trans)
+{
+ gsm411_smr_clear(&trans->sms.smr_inst);
+ gsm411_smc_clear(&trans->sms.smc_inst);
+
+ if (trans->sms.sms) {
+ LOGP(DLSMS, LOGL_ERROR, "Transaction contains SMS.\n");
+ gsm411_sms_report(trans->ms, trans->sms.sms,
+ GSM411_RP_CAUSE_MO_SMS_REJECTED);
+ sms_free(trans->sms.sms);
+ trans->sms.sms = NULL;
+ }
+}
+
+/* release MM connection, free transaction */
+static int gsm411_trans_free(struct gsm_trans *trans)
+{
+ struct msgb *nmsg;
+
+ /* release MM connection */
+ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_REQ, trans->callref,
+ trans->transaction_id, trans->sms.sapi);
+ if (!nmsg)
+ return -ENOMEM;
+ LOGP(DLSMS, LOGL_INFO, "Sending MMSMS_REL_REQ\n");
+ gsm48_mmxx_downmsg(trans->ms, nmsg);
+
+ trans->callref = 0;
+ trans_free(trans);
+
+ return 0;
+}
+
+/*
+ * receive SMS
+ */
+
+/* now here comes our SMS */
+static int gsm340_rx_sms_deliver(struct osmocom_ms *ms, struct msgb *msg,
+ struct gsm_sms *gsms)
+{
+ const char osmocomsms[] = ".osmocom/bb/sms.txt";
+ int len;
+ const char *home;
+ char *sms_file;
+ char vty_text[sizeof(gsms->text)], *p;
+ FILE *fp;
+
+ /* remove linefeeds and show at VTY */
+ strcpy(vty_text, gsms->text);
+ for (p = vty_text; *p; p++) {
+ if (*p == '\n' || *p == '\r')
+ *p = ' ';
+ }
+ vty_notify(ms, NULL);
+ vty_notify(ms, "SMS from %s: '%s'\n", gsms->address, vty_text);
+
+ home = getenv("HOME");
+ if (!home) {
+fail:
+ fprintf(stderr, "Can't deliver SMS, be sure to create '%s' in "
+ "your home directory.\n", osmocomsms);
+ return GSM411_RP_CAUSE_MT_MEM_EXCEEDED;
+ }
+ len = strlen(home) + 1 + sizeof(osmocomsms);
+ sms_file = talloc_size(l23_ctx, len);
+ if (!sms_file)
+ goto fail;
+ snprintf(sms_file, len, "%s/%s", home, osmocomsms);
+
+ fp = fopen(sms_file, "a");
+ if (!fp)
+ goto fail;
+ fprintf(fp, "[SMS from %s]\n%s\n", gsms->address, gsms->text);
+ fclose(fp);
+
+ talloc_free(sms_file);
+
+ return 0;
+}
+
+/* process an incoming TPDU (called from RP-DATA)
+ * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
+static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg)
+{
+ uint8_t *smsp = msgb_sms(msg);
+ struct gsm_sms *gsms;
+ unsigned int sms_alphabet;
+ uint8_t sms_mti, sms_mms;
+ uint8_t oa_len_bytes;
+ uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
+ int rc = 0;
+
+ gsms = sms_alloc();
+
+ /* invert those fields where 0 means active/present */
+ sms_mti = *smsp & 0x03;
+ sms_mms = !!(*smsp & 0x04);
+ gsms->status_rep_req = (*smsp & 0x20);
+ gsms->ud_hdr_ind = (*smsp & 0x40);
+ gsms->reply_path_req = (*smsp & 0x80);
+ smsp++;
+
+ /* length in bytes of the originate address */
+ oa_len_bytes = 2 + *smsp/2 + *smsp%2;
+ if (oa_len_bytes > 12) {
+ LOGP(DLSMS, LOGL_ERROR, "Originate Address > 12 bytes ?!?\n");
+ rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
+ goto out;
+ }
+ memset(address_lv, 0, sizeof(address_lv));
+ memcpy(address_lv, smsp, oa_len_bytes);
+ /* mangle first byte to reflect length in bytes, not digits */
+ address_lv[0] = oa_len_bytes - 1;
+ /* convert to real number */
+ if (((smsp[1] & 0x70) >> 4) == 1)
+ strcpy(gsms->address, "+");
+ else if (((smsp[1] & 0x70) >> 4) == 2)
+ strcpy(gsms->address, "0");
+ else
+ gsms->address[0] = '\0';
+ gsm48_decode_bcd_number(gsms->address + strlen(gsms->address),
+ sizeof(gsms->address) - strlen(gsms->address), address_lv, 1);
+ smsp += oa_len_bytes;
+
+ gsms->protocol_id = *smsp++;
+ gsms->data_coding_scheme = *smsp++;
+
+ sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
+ if (sms_alphabet == 0xffffffff) {
+ sms_free(gsms);
+ return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
+ }
+
+ /* get timestamp */
+ gsms->time = gsm340_scts(smsp);
+ smsp += 7;
+
+ /* user data */
+ gsms->user_data_len = *smsp++;
+ if (gsms->user_data_len) {
+ memcpy(gsms->user_data, smsp, gsms->user_data_len);
+
+ switch (sms_alphabet) {
+ case DCS_7BIT_DEFAULT:
+ gsm_7bit_decode(gsms->text, smsp, gsms->user_data_len);
+ break;
+ case DCS_8BIT_DATA:
+ case DCS_UCS2:
+ case DCS_NONE:
+ break;
+ }
+ }
+
+ LOGP(DLSMS, LOGL_INFO, "RX SMS: MTI: 0x%02x, "
+ "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, OA: %s, "
+ "UserDataLength: 0x%02x, UserData: \"%s\"\n",
+ sms_mti, gsms->msg_ref,
+ gsms->protocol_id, gsms->data_coding_scheme, gsms->address,
+ gsms->user_data_len,
+ sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
+ osmo_hexdump(gsms->user_data,
+ gsms->user_data_len));
+
+ switch (sms_mti) {
+ case GSM340_SMS_DELIVER_SC2MS:
+ /* MS is receiving an SMS */
+ rc = gsm340_rx_sms_deliver(trans->ms, msg, gsms);
+ break;
+ case GSM340_SMS_STATUS_REP_SC2MS:
+ case GSM340_SMS_SUBMIT_REP_SC2MS:
+ LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
+ rc = GSM411_RP_CAUSE_IE_NOTEXIST;
+ break;
+ default:
+ LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
+ rc = GSM411_RP_CAUSE_IE_NOTEXIST;
+ break;
+ }
+
+out:
+ sms_free(gsms);
+
+ return rc;
+}
+
+static int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
+{
+ struct msgb *msg = gsm411_msgb_alloc();
+
+ LOGP(DLSMS, LOGL_INFO, "TX: SMS RP ACK\n");
+
+ gsm411_push_rp_header(msg, GSM411_MT_RP_ACK_MO, msg_ref);
+ return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ,
+ msg);
+}
+
+static int gsm411_send_rp_error(struct gsm_trans *trans,
+ uint8_t msg_ref, uint8_t cause)
+{
+ struct msgb *msg = gsm411_msgb_alloc();
+
+ msgb_tv_put(msg, 1, cause);
+
+ LOGP(DLSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
+ get_value_string(gsm411_rp_cause_strs, cause));
+
+ gsm411_push_rp_header(msg, GSM411_MT_RP_ERROR_MO, msg_ref);
+ return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ,
+ msg);
+}
+
+/* Receive a 04.11 TPDU inside RP-DATA / user data */
+static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph,
+ uint8_t src_len, uint8_t *src,
+ uint8_t dst_len, uint8_t *dst,
+ uint8_t tpdu_len, uint8_t *tpdu)
+{
+ int rc = 0;
+
+ if (dst_len && dst)
+ LOGP(DLSMS, LOGL_ERROR, "RP-DATA (MT) with DST ?!?\n");
+
+ if (!src_len || !src || !tpdu_len || !tpdu) {
+ LOGP(DLSMS, LOGL_ERROR,
+ "RP-DATA (MO) without DST or TPDU ?!?\n");
+ gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_INV_MAND_INF);
+ return -EIO;
+ }
+ msg->l4h = tpdu;
+
+ LOGP(DLSMS, LOGL_INFO, "DST(%u,%s)\n", src_len,
+ osmo_hexdump(src, src_len));
+ LOGP(DLSMS, LOGL_INFO, "TPDU(%u,%s)\n", msg->tail-msg->l4h,
+ osmo_hexdump(msg->l4h, msg->tail-msg->l4h));
+
+ rc = gsm340_rx_tpdu(trans, msg);
+ if (rc == 0)
+ return gsm411_send_rp_ack(trans, rph->msg_ref);
+ else if (rc > 0)
+ return gsm411_send_rp_error(trans, rph->msg_ref, rc);
+ else
+ return rc;
+}
+
+/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
+static int gsm411_rx_rp_data(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
+{
+ uint8_t src_len, dst_len, rpud_len;
+ uint8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
+
+ /* in the MO case, this should always be zero length */
+ src_len = rph->data[0];
+ if (src_len)
+ src = &rph->data[1];
+
+ dst_len = rph->data[1+src_len];
+ if (dst_len)
+ dst = &rph->data[1+src_len+1];
+
+ rpud_len = rph->data[1+src_len+1+dst_len];
+ if (rpud_len)
+ rp_ud = &rph->data[1+src_len+1+dst_len+1];
+
+ LOGP(DLSMS, LOGL_INFO, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n",
+ src_len, dst_len, rpud_len);
+ return gsm411_rx_rp_ud(msg, trans, rph, src_len, src, dst_len, dst,
+ rpud_len, rp_ud);
+}
+
+/* receive RL DATA */
+static int gsm411_rx_rl_data(struct msgb *msg, struct gsm48_hdr *gh,
+ struct gsm_trans *trans)
+{
+ struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
+ uint8_t msg_type = rp_data->msg_type & 0x07;
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM411_MT_RP_DATA_MT:
+ LOGP(DLSMS, LOGL_INFO, "RX SMS RP-DATA (MT)\n");
+ rc = gsm411_rx_rp_data(msg, trans, rp_data);
+ break;
+ default:
+ LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
+ gsm411_trans_free(trans);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * send SMS
+ */
+
+/* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */
+static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct gsm_sms *sms = trans->sms.sms;
+
+ /* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
+ * successfully received a SMS. We can now safely mark it as
+ * transmitted */
+
+ if (!sms) {
+ LOGP(DLSMS, LOGL_ERROR, "RX RP-ACK but no sms in "
+ "transaction?!?\n");
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_PROTOCOL_ERR);
+ }
+
+ gsm411_sms_report(ms, sms, 0);
+
+ sms_free(sms);
+ trans->sms.sms = NULL;
+
+ return 0;
+}
+
+static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
+ struct gsm411_rp_hdr *rph)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct gsm_sms *sms = trans->sms.sms;
+ uint8_t cause_len = rph->data[0];
+ uint8_t cause = rph->data[1];
+
+ /* Error in response to MT RP_DATA, i.e. the MS did not
+ * successfully receive the SMS. We need to investigate
+ * the cause and take action depending on it */
+
+ LOGP(DLSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
+ trans->ms->name, cause_len, cause,
+ get_value_string(gsm411_rp_cause_strs, cause));
+
+ if (!sms) {
+ LOGP(DLSMS, LOGL_ERROR,
+ "RX RP-ERR, but no sms in transaction?!?\n");
+ return -EINVAL;
+#if 0
+ return gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_PROTOCOL_ERR);
+#endif
+ }
+
+ gsm411_sms_report(ms, sms, cause);
+
+ sms_free(sms);
+ trans->sms.sms = NULL;
+
+ return 0;
+}
+
+/* receive RL REPORT */
+static int gsm411_rx_rl_report(struct msgb *msg, struct gsm48_hdr *gh,
+ struct gsm_trans *trans)
+{
+ struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
+ uint8_t msg_type = rp_data->msg_type & 0x07;
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM411_MT_RP_ACK_MT:
+ LOGP(DLSMS, LOGL_INFO, "RX SMS RP-ACK (MT)\n");
+ rc = gsm411_rx_rp_ack(msg, trans, rp_data);
+ break;
+ case GSM411_MT_RP_ERROR_MT:
+ LOGP(DLSMS, LOGL_INFO, "RX SMS RP-ERROR (MT)\n");
+ rc = gsm411_rx_rp_error(msg, trans, rp_data);
+ break;
+ default:
+ LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
+ gsm411_trans_free(trans);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+/* generate a msgb containing a TPDU derived from struct gsm_sms,
+ * returns total size of TPDU */
+static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
+{
+ uint8_t *smsp;
+ uint8_t da[12]; /* max len per 03.40 */
+ uint8_t da_len = 0;
+ uint8_t octet_len;
+ unsigned int old_msg_len = msg->len;
+ uint8_t sms_vpf = GSM340_TP_VPF_NONE;
+ uint8_t sms_vp;
+
+ /* generate first octet with masked bits */
+ smsp = msgb_put(msg, 1);
+ /* TP-MTI (message type indicator) */
+ *smsp = GSM340_SMS_SUBMIT_MS2SC;
+ /* TP-RD */
+ if (0 /* FIXME */)
+ *smsp |= 0x04;
+ /* TP-VPF */
+ *smsp |= (sms_vpf << 3);
+ /* TP-SRI(deliver)/SRR(submit) */
+ if (sms->status_rep_req)
+ *smsp |= 0x20;
+ /* TP-UDHI (indicating TP-UD contains a header) */
+ if (sms->ud_hdr_ind)
+ *smsp |= 0x40;
+ /* TP-RP */
+ if (sms->reply_path_req)
+ *smsp |= 0x80;
+
+ /* generate message ref */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->msg_ref;
+
+ /* generate destination address */
+ if (sms->address[0] == '+')
+ da_len = gsm340_gen_oa(da, sizeof(da), 0x1, 0x1,
+ sms->address + 1);
+ else
+ da_len = gsm340_gen_oa(da, sizeof(da), 0x0, 0x1, sms->address);
+ smsp = msgb_put(msg, da_len);
+ memcpy(smsp, da, da_len);
+
+ /* generate TP-PID */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->protocol_id;
+
+ /* generate TP-DCS */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->data_coding_scheme;
+
+ /* generate TP-VP */
+ switch (sms_vpf) {
+ case GSM340_TP_VPF_NONE:
+ sms_vp = 0;
+ break;
+ default:
+ fprintf(stderr, "VPF unsupported, please fix!\n");
+ exit(0);
+ }
+ smsp = msgb_put(msg, sms_vp);
+
+ /* generate TP-UDL */
+ smsp = msgb_put(msg, 1);
+ *smsp = sms->user_data_len;
+
+ /* generate TP-UD */
+ switch (gsm338_get_sms_alphabet(sms->data_coding_scheme)) {
+ case DCS_7BIT_DEFAULT:
+ octet_len = sms->user_data_len*7/8;
+ if (sms->user_data_len*7%8 != 0)
+ octet_len++;
+ /* Warning, user_data_len indicates the amount of septets
+ * (characters), we need amount of octets occupied */
+ smsp = msgb_put(msg, octet_len);
+ memcpy(smsp, sms->user_data, octet_len);
+ break;
+ case DCS_UCS2:
+ case DCS_8BIT_DATA:
+ smsp = msgb_put(msg, sms->user_data_len);
+ memcpy(smsp, sms->user_data, sms->user_data_len);
+ break;
+ default:
+ LOGP(DLSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: "
+ "0x%02X\n", sms->data_coding_scheme);
+ break;
+ }
+
+ return msg->len - old_msg_len;
+}
+
+/* Take a SMS in gsm_sms structure and send it. */
+static int gsm411_tx_sms_submit(struct osmocom_ms *ms, const char *sms_sca,
+ struct gsm_sms *sms)
+{
+ struct msgb *msg;
+ struct gsm_trans *trans;
+ uint8_t *data, *rp_ud_len;
+ uint8_t msg_ref = 42;
+ int rc;
+ uint8_t transaction_id;
+ uint8_t sca[11]; /* max len per 03.40 */
+
+ LOGP(DLSMS, LOGL_INFO, "..._sms_submit()\n");
+
+ /* no running, no transaction */
+ if (!ms->started || ms->shutdown) {
+ LOGP(DLSMS, LOGL_ERROR, "Phone is down\n");
+ gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_TEMP_FAIL);
+ sms_free(sms);
+ return -EIO;
+ }
+
+ /* allocate transaction with dummy reference */
+ transaction_id = trans_assign_trans_id(ms, GSM48_PDISC_SMS, 0);
+ if (transaction_id < 0) {
+ LOGP(DLSMS, LOGL_ERROR, "No transaction ID available\n");
+ gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_CONGESTION);
+ sms_free(sms);
+ return -ENOMEM;
+ }
+ trans = trans_alloc(ms, GSM48_PDISC_SMS, transaction_id, new_callref++);
+ if (!trans) {
+ LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n");
+ gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_MO_TEMP_FAIL);
+ sms_free(sms);
+ return -ENOMEM;
+ }
+ gsm411_smc_init(&trans->sms.smc_inst, 0, gsm411_mn_recv,
+ gsm411_mm_send);
+ gsm411_smr_init(&trans->sms.smr_inst, 0, gsm411_rl_recv,
+ gsm411_mn_send);
+ trans->sms.sms = sms;
+ trans->sms.sapi = UM_SAPI_SMS;
+
+ msg = gsm411_msgb_alloc();
+
+ /* no orig Address */
+ data = (uint8_t *)msgb_put(msg, 1);
+ data[0] = 0x00; /* originator length == 0 */
+
+ /* Destination Address */
+ sca[1] = 0x80; /* no extension */
+ sca[1] |= ((sms_sca[0] == '+') ? 0x01 : 0x00) << 4; /* type */
+ sca[1] |= 0x1; /* plan*/
+
+ rc = gsm48_encode_bcd_number(sca, sizeof(sca), 1,
+ sms_sca + (sms_sca[0] == '+'));
+ if (rc < 0) {
+error:
+ gsm411_sms_report(ms, sms, GSM411_RP_CAUSE_SEMANT_INC_MSG);
+ gsm411_trans_free(trans);
+ msgb_free(msg);
+ return rc;
+ }
+ data = msgb_put(msg, rc);
+ memcpy(data, sca, rc);
+
+ /* obtain a pointer for the rp_ud_len, so we can fill it later */
+ rp_ud_len = (uint8_t *)msgb_put(msg, 1);
+
+ /* generate the 03.40 TPDU */
+ rc = gsm340_gen_tpdu(msg, sms);
+ if (rc < 0)
+ goto error;
+ *rp_ud_len = rc;
+
+ LOGP(DLSMS, LOGL_INFO, "TX: SMS DELIVER\n");
+
+ gsm411_push_rp_header(msg, GSM411_MT_RP_DATA_MO, msg_ref);
+ return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_DATA_REQ,
+ msg);
+}
+
+/* create and send SMS */
+int sms_send(struct osmocom_ms *ms, const char *sms_sca, const char *number,
+ const char *text)
+{
+ struct gsm_sms *sms = sms_from_text(number, 0, text);
+
+ if (!sms)
+ return -ENOMEM;
+
+ return gsm411_tx_sms_submit(ms, sms_sca, sms);
+}
+
+/*
+ * message flow between layers
+ */
+
+/* push MMSMS header and send to MM */
+static int gsm411_to_mm(struct msgb *msg, struct gsm_trans *trans,
+ int msg_type)
+{
+ struct gsm48_mmxx_hdr *mmh;
+
+ /* push RR header */
+ msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
+ mmh = (struct gsm48_mmxx_hdr *)msg->data;
+ mmh->msg_type = msg_type;
+ mmh->ref = trans->callref;
+ mmh->transaction_id = trans->transaction_id;
+ mmh->sapi = trans->sms.sapi;
+ mmh->emergency = 0;
+
+ /* send message to MM */
+ LOGP(DLSMS, LOGL_INFO, "Sending '%s' to MM (callref=%x, "
+ "transaction_id=%d, sapi=%d)\n", get_mmxx_name(msg_type),
+ trans->callref, trans->transaction_id, trans->sms.sapi);
+ return gsm48_mmxx_downmsg(trans->ms, msg);
+}
+
+/* mm_send: receive MMSMS sap message from SMC */
+static int gsm411_mm_send(struct gsm411_smc_inst *inst, int msg_type,
+ struct msgb *msg, int cp_msg_type)
+{
+ struct gsm_trans *trans =
+ container_of(inst, struct gsm_trans, sms.smc_inst);
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM411_MMSMS_EST_REQ:
+ gsm411_to_mm(msg, trans, msg_type);
+ break;
+ case GSM411_MMSMS_DATA_REQ:
+ gsm411_push_cp_header(msg, trans->protocol,
+ trans->transaction_id, cp_msg_type);
+ msg->l3h = msg->data;
+ LOGP(DLSMS, LOGL_INFO, "sending CP message (trans=%x)\n",
+ trans->transaction_id);
+ rc = gsm411_to_mm(msg, trans, msg_type);
+ break;
+ case GSM411_MMSMS_REL_REQ:
+ LOGP(DLSMS, LOGL_INFO, "Got MMSMS_REL_REQ, destroying "
+ "transaction.\n");
+ gsm411_to_mm(msg, trans, msg_type);
+ gsm411_trans_free(trans);
+ break;
+ default:
+ msgb_free(msg);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/* mm_send: receive MNSMS sap message from SMR */
+static int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type,
+ struct msgb *msg)
+{
+ struct gsm_trans *trans =
+ container_of(inst, struct gsm_trans, sms.smr_inst);
+
+ /* forward to SMC */
+ return gsm411_smc_send(&trans->sms.smc_inst, msg_type, msg);
+}
+
+/* receive SM-RL sap message from SMR
+ * NOTE: Message is freed by sender
+ */
+static int gsm411_rl_recv(struct gsm411_smr_inst *inst, int msg_type,
+ struct msgb *msg)
+{
+ struct gsm_trans *trans =
+ container_of(inst, struct gsm_trans, sms.smr_inst);
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM411_SM_RL_DATA_IND:
+ rc = gsm411_rx_rl_data(msg, gh, trans);
+ break;
+ case GSM411_SM_RL_REPORT_IND:
+ if (!gh)
+ LOGP(DLSMS, LOGL_INFO, "Release transaction on empty "
+ "report.\n");
+ else {
+ LOGP(DLSMS, LOGL_INFO, "Release transaction on RL "
+ "report.\n");
+ rc = gsm411_rx_rl_report(msg, gh, trans);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/* receive MNSMS sap message from SMC
+ * NOTE: Message is freed by sender
+ */
+static int gsm411_mn_recv(struct gsm411_smc_inst *inst, int msg_type,
+ struct msgb *msg)
+{
+ struct gsm_trans *trans =
+ container_of(inst, struct gsm_trans, sms.smc_inst);
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM411_MNSMS_EST_IND:
+ case GSM411_MNSMS_DATA_IND:
+ LOGP(DLSMS, LOGL_INFO, "MNSMS-DATA/EST-IND\n");
+ rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg);
+ break;
+ case GSM411_MNSMS_ERROR_IND:
+ if (gh)
+ LOGP(DLSMS, LOGL_INFO, "MNSMS-ERROR-IND, cause %d "
+ "(%s)\n", gh->data[0],
+ get_value_string(gsm411_cp_cause_strs,
+ gh->data[0]));
+ else
+ LOGP(DLSMS, LOGL_INFO, "MNSMS-ERROR-IND, no cause\n");
+ rc = gsm411_smr_recv(&trans->sms.smr_inst, msg_type, msg);
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/* receive est/data message from MM layer */
+static int gsm411_mmsms_ind(int mmsms_msg, struct gsm_trans *trans,
+ struct msgb *msg)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ int msg_type = gh->msg_type & 0xbf;
+ uint8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4;
+ /* flip */
+
+ /* pull the MMSMS header */
+ msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
+
+ LOGP(DLSMS, LOGL_INFO, "(ms %s) Received est/data '%u'\n", ms->name,
+ msg_type);
+
+ /* 5.4: For MO, if a CP-DATA is received for a new
+ * transaction, equals reception of an implicit
+ * last CP-ACK for previous transaction */
+ if (trans->sms.smc_inst.cp_state == GSM411_CPS_IDLE
+ && msg_type == GSM411_MT_CP_DATA) {
+ int i;
+ struct gsm_trans *ptrans;
+
+ /* Scan through all remote initiated transactions */
+ for (i=8; i<15; i++) {
+ if (i == transaction_id)
+ continue;
+
+ ptrans = trans_find_by_id(ms, GSM48_PDISC_SMS, i);
+ if (!ptrans)
+ continue;
+
+ LOGP(DLSMS, LOGL_INFO, "Implicit CP-ACK for "
+ "trans_id=%x\n", i);
+
+ /* Finish it for good */
+ gsm411_trans_free(ptrans);
+ }
+ }
+ return gsm411_smc_recv(&trans->sms.smc_inst, mmsms_msg, msg, msg_type);
+}
+
+/* receive message from MM layer */
+int gsm411_rcv_sms(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
+ int msg_type = mmh->msg_type;
+ int sapi = mmh->sapi;
+ struct gsm_trans *trans;
+ int rc = 0;
+
+ trans = trans_find_by_callref(ms, mmh->ref);
+ if (!trans) {
+ LOGP(DLSMS, LOGL_INFO, " -> (new transaction sapi=%d)\n", sapi);
+ trans = trans_alloc(ms, GSM48_PDISC_SMS, mmh->transaction_id,
+ mmh->ref);
+ if (!trans)
+ return -ENOMEM;
+ gsm411_smc_init(&trans->sms.smc_inst, 0, gsm411_mn_recv,
+ gsm411_mm_send);
+ gsm411_smr_init(&trans->sms.smr_inst, 0, gsm411_rl_recv,
+ gsm411_mn_send);
+ trans->sms.sapi = mmh->sapi;
+ }
+
+ LOGP(DLSMS, LOGL_INFO, "(ms %s) Received '%s' from MM\n", ms->name,
+ get_mmxx_name(msg_type));
+
+ switch (msg_type) {
+ case GSM48_MMSMS_EST_CNF:
+ rc = gsm411_smc_recv(&trans->sms.smc_inst, GSM411_MMSMS_EST_CNF,
+ msg, 0);
+ break;
+ case GSM48_MMSMS_EST_IND:
+ case GSM48_MMSMS_DATA_IND:
+ rc = gsm411_mmsms_ind(msg_type, trans, msg);
+ break;
+ case GSM48_MMSMS_REL_IND:
+ case GSM48_MMSMS_ERR_IND:
+ LOGP(DLSMS, LOGL_INFO, "MM connection released.\n");
+ trans_free(trans);
+ break;
+ default:
+ LOGP(DLSMS, LOGL_NOTICE, "Message unhandled.\n");
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}
+
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm480_ss.c b/Src/osmolib/src/host/layer23/src/mobile/gsm480_ss.c
new file mode 100644
index 0000000..fda6288
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm480_ss.c
@@ -0,0 +1,1289 @@
+/*
+ * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/transaction.h>
+#include <osmocom/bb/mobile/gsm480_ss.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/bb/mobile/vty.h>
+#include <osmocom/gsm/protocol/gsm_04_80.h>
+#include <osmocom/gsm/gsm48.h>
+
+static uint32_t new_callref = 0x80000001;
+
+static int gsm480_to_mm(struct msgb *msg, struct gsm_trans *trans,
+ int msg_type);
+static const struct value_string gsm480_err_names[] = {
+ { GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER,
+ "UNKNOWN SUBSCRIBER" },
+ { GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER,
+ "ILLEGAL SUBSCRIBER" },
+ { GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED,
+ "BEARER SERVICE NOT PROVISIONED" },
+ { GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED,
+ "TELESERVICE NOT PROVISIONED" },
+ { GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT,
+ "ILLEGAL EQUIPMENT" },
+ { GSM0480_ERR_CODE_CALL_BARRED,
+ "CALL BARRED" },
+ { GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION,
+ "ILLEGAL SS OPERATION" },
+ { GSM0480_ERR_CODE_SS_ERROR_STATUS,
+ "SS ERROR STATUS" },
+ { GSM0480_ERR_CODE_SS_NOT_AVAILABLE,
+ "SS NOT AVAILABLE" },
+ { GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION,
+ "SS SUBSCRIPTION VIOLATION" },
+ { GSM0480_ERR_CODE_SS_INCOMPATIBILITY,
+ "SS INCOMPATIBILITY" },
+ { GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED,
+ "FACILITY NOT SUPPORTED" },
+ { GSM0480_ERR_CODE_ABSENT_SUBSCRIBER,
+ "ABSENT SUBSCRIBER" },
+ { GSM0480_ERR_CODE_SYSTEM_FAILURE,
+ "SYSTEM FAILURE" },
+ { GSM0480_ERR_CODE_DATA_MISSING,
+ "DATA MISSING" },
+ { GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE,
+ "UNEXPECTED DATA VALUE" },
+ { GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE,
+ "PW REGISTRATION FAILURE" },
+ { GSM0480_ERR_CODE_NEGATIVE_PW_CHECK,
+ "NEGATIVE PW CHECK" },
+ { GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION,
+ "NUM PW ATTEMPTS VIOLATION" },
+ { GSM0480_ERR_CODE_UNKNOWN_ALPHABET,
+ "UNKNOWN ALPHABET" },
+ { GSM0480_ERR_CODE_USSD_BUSY,
+ "USSD BUSY" },
+ { GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS,
+ "MAX MPTY PARTICIPANTS" },
+ { GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE,
+ "RESOURCES NOT AVAILABLE" },
+ {0, NULL }
+};
+
+/* taken from Wireshark */
+static const struct value_string Teleservice_vals[] = {
+ {0x00, "allTeleservices" },
+ {0x10, "allSpeechTransmissionServices" },
+ {0x11, "telephony" },
+ {0x12, "emergencyCalls" },
+ {0x20, "allShortMessageServices" },
+ {0x21, "shortMessageMT-PP" },
+ {0x22, "shortMessageMO-PP" },
+ {0x60, "allFacsimileTransmissionServices" },
+ {0x61, "facsimileGroup3AndAlterSpeech" },
+ {0x62, "automaticFacsimileGroup3" },
+ {0x63, "facsimileGroup4" },
+
+ {0x70, "allDataTeleservices" },
+ {0x80, "allTeleservices-ExeptSMS" },
+
+ {0x90, "allVoiceGroupCallServices" },
+ {0x91, "voiceGroupCall" },
+ {0x92, "voiceBroadcastCall" },
+
+ {0xd0, "allPLMN-specificTS" },
+ {0xd1, "plmn-specificTS-1" },
+ {0xd2, "plmn-specificTS-2" },
+ {0xd3, "plmn-specificTS-3" },
+ {0xd4, "plmn-specificTS-4" },
+ {0xd5, "plmn-specificTS-5" },
+ {0xd6, "plmn-specificTS-6" },
+ {0xd7, "plmn-specificTS-7" },
+ {0xd8, "plmn-specificTS-8" },
+ {0xd9, "plmn-specificTS-9" },
+ {0xda, "plmn-specificTS-A" },
+ {0xdb, "plmn-specificTS-B" },
+ {0xdc, "plmn-specificTS-C" },
+ {0xdd, "plmn-specificTS-D" },
+ {0xde, "plmn-specificTS-E" },
+ {0xdf, "plmn-specificTS-F" },
+ { 0, NULL }
+};
+
+/* taken from Wireshark */
+static const struct value_string Bearerservice_vals[] = {
+ {0x00, "allBearerServices" },
+ {0x10, "allDataCDA-Services" },
+ {0x11, "dataCDA-300bps" },
+ {0x12, "dataCDA-1200bps" },
+ {0x13, "dataCDA-1200-75bps" },
+ {0x14, "dataCDA-2400bps" },
+ {0x15, "dataCDA-4800bps" },
+ {0x16, "dataCDA-9600bps" },
+ {0x17, "general-dataCDA" },
+
+ {0x18, "allDataCDS-Services" },
+ {0x1A, "dataCDS-1200bps" },
+ {0x1C, "dataCDS-2400bps" },
+ {0x1D, "dataCDS-4800bps" },
+ {0x1E, "dataCDS-9600bps" },
+ {0x1F, "general-dataCDS" },
+
+ {0x20, "allPadAccessCA-Services" },
+ {0x21, "padAccessCA-300bps" },
+ {0x22, "padAccessCA-1200bps" },
+ {0x23, "padAccessCA-1200-75bps" },
+ {0x24, "padAccessCA-2400bps" },
+ {0x25, "padAccessCA-4800bps" },
+ {0x26, "padAccessCA-9600bps" },
+ {0x27, "general-padAccessCA" },
+
+ {0x28, "allDataPDS-Services" },
+ {0x2C, "dataPDS-2400bps" },
+ {0x2D, "dataPDS-4800bps" },
+ {0x2E, "dataPDS-9600bps" },
+ {0x2F, "general-dataPDS" },
+
+ {0x30, "allAlternateSpeech-DataCDA" },
+ {0x38, "allAlternateSpeech-DataCDS" },
+ {0x40, "allSpeechFollowedByDataCDA" },
+ {0x48, "allSpeechFollowedByDataCDS" },
+
+ {0x50, "allDataCircuitAsynchronous" },
+ {0x60, "allAsynchronousServices" },
+ {0x58, "allDataCircuitSynchronous" },
+ {0x68, "allSynchronousServices" },
+
+ {0xD0, "allPLMN-specificBS" },
+ {0xD1, "plmn-specificBS-1" },
+ {0xD2, "plmn-specificBS-2" },
+ {0xD3, "plmn-specificBS-3" },
+ {0xD4, "plmn-specificBS-4" },
+ {0xD5, "plmn-specificBS-5" },
+ {0xD6, "plmn-specificBS-6" },
+ {0xD7, "plmn-specificBS-7" },
+ {0xD8, "plmn-specificBS-8" },
+ {0xD9, "plmn-specificBS-9" },
+ {0xDA, "plmn-specificBS-A" },
+ {0xDB, "plmn-specificBS-B" },
+ {0xDC, "plmn-specificBS-C" },
+ {0xDD, "plmn-specificBS-D" },
+ {0xDE, "plmn-specificBS-E" },
+ {0xDF, "plmn-specificBS-F" },
+ { 0, NULL }
+};
+
+static int gsm480_ss_result(struct osmocom_ms *ms, const char *response,
+ uint8_t error)
+{
+ vty_notify(ms, NULL);
+ if (response) {
+ char text[256], *t = text, *s;
+
+ strncpy(text, response, sizeof(text) - 1);
+ text[sizeof(text) - 1] = '\0';
+ while ((s = strchr(text, '\r')))
+ *s = '\n';
+ while ((s = strsep(&t, "\n"))) {
+ vty_notify(ms, "Service response: %s\n", s);
+ }
+ } else if (error)
+ vty_notify(ms, "Service request failed: %s\n",
+ get_value_string(gsm480_err_names, error));
+ else
+ vty_notify(ms, "Service request failed.\n");
+
+ return 0;
+}
+
+enum {
+ GSM480_SS_ST_IDLE = 0,
+ GSM480_SS_ST_REGISTER,
+ GSM480_SS_ST_ACTIVE,
+};
+
+/*
+ * init / exit
+ */
+
+int gsm480_ss_init(struct osmocom_ms *ms)
+{
+ LOGP(DSS, LOGL_INFO, "init SS\n");
+
+ return 0;
+}
+
+int gsm480_ss_exit(struct osmocom_ms *ms)
+{
+ struct gsm_trans *trans, *trans2;
+
+ LOGP(DSS, LOGL_INFO, "exit SS processes for %s\n", ms->name);
+
+ llist_for_each_entry_safe(trans, trans2, &ms->trans_list, entry) {
+ if (trans->protocol == GSM48_PDISC_NC_SS) {
+ LOGP(DSS, LOGL_NOTICE, "Free pendig "
+ "SS-transaction.\n");
+ trans_free(trans);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * transaction
+ */
+
+/* SS Specific transaction release.
+ * gets called by trans_free, DO NOT CALL YOURSELF!
+ */
+void _gsm480_ss_trans_free(struct gsm_trans *trans)
+{
+ if (trans->ss.msg) {
+ LOGP(DSS, LOGL_INFO, "Free pending SS request\n");
+ msgb_free(trans->ss.msg);
+ trans->ss.msg = NULL;
+ }
+ vty_notify(trans->ms, NULL);
+ vty_notify(trans->ms, "Service connection terminated.\n");
+}
+
+/* release MM connection, free transaction */
+static int gsm480_trans_free(struct gsm_trans *trans)
+{
+ struct msgb *nmsg;
+
+ /* release MM connection */
+ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_REQ, trans->callref,
+ trans->transaction_id, 0);
+ if (!nmsg)
+ return -ENOMEM;
+ LOGP(DSS, LOGL_INFO, "Sending MMSS_REL_REQ\n");
+ gsm48_mmxx_downmsg(trans->ms, nmsg);
+
+ trans->callref = 0;
+ trans_free(trans);
+
+ return 0;
+}
+
+/*
+ * endcoding
+ */
+
+#define GSM480_ALLOC_SIZE 512+128
+#define GSM480_ALLOC_HEADROOM 128
+
+struct msgb *gsm480_msgb_alloc(void)
+{
+ return msgb_alloc_headroom(GSM480_ALLOC_SIZE, GSM480_ALLOC_HEADROOM,
+ "GSM 04.80");
+}
+
+static inline unsigned char *msgb_wrap_with_L(struct msgb *msgb)
+{
+ uint8_t *data = msgb_push(msgb, 1);
+
+ data[0] = msgb->len - 1;
+ return data;
+}
+
+/* support function taken from OpenBSC */
+static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
+{
+ uint8_t *data = msgb_push(msgb, 2);
+
+ data[0] = tag;
+ data[1] = msgb->len - 2;
+ return data;
+}
+
+static inline void msgb_wrap_with_TL_asn(struct msgb *msg, uint8_t tag)
+{
+ int len = msg->len;
+ uint8_t *data = msgb_push(msg, (len >= 128) ? 3 : 2);
+
+ *data++ = tag;
+ if (len >= 128)
+ *data++ = 0x81;
+ *data = len;
+ return;
+}
+
+/* support function taken from OpenBSC */
+static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
+uint8_t value)
+{
+ uint8_t *data = msgb_push(msgb, 3);
+
+ data[0] = tag;
+ data[1] = 1;
+ data[2] = value;
+ return data;
+}
+
+static const char *ss_code_by_char(const char *code, uint8_t *ss_code)
+{
+ if (!strncmp(code, "21", 2)) {
+ *ss_code = 33;
+ return code + 2;
+ }
+ if (!strncmp(code, "67", 2)) {
+ *ss_code = 41;
+ return code + 2;
+ }
+ if (!strncmp(code, "61", 2)) {
+ *ss_code = 42;
+ return code + 2;
+ }
+ if (!strncmp(code, "62", 2)) {
+ *ss_code = 43;
+ return code + 2;
+ }
+ if (!strncmp(code, "002", 3)) {
+ *ss_code = 32;
+ return code + 3;
+ }
+ if (!strncmp(code, "004", 3)) {
+ *ss_code = 40;
+ return code + 3;
+ }
+
+ return NULL;
+}
+
+static const char *decode_ss_code(uint8_t ss_code)
+{
+ static char unknown[16];
+
+ switch (ss_code) {
+ case 33:
+ return "CFU";
+ case 41:
+ return "CFB";
+ case 42:
+ return "CFNR";
+ case 43:
+ return "CF Not Reachable";
+ case 32:
+ return "All CF";
+ case 40:
+ return "All conditional CF";
+ default:
+ sprintf(unknown, "Unknown %d", ss_code);
+ return unknown;
+ }
+}
+
+static int gsm480_tx_release_compl(struct gsm_trans *trans, uint8_t cause)
+{
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+
+ msg = gsm480_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ gh->proto_discr = GSM48_PDISC_NC_SS | (trans->transaction_id << 4);
+ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
+
+ if (cause) {
+ uint8_t *tlv = msgb_put(msg, 4);
+ *tlv = GSM48_IE_CAUSE;
+ *tlv = 2;
+ *tlv = 0x80 | cause;
+ *tlv = 0x80 | GSM48_CAUSE_LOC_USER;
+ }
+ return gsm480_to_mm(msg, trans, GSM48_MMSS_DATA_REQ);
+}
+
+static int return_imei(struct osmocom_ms *ms)
+{
+ char text[32];
+ struct gsm_settings *set = &ms->settings;
+
+ sprintf(text, "IMEI: %s SV: %s", set->imei,
+ set->imeisv + strlen(set->imei));
+ gsm480_ss_result(ms, text, 0);
+
+ return 0;
+}
+
+/* prepend invoke-id, facility IE and facility message */
+static int gsm480_tx_invoke(struct gsm_trans *trans, struct msgb *msg,
+ uint8_t msg_type)
+{
+ struct gsm48_hdr *gh;
+
+ /* Pre-pend the invoke ID */
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, trans->ss.invoke_id);
+
+ /* Wrap this up as invoke vomponent */
+ if (msg_type == GSM0480_MTYPE_FACILITY)
+ msgb_wrap_with_TL_asn(msg, GSM0480_CTYPE_RETURN_RESULT);
+ else
+ msgb_wrap_with_TL_asn(msg, GSM0480_CTYPE_INVOKE);
+
+ /* Wrap this up as facility IE */
+ if (msg_type == GSM0480_MTYPE_FACILITY)
+ msgb_wrap_with_L(msg);
+ else
+ msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
+
+ /* FIXME: If phase 2, we need SSVERSION to be added */
+
+ /* Push L3 header */
+ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+ gh->proto_discr = GSM48_PDISC_NC_SS | (trans->transaction_id << 4);
+ gh->msg_type = msg_type;
+
+ if (msg_type == GSM0480_MTYPE_FACILITY) {
+ /* directly transmit data on established connection */
+ return gsm480_to_mm(msg, trans, GSM48_MMSS_DATA_REQ);
+ } else {
+ /* store header until our MM connection is established */
+ trans->ss.msg = msg;
+
+ /* request establishment */
+ msg = gsm480_msgb_alloc();
+ if (!msg) {
+ trans_free(trans);
+ return -ENOMEM;
+ }
+ return gsm480_to_mm(msg, trans, GSM48_MMSS_EST_REQ);
+ }
+}
+
+static int gsm480_tx_cf(struct gsm_trans *trans, uint8_t msg_type,
+ uint8_t op_code, uint8_t ss_code, const char *dest)
+{
+ struct msgb *msg;
+
+ /* allocate message */
+ msg = gsm480_msgb_alloc();
+ if (!msg) {
+ trans_free(trans);
+ return -ENOMEM;
+ }
+
+ if (dest) {
+ uint8_t tlv[32];
+ int rc;
+
+ /* Forwarding To address */
+ tlv[0] = 0x84;
+ tlv[2] = 0x80; /* no extension */
+ tlv[2] |= ((dest[0] == '+') ? 0x01 : 0x00) << 4; /* type */
+ tlv[2] |= 0x1; /* plan*/
+ rc = gsm48_encode_bcd_number(tlv + 1, sizeof(tlv) - 1, 1,
+ dest + (dest[0] == '+'));
+ if (rc < 0) {
+ msgb_free(msg);
+ trans_free(trans);
+ return -EINVAL;
+ }
+ memcpy(msgb_put(msg, rc + 1), tlv, rc + 1);
+ }
+
+ /* Encode ss-Code */
+ msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, ss_code);
+
+ /* Then wrap these as a Sequence */
+ msgb_wrap_with_TL_asn(msg, GSM_0480_SEQUENCE_TAG);
+
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, op_code);
+
+ return gsm480_tx_invoke(trans, msg, msg_type);
+}
+
+static int gsm480_tx_ussd(struct gsm_trans *trans, uint8_t msg_type,
+ const char *text)
+{
+ struct msgb *msg;
+ int length;
+
+ /* allocate message */
+ msg = gsm480_msgb_alloc();
+ if (!msg) {
+ trans_free(trans);
+ return -ENOMEM;
+ }
+
+ /* Encode service request */
+ length = gsm_7bit_encode(msg->data, text);
+ msgb_put(msg, length);
+
+ /* Then wrap it as an Octet String */
+ msgb_wrap_with_TL_asn(msg, ASN1_OCTET_STRING_TAG);
+
+ /* Pre-pend the DCS octet string */
+ msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F);
+
+ /* Then wrap these as a Sequence */
+ msgb_wrap_with_TL_asn(msg, GSM_0480_SEQUENCE_TAG);
+
+ if (msg_type == GSM0480_MTYPE_FACILITY) {
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
+ GSM0480_OP_CODE_USS_REQUEST);
+
+ /* Then wrap these as a Sequence */
+ msgb_wrap_with_TL_asn(msg, GSM_0480_SEQUENCE_TAG);
+ } else {
+ /* Pre-pend the operation code */
+ msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
+ GSM0480_OP_CODE_PROCESS_USS_REQ);
+ }
+
+ return gsm480_tx_invoke(trans, msg, msg_type);
+}
+
+/* create and send service code */
+int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
+{
+ struct gsm_trans *trans = NULL, *transt;
+ uint8_t transaction_id;
+
+ /* look for an old transaction */
+ if (!new_trans) {
+ llist_for_each_entry(transt, &ms->trans_list, entry) {
+ if (transt->protocol == GSM48_PDISC_NC_SS) {
+ trans = transt;
+ break;
+ }
+ }
+ }
+
+ /* if there is an old transaction, check if we can send data */
+ if (trans) {
+ if (trans->ss.state != GSM480_SS_ST_ACTIVE) {
+ LOGP(DSS, LOGL_INFO, "Pending trans not active.\n");
+ gsm480_ss_result(trans->ms, "Current service pending",
+ 0);
+ return 0;
+ }
+ if (!strcmp(code, "hangup")) {
+ gsm480_tx_release_compl(trans, 0);
+ gsm480_trans_free(trans);
+ return 0;
+ }
+ LOGP(DSS, LOGL_INFO, "Existing transaction.\n");
+ return gsm480_tx_ussd(trans, GSM0480_MTYPE_FACILITY, code);
+ }
+
+ /* do nothing, if hangup is received */
+ if (!strcmp(code, "hangup"))
+ return 0;
+
+ /* internal codes */
+ if (!strcmp(code, "*#06#")) {
+ return return_imei(ms);
+ }
+
+ /* no running, no transaction */
+ if (!ms->started || ms->shutdown) {
+ gsm480_ss_result(ms, "<phone is down>", 0);
+ return -EIO;
+ }
+
+ /* allocate transaction with dummy reference */
+ transaction_id = trans_assign_trans_id(ms, GSM48_PDISC_NC_SS,
+ 0);
+ if (transaction_id < 0) {
+ LOGP(DSS, LOGL_ERROR, "No transaction ID available\n");
+ gsm480_ss_result(ms, NULL,
+ GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE);
+ return -ENOMEM;
+ }
+ trans = trans_alloc(ms, GSM48_PDISC_NC_SS, transaction_id,
+ new_callref++);
+ if (!trans) {
+ LOGP(DSS, LOGL_ERROR, "No memory for trans\n");
+ gsm480_ss_result(ms, NULL,
+ GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE);
+ return -ENOMEM;
+ }
+
+ /* go register sent state */
+ trans->ss.state = GSM480_SS_ST_REGISTER;
+
+ /* FIXME: generate invoke ID */
+ trans->ss.invoke_id = 5;
+
+ /* interrogate */
+ if (code[0] == '*' && code[1] == '#' && code[strlen(code) - 1] == '#') {
+ uint8_t ss_code = 0;
+
+ ss_code_by_char(code + 2, &ss_code);
+ if (code)
+ return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
+ GSM0480_OP_CODE_INTERROGATE_SS, ss_code, NULL);
+ } else
+ /* register / activate */
+ if (code[0] == '*' && code[strlen(code) - 1] == '#') {
+ uint8_t ss_code = 0;
+ const char *to;
+ char dest[32];
+
+ /* double star */
+ if (code[1] == '*')
+ code++;
+
+ to = ss_code_by_char(code + 1, &ss_code);
+
+ /* register */
+ if (code && to && to[0] == '*') {
+ strncpy(dest, to + 1, sizeof(dest) - 1);
+ dest[sizeof(dest) - 1] = '\0';
+ dest[strlen(dest) - 1] = '\0';
+ return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
+ GSM0480_OP_CODE_REGISTER_SS, ss_code, dest);
+ }
+ /* activate */
+ if (code && to && to[0] == '#') {
+ return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
+ GSM0480_OP_CODE_ACTIVATE_SS, ss_code, NULL);
+ }
+ } else
+ /* erasure */
+ if (code[0] == '#' && code[1] == '#' && code[strlen(code) - 1] == '#') {
+ uint8_t ss_code = 0;
+
+ ss_code_by_char(code + 2, &ss_code);
+
+ if (code)
+ return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
+ GSM0480_OP_CODE_ERASE_SS, ss_code, NULL);
+ } else
+ /* deactivate */
+ if (code[0] == '#' && code[strlen(code) - 1] == '#') {
+ uint8_t ss_code = 0;
+
+ ss_code_by_char(code + 1, &ss_code);
+
+ if (code)
+ return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
+ GSM0480_OP_CODE_DEACTIVATE_SS, ss_code, NULL);
+ }
+
+ /* other codes */
+ return gsm480_tx_ussd(trans, GSM0480_MTYPE_REGISTER, code);
+}
+
+/*
+ * decoding
+ */
+
+static int parse_tag_asn1(const uint8_t *data, int len,
+ const uint8_t **tag_data, int *tag_len)
+{
+ /* at least 2 bytes (tag + len) */
+ if (len < 2)
+ return -1;
+
+ /* extended length */
+ if (data[1] == 0x81) {
+ /* at least 2 bytes (tag + 0x81 + len) */
+ if (len < 3)
+ return -1;
+ *tag_len = data[2];
+ *tag_data = data + 3;
+ len -= 3;
+ } else {
+ *tag_len = data[1];
+ *tag_data = data + 2;
+ len -= 2;
+ }
+
+ /* check for buffer overflow */
+ if (len < *tag_len)
+ return -1;
+
+ /* return length */
+ return len;
+}
+
+static int gsm480_rx_ussd(struct gsm_trans *trans, const uint8_t *data,
+ int len)
+{
+ int num_chars;
+ char text[256];
+ int i;
+ const uint8_t *tag_data;
+ int tag_len;
+
+ /* sequence tag */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "2. Sequence tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM_0480_SEQUENCE_TAG) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting 2. Sequence Tag\n");
+ return -EINVAL;
+ }
+ len = tag_len;
+ data = tag_data;
+
+ /* DSC */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 1) {
+ LOGP(DSS, LOGL_NOTICE, "DSC tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != ASN1_OCTET_STRING_TAG || tag_len != 1) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting DSC tag\n");
+ return -EINVAL;
+ }
+ if (tag_data[0] != 0x0f) {
+ LOGP(DSS, LOGL_NOTICE, "DSC not 0x0f\n");
+ return -EINVAL;
+ }
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+
+ /* text */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Text tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != ASN1_OCTET_STRING_TAG) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting text tag\n");
+ return -EINVAL;
+ }
+ num_chars = tag_len * 8 / 7;
+ /* Prevent a mobile-originated buffer-overrun! */
+ if (num_chars > sizeof(text) - 1)
+ num_chars = sizeof(text) - 1;
+ text[sizeof(text) - 1] = '\0';
+ gsm_7bit_decode(text, tag_data, num_chars);
+
+ for (i = 0; text[i]; i++) {
+ if (text[i] == '\r')
+ text[i] = '\n';
+ }
+ /* remove last CR, if exists */
+ if (text[0] && text[strlen(text) - 1] == '\n')
+ text[strlen(text) - 1] = '\0';
+ gsm480_ss_result(trans->ms, text, 0);
+
+ return 0;
+}
+
+static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
+ int len)
+{
+ struct osmocom_ms *ms = trans->ms;
+ const uint8_t *tag_data, *data2;
+ int tag_len, len2;
+ char number[32];
+
+ LOGP(DSS, LOGL_INFO, "call forwarding reply: len %d data %s\n", len,
+ osmo_hexdump(data, len));
+
+ vty_notify(ms, NULL);
+
+ /* forwarding feature list */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] == 0x80) {
+ if ((tag_data[0] & 0x01))
+ vty_notify(ms, "Status: activated\n");
+ else
+ vty_notify(ms, "Status: deactivated\n");
+ return 0;
+ }
+
+ switch(data[0]) {
+ case 0xa3:
+ len = tag_len;
+ data = tag_data;
+ break;
+ case 0xa0: /* forwarding info */
+ len = tag_len;
+ data = tag_data;
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 1) {
+ LOGP(DSS, LOGL_NOTICE, "Tag too short\n");
+ return -EINVAL;
+ }
+ /* check for SS code */
+ if (data[0] != 0x04)
+ break;
+ vty_notify(ms, "Reply for %s\n", decode_ss_code(tag_data[0]));
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+ /* sequence tag */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM_0480_SEQUENCE_TAG) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting sequence tag\n");
+ return -EINVAL;
+ }
+ len = tag_len;
+ data = tag_data;
+ break;
+ default:
+ vty_notify(ms, "Call Forwarding reply unsupported.\n");
+ return 0;
+ }
+
+ while (len) {
+ /* sequence tag */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM_0480_SEQUENCE_TAG) {
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+ LOGP(DSS, LOGL_NOTICE, "Skipping tag 0x%x\n", data[0]);
+ continue;
+ }
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+ len2 = tag_len;
+ data2 = tag_data;
+
+ while (len2) {
+ /* tags in sequence */
+ if (parse_tag_asn1(data2, len2, &tag_data, &tag_len)
+ < 1) {
+ LOGP(DSS, LOGL_NOTICE, "Tag too short\n");
+ return -EINVAL;
+ }
+ LOGP(DSS, LOGL_INFO, "Tag: len %d data %s\n", tag_len,
+ osmo_hexdump(tag_data, tag_len));
+ switch (data2[0]) {
+ case 0x82:
+ vty_notify(ms, "Bearer Service: %s\n",
+ get_value_string(Bearerservice_vals,
+ tag_data[0]));
+ break;
+ case 0x83:
+ vty_notify(ms, "Teleservice: %s\n",
+ get_value_string(Teleservice_vals,
+ tag_data[0]));
+ break;
+ case 0x84:
+ if ((tag_data[0] & 0x01))
+ vty_notify(ms, "Status: activated\n");
+ else
+ vty_notify(ms, "Status: deactivated\n");
+ break;
+ case 0x85:
+ if (((tag_data[0] & 0x70) >> 4) == 1)
+ strcpy(number, "+");
+ else if (((tag_data[0] & 0x70) >> 4) == 1)
+ strcpy(number, "+");
+ else
+ number[0] = '\0';
+ gsm48_decode_bcd_number(number + strlen(number),
+ sizeof(number) - strlen(number),
+ tag_data - 1, 1);
+ vty_notify(ms, "Destination: %s\n", number);
+ break;
+ }
+ len2 -= tag_data - data2 + tag_len;
+ data2 = tag_data + tag_len;
+ }
+ }
+
+ return 0;
+}
+
+static int gsm480_rx_result(struct gsm_trans *trans, const uint8_t *data,
+ int len, int msg_type)
+{
+ const uint8_t *tag_data;
+ int tag_len;
+ int rc = 0;
+
+ LOGP(DSS, LOGL_INFO, "Result received (len %d)\n", len);
+
+ if (len && data[0] == 0x8d) {
+ LOGP(DSS, LOGL_NOTICE, "Skipping mysterious 0x8d\n");
+ len--;
+ data++;
+ }
+
+ /* invoke ID */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 1) {
+ LOGP(DSS, LOGL_NOTICE, "Invoke ID too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM0480_COMPIDTAG_INVOKE_ID || tag_len != 1) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting invoke ID\n");
+ return -EINVAL;
+ }
+
+ if (msg_type == GSM0480_CTYPE_RETURN_RESULT) {
+ if (trans->ss.invoke_id != data[2]) {
+ LOGP(DSS, LOGL_NOTICE, "Invoke ID mismatch\n");
+ }
+ }
+ /* Store invoke ID, in case we wan't to send a result. */
+ trans->ss.invoke_id = tag_data[0];
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+
+ if (!len) {
+ gsm480_ss_result(trans->ms, "<no result>", 0);
+ return 0;
+ }
+
+ /* sequence tag */
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Sequence tag too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM_0480_SEQUENCE_TAG) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting Sequence Tag, trying "
+ "Operation Tag\n");
+ goto operation;
+ }
+ len = tag_len;
+ data = tag_data;
+
+ /* operation */
+operation:
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 1) {
+ LOGP(DSS, LOGL_NOTICE, "Operation too short\n");
+ return -EINVAL;
+ }
+ if (data[0] != GSM0480_OPERATION_CODE || tag_len != 1) {
+ LOGP(DSS, LOGL_NOTICE, "Expecting Operation Code\n");
+ return -EINVAL;
+ }
+ len -= tag_data - data + tag_len;
+ data = tag_data + tag_len;
+
+ switch (tag_data[0]) {
+ case GSM0480_OP_CODE_PROCESS_USS_REQ:
+ case GSM0480_OP_CODE_USS_REQUEST:
+ rc = gsm480_rx_ussd(trans, data, len);
+ break;
+ case GSM0480_OP_CODE_INTERROGATE_SS:
+ case GSM0480_OP_CODE_REGISTER_SS:
+ case GSM0480_OP_CODE_ACTIVATE_SS:
+ case GSM0480_OP_CODE_DEACTIVATE_SS:
+ case GSM0480_OP_CODE_ERASE_SS:
+ rc = gsm480_rx_cf(trans, data, len);
+ break;
+ default:
+ LOGP(DSS, LOGL_NOTICE, "Operation code not USS\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/* facility from BSC */
+static int gsm480_rx_fac_ie(struct gsm_trans *trans, const uint8_t *data,
+ int len)
+{
+ int rc = 0;
+ const uint8_t *tag_data;
+ int tag_len;
+
+ LOGP(DSS, LOGL_INFO, "Facility received (len %d)\n", len);
+
+ if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
+ LOGP(DSS, LOGL_NOTICE, "Facility too short\n");
+ return -EINVAL;
+ }
+
+ switch (data[0]) {
+ case GSM0480_CTYPE_INVOKE:
+ case GSM0480_CTYPE_RETURN_RESULT:
+ rc = gsm480_rx_result(trans, tag_data, tag_len, data[0]);
+ break;
+ case GSM0480_CTYPE_RETURN_ERROR:
+ // FIXME: return error code
+ gsm480_ss_result(trans->ms, "<error received>", 0);
+ break;
+ case GSM0480_CTYPE_REJECT:
+ gsm480_ss_result(trans->ms, "<service rejected>", 0);
+ break;
+ default:
+ LOGP(DSS, LOGL_NOTICE, "CTYPE unknown\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int gsm480_rx_cause_ie(struct gsm_trans *trans, const uint8_t *data,
+ int len)
+{
+ uint8_t value;
+
+ LOGP(DSS, LOGL_INFO, "Cause received (len %d)\n", len);
+
+ if (len < 2) {
+ LOGP(DSS, LOGL_NOTICE, "Cause too short\n");
+ return -EINVAL;
+ }
+ if (!(data[1] & 0x80)) {
+ if (len < 3) {
+ LOGP(DSS, LOGL_NOTICE, "Cause too short\n");
+ return -EINVAL;
+ }
+ value = data[3] & 0x7f;
+ } else
+ value = data[2] & 0x7f;
+
+ LOGP(DSS, LOGL_INFO, "Received Cause %d\n", value);
+
+ /* this is an error */
+ return -EINVAL;
+}
+
+/* release complete from BSC */
+static int gsm480_rx_release_comp(struct gsm_trans *trans, struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
+ struct tlv_parsed tp;
+ int rc = 0;
+
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
+ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
+ rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
+ *(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
+ } else {
+ /* facility optional */
+ LOGP(DSS, LOGL_INFO, "No facility IE received\n");
+ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
+ rc = gsm480_rx_cause_ie(trans,
+ TLVP_VAL(&tp, GSM48_IE_CAUSE),
+ *(TLVP_VAL(&tp, GSM48_IE_CAUSE)-1));
+ }
+ }
+
+ if (rc < 0)
+ gsm480_ss_result(trans->ms, NULL, 0);
+ if (rc > 0)
+ gsm480_ss_result(trans->ms, NULL, rc);
+
+ /* remote releases */
+ gsm480_trans_free(trans);
+
+ return rc;
+}
+
+/* facility from BSC */
+static int gsm480_rx_facility(struct gsm_trans *trans, struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
+ struct tlv_parsed tp;
+ int rc = 0;
+
+ /* go register state */
+ trans->ss.state = GSM480_SS_ST_ACTIVE;
+
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len,
+ GSM48_IE_FACILITY, 0);
+ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
+ rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
+ *(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
+ } else {
+ LOGP(DSS, LOGL_INFO, "No facility IE received\n");
+ /* release 3.7.5 */
+ gsm480_tx_release_compl(trans, 96);
+ /* local releases */
+ gsm480_trans_free(trans);
+ }
+
+ if (rc < 0)
+ gsm480_ss_result(trans->ms, NULL, 0);
+ if (rc > 0)
+ gsm480_ss_result(trans->ms, NULL, rc);
+
+ return rc;
+}
+
+/* regisster from BSC */
+static int gsm480_rx_register(struct gsm_trans *trans, struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
+ struct tlv_parsed tp;
+ int rc = 0;
+
+ /* go register state */
+ trans->ss.state = GSM480_SS_ST_ACTIVE;
+
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
+ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
+ rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
+ *(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
+ } else {
+ /* facility optional */
+ LOGP(DSS, LOGL_INFO, "No facility IE received\n");
+ /* release 3.7.5 */
+ gsm480_tx_release_compl(trans, 96);
+ /* local releases */
+ gsm480_trans_free(trans);
+ }
+
+ if (rc < 0)
+ gsm480_ss_result(trans->ms, NULL, 0);
+ if (rc > 0)
+ gsm480_ss_result(trans->ms, NULL, rc);
+
+ return rc;
+}
+
+/*
+ * message handling
+ */
+
+/* push MMSS header and send to MM */
+static int gsm480_to_mm(struct msgb *msg, struct gsm_trans *trans,
+ int msg_type)
+{
+ struct gsm48_mmxx_hdr *mmh;
+
+ /* set l3H */
+ msg->l3h = msg->data;
+
+ /* push RR header */
+ msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
+ mmh = (struct gsm48_mmxx_hdr *)msg->data;
+ mmh->msg_type = msg_type;
+ mmh->ref = trans->callref;
+ mmh->transaction_id = trans->transaction_id;
+ mmh->sapi = 0;
+ mmh->emergency = 0;
+
+ /* send message to MM */
+ LOGP(DSS, LOGL_INFO, "Sending '%s' to MM (callref=%x, "
+ "transaction_id=%d)\n", get_mmxx_name(msg_type), trans->callref,
+ trans->transaction_id);
+ return gsm48_mmxx_downmsg(trans->ms, msg);
+}
+
+/* receive est confirm from MM layer */
+static int gsm480_mmss_est(int mmss_msg, struct gsm_trans *trans,
+ struct msgb *msg)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct msgb *temp;
+
+ LOGP(DSS, LOGL_INFO, "(ms %s) Received confirm, sending pending SS\n",
+ ms->name);
+
+ /* remove transaction, if no SS message */
+ if (!trans->ss.msg) {
+ LOGP(DSS, LOGL_ERROR, "(ms %s) No pending SS!\n", ms->name);
+ gsm480_trans_free(trans);
+ return -EINVAL;
+ }
+
+ /* detach message and then send */
+ temp = trans->ss.msg;
+ trans->ss.msg = NULL;
+ return gsm480_to_mm(temp, trans, GSM48_MMSS_DATA_REQ);
+}
+
+/* receive data indication from MM layer */
+static int gsm480_mmss_ind(int mmss_msg, struct gsm_trans *trans,
+ struct msgb *msg)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ int msg_type = gh->msg_type & 0xbf;
+ int rc = 0;
+
+ /* pull the MMSS header */
+ msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
+
+ LOGP(DSS, LOGL_INFO, "(ms %s) Received est/data '%u'\n", ms->name,
+ msg_type);
+
+ switch (msg_type) {
+ case GSM0480_MTYPE_RELEASE_COMPLETE:
+ rc = gsm480_rx_release_comp(trans, msg);
+ break;
+ case GSM0480_MTYPE_FACILITY:
+ rc = gsm480_rx_facility(trans, msg);
+ break;
+ case GSM0480_MTYPE_REGISTER:
+ rc = gsm480_rx_register(trans, msg);
+ break;
+ default:
+ LOGP(DSS, LOGL_NOTICE, "Message unhandled.\n");
+ /* release 3.7.4 */
+ gsm480_tx_release_compl(trans, 97);
+ gsm480_trans_free(trans);
+ rc = -ENOTSUP;
+ }
+ return 0;
+}
+
+/* receive message from MM layer */
+int gsm480_rcv_ss(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
+ int msg_type = mmh->msg_type;
+ struct gsm_trans *trans;
+ int rc = 0;
+
+ trans = trans_find_by_callref(ms, mmh->ref);
+ if (!trans) {
+ LOGP(DSS, LOGL_INFO, " -> (new transaction)\n");
+ trans = trans_alloc(ms, GSM48_PDISC_NC_SS, mmh->transaction_id,
+ mmh->ref);
+ if (!trans)
+ return -ENOMEM;
+ }
+
+ LOGP(DSS, LOGL_INFO, "(ms %s) Received '%s' from MM\n", ms->name,
+ get_mmxx_name(msg_type));
+
+ switch (msg_type) {
+ case GSM48_MMSS_EST_CNF:
+ rc = gsm480_mmss_est(msg_type, trans, msg);
+ break;
+ case GSM48_MMSS_EST_IND:
+ case GSM48_MMSS_DATA_IND:
+ rc = gsm480_mmss_ind(msg_type, trans, msg);
+ break;
+ case GSM48_MMSS_REL_IND:
+ case GSM48_MMSS_ERR_IND:
+ LOGP(DSS, LOGL_INFO, "MM connection released.\n");
+ trans_free(trans);
+ break;
+ default:
+ LOGP(DSS, LOGL_NOTICE, "Message unhandled.\n");
+ rc = -ENOTSUP;
+ }
+
+ return rc;
+}
+
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm48_cc.c b/Src/osmolib/src/host/layer23/src/mobile/gsm48_cc.c
index 2e97819..38dfab0 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/gsm48_cc.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm48_cc.c
@@ -43,7 +43,7 @@ extern void *l23_ctx;
static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg);
static int gsm48_rel_null_free(struct gsm_trans *trans);
int mncc_release_ind(struct osmocom_ms *ms, struct gsm_trans *trans,
- u_int32_t callref, int location, int value);
+ uint32_t callref, int location, int value);
static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg);
@@ -173,6 +173,7 @@ static int gsm48_cc_to_mm(struct msgb *msg, struct gsm_trans *trans,
mmh->msg_type = msg_type;
mmh->ref = trans->callref;
mmh->transaction_id = trans->transaction_id;
+ mmh->sapi = 0;
mmh->emergency = emergency;
/* send message to MM */
@@ -215,7 +216,7 @@ int mncc_dequeue(struct osmocom_ms *ms)
struct gsm_mncc *mncc;
struct msgb *msg;
int work = 0;
-
+
while ((msg = msgb_dequeue(&cc->mncc_upqueue))) {
mncc = (struct gsm_mncc *)msg->data;
if (ms->mncc_entity.mncc_recv)
@@ -223,7 +224,7 @@ int mncc_dequeue(struct osmocom_ms *ms)
work = 1; /* work done */
msgb_free(msg);
}
-
+
return work;
}
@@ -392,7 +393,7 @@ static int gsm48_rel_null_free(struct gsm_trans *trans)
/* release MM connection */
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref,
- trans->transaction_id);
+ trans->transaction_id, 0);
if (!nmsg)
return -ENOMEM;
LOGP(DCC, LOGL_INFO, "Sending MMCC_REL_REQ\n");
@@ -416,7 +417,7 @@ void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
/* send release indication to upper layer */
int mncc_release_ind(struct osmocom_ms *ms, struct gsm_trans *trans,
- u_int32_t callref, int location, int value)
+ uint32_t callref, int location, int value)
{
struct gsm_mncc rel;
@@ -497,7 +498,7 @@ static int gsm48_cc_init_mm(struct gsm_trans *trans, void *arg)
/* establish MM connection */
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_REQ, trans->callref,
- trans->transaction_id);
+ trans->transaction_id, 0);
if (!nmsg)
return -ENOMEM;
nmmh = (struct gsm48_mmxx_hdr *) nmsg->data;
@@ -514,7 +515,7 @@ static int gsm48_cc_abort_mm(struct gsm_trans *trans, void *arg)
/* abort MM connection */
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref,
- trans->transaction_id);
+ trans->transaction_id, 0);
if (!nmsg)
return -ENOMEM;
LOGP(DCC, LOGL_INFO, "Sending MMCC_REL_REQ\n");
@@ -556,7 +557,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans)
trans_free(trans);
return rc;
}
-
+
/* Get free transaction_id */
transaction_id = trans_assign_trans_id(trans->ms, GSM48_PDISC_CC, 0);
if (transaction_id < 0) {
@@ -712,7 +713,7 @@ static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct tlv_parsed tp;
struct gsm_mncc alerting;
-
+
LOGP(DCC, LOGL_INFO, "received ALERTING\n");
gsm48_stop_cc_timer(trans);
@@ -945,7 +946,7 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
gsm48_encode_ssversion(nmsg, &alerting->ssversion);
new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
-
+
return gsm48_cc_to_mm(nmsg, trans, GSM48_MMCC_DATA_REQ);
}
@@ -993,7 +994,7 @@ static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
gsm48_stop_cc_timer(trans);
new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
+
memset(&connect_ack, 0, sizeof(struct gsm_mncc));
connect_ack.callref = trans->callref;
return mncc_recvmsg(trans->ms, trans, MNCC_SETUP_COMPL_IND,
@@ -1846,7 +1847,7 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
/* state trasitions for MNCC messages (upper layer) */
static struct downstate {
- u_int32_t states;
+ uint32_t states;
int type;
int (*rout) (struct gsm_trans *trans, void *arg);
} downstatelist[] = {
@@ -1991,12 +1992,12 @@ int mncc_tx_to_cc(void *inst, int msg_type, void *arg)
if ((msg_type == downstatelist[i].type)
&& ((1 << trans->cc.state) & downstatelist[i].states))
break;
- if (i == DOWNSLLEN) {
- LOGP(DCC, LOGL_NOTICE, "Message %d unhandled at state "
- "%d\n", msg_type, trans->cc.state);
- return 0;
- }
-
+ if (i == DOWNSLLEN) {
+ LOGP(DCC, LOGL_NOTICE, "Message %d unhandled at state %d\n",
+ msg_type, trans->cc.state);
+ return 0;
+ }
+
rc = downstatelist[i].rout(trans, arg);
return rc;
@@ -2004,7 +2005,7 @@ int mncc_tx_to_cc(void *inst, int msg_type, void *arg)
/* state trasitions for call control messages (lower layer) */
static struct datastate {
- u_int32_t states;
+ uint32_t states;
int type;
int (*rout) (struct gsm_trans *trans, struct msgb *msg);
} datastatelist[] = {
@@ -2021,7 +2022,7 @@ static struct datastate {
GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
{SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) |
- SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.6 */
+ SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.6 */
GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
/* mobile terminating call establishment */
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm48_mm.c b/Src/osmolib/src/host/layer23/src/mobile/gsm48_mm.c
index ff936e3..a8f699d 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/gsm48_mm.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm48_mm.c
@@ -36,6 +36,8 @@
#include <osmocom/bb/common/networks.h>
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/mobile/gsm48_cc.h>
+#include <osmocom/bb/mobile/gsm480_ss.h>
+#include <osmocom/bb/mobile/gsm411_sms.h>
#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/mobile/vty.h>
@@ -661,7 +663,7 @@ const char *get_mmr_name(int value)
/* allocate GSM 04.08 message (MMxx-SAP) */
struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref,
- uint8_t transaction_id)
+ uint8_t transaction_id, uint8_t sapi)
{
struct msgb *msg;
struct gsm48_mmxx_hdr *mmh;
@@ -675,6 +677,7 @@ struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref,
mmh->msg_type = msg_type;
mmh->ref = ref;
mmh->transaction_id = transaction_id;
+ mmh->sapi = sapi;
return msg;
}
@@ -748,26 +751,24 @@ int gsm48_mmxx_dequeue(struct osmocom_ms *ms)
struct msgb *msg;
struct gsm48_mmxx_hdr *mmh;
int work = 0;
-
+
while ((msg = msgb_dequeue(&mm->mmxx_upqueue))) {
mmh = (struct gsm48_mmxx_hdr *) msg->data;
switch (mmh->msg_type & GSM48_MMXX_MASK) {
case GSM48_MMCC_CLASS:
gsm48_rcv_cc(ms, msg);
break;
-#if 0
case GSM48_MMSS_CLASS:
- gsm48_rcv_ss(ms, msg);
+ gsm480_rcv_ss(ms, msg);
break;
case GSM48_MMSMS_CLASS:
- gsm48_rcv_sms(ms, msg);
+ gsm411_rcv_sms(ms, msg);
break;
-#endif
}
msgb_free(msg);
work = 1; /* work done */
}
-
+
return work;
}
@@ -778,14 +779,14 @@ int gsm48_mmr_dequeue(struct osmocom_ms *ms)
struct msgb *msg;
struct gsm48_mmr *mmr;
int work = 0;
-
+
while ((msg = msgb_dequeue(&mm->mmr_downqueue))) {
mmr = (struct gsm48_mmr *) msg->data;
gsm48_rcv_mmr(ms, msg);
msgb_free(msg);
work = 1; /* work done */
}
-
+
return work;
}
@@ -795,13 +796,13 @@ int gsm48_rr_dequeue(struct osmocom_ms *ms)
struct gsm48_mmlayer *mm = &ms->mmlayer;
struct msgb *msg;
int work = 0;
-
+
while ((msg = msgb_dequeue(&mm->rr_upqueue))) {
/* msg is freed there */
gsm48_rcv_rr(ms, msg);
work = 1; /* work done */
}
-
+
return work;
}
@@ -812,20 +813,20 @@ int gsm48_mmevent_dequeue(struct osmocom_ms *ms)
struct gsm48_mm_event *mme;
struct msgb *msg;
int work = 0;
-
+
while ((msg = msgb_dequeue(&mm->event_queue))) {
mme = (struct gsm48_mm_event *) msg->data;
gsm48_mm_ev(ms, mme->msg_type, msg);
msgb_free(msg);
work = 1; /* work done */
}
-
+
return work;
}
/* push RR header and send to RR */
-static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg,
- int msg_type, uint8_t cause)
+static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg, int msg_type,
+ uint8_t sapi, uint8_t cause)
{
struct gsm48_rr_hdr *rrh;
@@ -833,6 +834,7 @@ static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg,
msgb_push(msg, sizeof(struct gsm48_rr_hdr));
rrh = (struct gsm48_rr_hdr *) msg->data;
rrh->msg_type = msg_type;
+ rrh->sapi = sapi;
rrh->cause = cause;
/* send message to RR */
@@ -927,7 +929,7 @@ static void new_mm_state(struct gsm48_mmlayer *mm, int state, int substate)
switch (substate) {
case GSM48_MM_SST_NORMAL_SERVICE:
vty_notify(ms, NULL);
- vty_notify(ms, "On Network, normal service: %s, %s\n",
+ vty_notify(ms, "On Network, normal service: %s, %s\n",
gsm_get_mcc(plmn->mcc),
gsm_get_mnc(plmn->mcc, plmn->mnc));
break;
@@ -1117,8 +1119,9 @@ static int gsm48_mm_return_idle(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
- /* selected cell equals the registered LAI */
- if (subscr->lac /* valid */
+ /* if we are attached and selected cell equals the registered LAI */
+ if (subscr->imsi_attached
+ && subscr->lac /* valid */
&& cs->sel_mcc == subscr->mcc
&& cs->sel_mnc == subscr->mnc
&& cs->sel_lac == subscr->lac) {
@@ -1336,7 +1339,7 @@ int gsm48_mm_exit(struct osmocom_ms *ms)
/* flush lists */
while (!llist_empty(&mm->mm_conn)) {
- conn = llist_entry(mm->mm_conn.next,
+ conn = llist_entry(mm->mm_conn.next,
struct gsm48_mm_conn, list);
mm_conn_free(conn);
}
@@ -1348,7 +1351,7 @@ int gsm48_mm_exit(struct osmocom_ms *ms)
msgb_free(msg);
while ((msg = msgb_dequeue(&mm->event_queue)))
msgb_free(msg);
-
+
/* stop timers */
stop_mm_t3210(mm);
stop_mm_t3211(mm);
@@ -1413,7 +1416,7 @@ struct gsm48_mm_conn *mm_conn_by_ref(struct gsm48_mmlayer *mm,
/* create MM connection instance */
static struct gsm48_mm_conn* mm_conn_new(struct gsm48_mmlayer *mm,
- int proto, uint8_t transaction_id, uint32_t ref)
+ int proto, uint8_t transaction_id, uint8_t sapi, uint32_t ref)
{
struct gsm48_mm_conn *conn = talloc_zero(l23_ctx, struct gsm48_mm_conn);
@@ -1421,12 +1424,13 @@ static struct gsm48_mm_conn* mm_conn_new(struct gsm48_mmlayer *mm,
return NULL;
LOGP(DMM, LOGL_INFO, "New MM Connection (proto 0x%02x trans_id %d "
- "ref %d)\n", proto, transaction_id, ref);
+ "sapi %d ref %x)\n", proto, transaction_id, sapi, ref);
conn->mm = mm;
conn->state = GSM48_MMXX_ST_IDLE;
conn->transaction_id = transaction_id;
conn->protocol = proto;
+ conn->sapi = sapi;
conn->ref = ref;
llist_add(&conn->list, &mm->mm_conn);
@@ -1448,22 +1452,27 @@ void mm_conn_free(struct gsm48_mm_conn *conn)
/* support function to release pending/all ongoing MM connections */
static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any,
- uint8_t cause, int error)
+ uint8_t cause, int error, uint8_t sapi)
{
struct gsm48_mmlayer *mm = &ms->mmlayer;
struct gsm48_mm_conn *conn, *conn2;
struct msgb *nmsg;
struct gsm48_mmxx_hdr *nmmh;
+ /* Note: For SAPI 0 all connections are released */
+
if (abort_any)
- LOGP(DMM, LOGL_INFO, "Release any MM Connection\n");
+ LOGP(DMM, LOGL_INFO, "Release any MM Connection "
+ "(sapi = %d)\n", sapi);
else
- LOGP(DMM, LOGL_INFO, "Release pending MM Connections\n");
+ LOGP(DMM, LOGL_INFO, "Release pending MM Connections "
+ "(sapi = %d)\n", sapi);
/* release MM connection(s) */
llist_for_each_entry_safe(conn, conn2, &mm->mm_conn, list) {
/* abort any OR the pending connection */
- if (abort_any || conn->state == GSM48_MMXX_ST_CONN_PEND) {
+ if ((abort_any || conn->state == GSM48_MMXX_ST_CONN_PEND)
+ && (sapi == conn->sapi || sapi == 0)) {
/* send MMxx-REL-IND */
nmsg = NULL;
switch(conn->protocol) {
@@ -1471,19 +1480,22 @@ static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any,
nmsg = gsm48_mmxx_msgb_alloc(
error ? GSM48_MMCC_ERR_IND
: GSM48_MMCC_REL_IND, conn->ref,
- conn->transaction_id);
+ conn->transaction_id,
+ conn->sapi);
break;
case GSM48_PDISC_NC_SS:
nmsg = gsm48_mmxx_msgb_alloc(
error ? GSM48_MMSS_ERR_IND
: GSM48_MMSS_REL_IND, conn->ref,
- conn->transaction_id);
+ conn->transaction_id,
+ conn->sapi);
break;
case GSM48_PDISC_SMS:
nmsg = gsm48_mmxx_msgb_alloc(
error ? GSM48_MMSMS_ERR_IND
: GSM48_MMSMS_REL_IND, conn->ref,
- conn->transaction_id);
+ conn->transaction_id,
+ conn->sapi);
break;
}
if (!nmsg) {
@@ -1525,7 +1537,7 @@ static int gsm48_mm_tx_mm_status(struct osmocom_ms *ms, uint8_t cause)
*reject_cause = cause;
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0);
}
/* 4.3.1.2 sending TMSI REALLOCATION COMPLETE message */
@@ -1545,7 +1557,7 @@ static int gsm48_mm_tx_tmsi_reall_cpl(struct osmocom_ms *ms)
ngh->msg_type = GSM48_MT_MM_TMSI_REALL_COMPL;
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0);
}
/* 4.3.1 TMSI REALLOCATION COMMAND is received */
@@ -1661,7 +1673,7 @@ static int gsm48_mm_tx_auth_rsp(struct osmocom_ms *ms, struct msgb *msg)
memcpy(sres, mme->sres, 4);
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0);
}
/* 4.3.2.5 AUTHENTICATION REJECT is received */
@@ -1766,7 +1778,7 @@ static int gsm48_mm_tx_id_rsp(struct osmocom_ms *ms, uint8_t mi_type)
gsm48_encode_mi(buf, nmsg, ms, mi_type);
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0);
}
/* 4.3.4.1 sending IMSI DETACH INDICATION message */
@@ -1814,7 +1826,7 @@ static int gsm48_mm_tx_imsi_detach(struct osmocom_ms *ms, int rr_prim)
/* push RR header and send down */
mm->est_cause = RR_EST_CAUSE_OTHER_SDCCH;
- return gsm48_mm_to_rr(ms, nmsg, rr_prim, mm->est_cause);
+ return gsm48_mm_to_rr(ms, nmsg, rr_prim, 0, mm->est_cause);
}
/* detach has ended */
@@ -1829,7 +1841,6 @@ static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, struct msgb *msg)
/* stop IMSI detach timer (if running) */
stop_mm_t3220(mm);
-
/* SIM invalid */
subscr->sim_valid = 0;
@@ -1856,6 +1867,24 @@ static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, struct msgb *msg)
return gsm48_mm_return_idle(ms, NULL);
}
+/* abort radio connection */
+static int gsm48_mm_imsi_detach_abort(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ /* abort RR if timer fired */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_REQ);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *) nmsg->data;
+ nrrh->cause = GSM48_RR_CAUSE_NORMAL;
+ gsm48_rr_downmsg(ms, nmsg);
+
+ /* imsi detach has ended now */
+ return gsm48_mm_imsi_detach_end(ms, msg);
+}
+
/* start an IMSI detach in MM IDLE */
static int gsm48_mm_imsi_detach_start(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -1891,7 +1920,7 @@ static int gsm48_mm_imsi_detach_sent(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
-
+
/* release MM connection and proceed with IMSI detach */
static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -1903,7 +1932,7 @@ static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, struct msgb *msg)
stop_mm_t3230(mm);
/* release all connections */
- gsm48_mm_release_mm_conn(ms, 1, 16, 0);
+ gsm48_mm_release_mm_conn(ms, 1, 16, 0, 0);
/* wait for release of RR */
if (!s->att_allowed || !subscr->imsi_attached) {
@@ -1972,10 +2001,10 @@ static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg)
/* stop MM connection timer */
stop_mm_t3230(mm);
- gsm48_mm_release_mm_conn(ms, 1, 16, 0);
+ gsm48_mm_release_mm_conn(ms, 1, 16, 0, 0);
}
- if (reject_cause == GSM48_REJECT_ILLEGAL_ME) {
+ if (reject_cause == GSM48_REJECT_ILLEGAL_ME) {
/* SIM invalid */
subscr->sim_valid = 0;
@@ -2038,7 +2067,7 @@ static int gsm48_mm_sysinfo(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_mmlayer *mm = &ms->mmlayer;
struct gsm48_sysinfo *s = &ms->cellsel.sel_si;
- /* t3212 not changed in these states */
+ /* t3212 not changed in these states */
if (mm->state == GSM48_MM_ST_MM_IDLE
&& (mm->substate == GSM48_MM_SST_NO_CELL_AVAIL
|| mm->substate == GSM48_MM_SST_LIMITED_SERVICE
@@ -2074,7 +2103,7 @@ static int gsm48_mm_sysinfo(struct osmocom_ms *ms, struct msgb *msg)
}
mm->t3212_value = s->t3212;
}
-
+
return 0;
}
@@ -2095,7 +2124,7 @@ static int gsm48_mm_loc_upd(struct osmocom_ms *ms, struct msgb *msg)
struct gsm_settings *set = &ms->settings;
struct msgb *nmsg;
int msg_type;
-
+
/* (re)start only if we still require location update */
if (!mm->lupd_pending) {
LOGP(DMM, LOGL_INFO, "No loc. upd. pending.\n");
@@ -2315,7 +2344,7 @@ static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms)
/* location updating type */
nlu->type = mm->lupd_type;
/* cipering key */
- nlu->key_seq = subscr->key_seq;
+ nlu->key_seq = gsm_subscr_get_key_seq(ms, subscr);
/* LAI (last SIM stored LAI)
*
* NOTE: The TMSI is only valid within a LAI!
@@ -2343,7 +2372,7 @@ static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms)
/* push RR header and send down */
mm->est_cause = RR_EST_CAUSE_LOC_UPD;
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ, mm->est_cause);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ, 0, mm->est_cause);
}
/* 4.4.4.1 RR is esablised during location update */
@@ -2511,7 +2540,7 @@ static int gsm48_mm_rx_loc_upd_rej(struct osmocom_ms *ms, struct msgb *msg)
start_mm_t3240(mm);
new_mm_state(mm, GSM48_MM_ST_LOC_UPD_REJ, 0);
-
+
return 0;
}
@@ -2522,7 +2551,7 @@ static int gsm48_mm_rel_loc_upd_rej(struct osmocom_ms *ms, struct msgb *msg)
struct gsm_subscriber *subscr = &ms->subscr;
struct msgb *nmsg;
struct gsm322_msg *ngm;
-
+
LOGP(DMM, LOGL_INFO, "Loc. upd. rejected (cause %d)\n",
mm->lupd_rej_cause);
@@ -2777,7 +2806,7 @@ static int gsm48_mm_tx_cm_serv_req(struct osmocom_ms *ms, int rr_prim,
/* type and key */
nsr->cm_service_type = cm_serv;
- nsr->cipher_key_seq = subscr->key_seq;
+ nsr->cipher_key_seq = gsm_subscr_get_key_seq(ms, subscr);
/* classmark 2 */
cm2lv[0] = sizeof(struct gsm48_classmark2);
gsm48_rr_enc_cm2(ms, (struct gsm48_classmark2 *)(cm2lv + 1),
@@ -2807,7 +2836,7 @@ static int gsm48_mm_tx_cm_serv_req(struct osmocom_ms *ms, int rr_prim,
/* prio is optional for eMLPP */
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, rr_prim, mm->est_cause);
+ return gsm48_mm_to_rr(ms, nmsg, rr_prim, 0, mm->est_cause);
}
/* cm service abort message from upper layer
@@ -2829,7 +2858,7 @@ static int gsm48_mm_tx_cm_service_abort(struct osmocom_ms *ms)
ngh->msg_type = GSM48_MT_MM_CM_SERV_ABORT;
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0);
}
/* cm service acknowledge is received from lower layer */
@@ -2900,7 +2929,7 @@ static int gsm48_mm_rx_cm_service_rej(struct osmocom_ms *ms, struct msgb *msg)
}
/* release MM connection(s) */
- gsm48_mm_release_mm_conn(ms, abort_any, 16, 0);
+ gsm48_mm_release_mm_conn(ms, abort_any, 16, 0, 0);
/* state depends on the existance of remaining MM connections */
if (llist_empty(&mm->mm_conn))
@@ -2930,6 +2959,7 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg,
struct msgb *nmsg;
struct gsm48_mmxx_hdr *nmmh;
struct gsm48_mm_conn *conn, *conn_found = NULL;
+ uint8_t sapi = mmh->sapi;
/* reset loc. upd. counter on CM service request */
mm->lupd_attempt = 0;
@@ -2947,20 +2977,24 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg,
LOGP(DMM, LOGL_INFO, "Init MM Connection, but already have "
"pending MM Connection.\n");
cause = 17;
+ /* use sapi from connection. if no connection, use sapi from
+ * message.
+ */
+ sapi = conn_found->sapi;
reject:
nmsg = NULL;
switch(msg_type) {
case GSM48_MMCC_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_IND,
- mmh->ref, mmh->transaction_id);
+ mmh->ref, mmh->transaction_id, sapi);
break;
case GSM48_MMSS_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_IND,
- mmh->ref, mmh->transaction_id);
+ mmh->ref, mmh->transaction_id, sapi);
break;
case GSM48_MMSMS_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_IND,
- mmh->ref, mmh->transaction_id);
+ mmh->ref, mmh->transaction_id, sapi);
break;
}
if (!nmsg)
@@ -3039,7 +3073,7 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg,
}
/* create MM connection instance */
- conn = mm_conn_new(mm, proto, mmh->transaction_id, mmh->ref);
+ conn = mm_conn_new(mm, proto, mmh->transaction_id, mmh->sapi, mmh->ref);
if (!conn)
return -ENOMEM;
@@ -3166,6 +3200,7 @@ static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
int msg_type = mmh->msg_type;
+ int sapi = mmh->sapi;
struct msgb *nmsg;
struct gsm48_mmxx_hdr *nmmh;
@@ -3174,15 +3209,15 @@ static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg)
switch(msg_type) {
case GSM48_MMCC_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_IND, mmh->ref,
- mmh->transaction_id);
+ mmh->transaction_id, sapi);
break;
case GSM48_MMSS_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_IND, mmh->ref,
- mmh->transaction_id);
+ mmh->transaction_id, sapi);
break;
case GSM48_MMSMS_EST_REQ:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_IND, mmh->ref,
- mmh->transaction_id);
+ mmh->transaction_id, sapi);
break;
}
if (!nmsg)
@@ -3198,7 +3233,7 @@ static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg)
*
* this function is called:
* - when ciphering command is received
- * - when cm service is accepted
+ * - when cm service is accepted
*/
static int gsm48_mm_conn_go_dedic(struct osmocom_ms *ms)
{
@@ -3228,22 +3263,33 @@ static int gsm48_mm_conn_go_dedic(struct osmocom_ms *ms)
nmsg = NULL;
switch(conn_found->protocol) {
case GSM48_PDISC_CC:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_CNF, conn->ref,
- conn->transaction_id);
+ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_CNF,
+ conn_found->ref, conn_found->transaction_id,
+ conn_found->sapi);
break;
case GSM48_PDISC_NC_SS:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_EST_CNF, conn->ref,
- conn->transaction_id);
+ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_EST_CNF,
+ conn_found->ref, conn_found->transaction_id,
+ conn_found->sapi);
break;
case GSM48_PDISC_SMS:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_EST_CNF, conn->ref,
- conn->transaction_id);
+ if (!mm->sapi3_link) {
+ LOGP(DMM, LOGL_INFO, "Sapi 3 link down, requesting "
+ "link, waiting for confirm.\n");
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ,
+ conn_found->sapi, 0);
+ }
+ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_EST_CNF,
+ conn_found->ref, conn_found->transaction_id,
+ conn_found->sapi);
break;
}
if (!nmsg)
return -ENOMEM;
nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = 17;
gsm48_mmxx_upmsg(ms, nmsg);
return 0;
@@ -3287,13 +3333,12 @@ static int gsm48_mm_sync_ind_active(struct osmocom_ms *ms, struct msgb *msg)
switch(conn->protocol) {
case GSM48_PDISC_CC:
nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_SYNC_IND,
- conn->ref, conn->transaction_id);
+ conn->ref, conn->transaction_id, conn->sapi);
break;
}
if (!nmsg)
continue; /* skip if not of CC type */
nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = 17;
/* copy L3 message */
nmsg->l3h = msgb_put(nmsg, msgb_l3len(msg));
memcpy(nmsg->l3h, msg->l3h, msgb_l3len(msg));
@@ -3331,7 +3376,7 @@ static int gsm48_mm_abort_mm_con(struct osmocom_ms *ms, struct msgb *msg)
stop_mm_t3230(mm);
/* release all connections */
- gsm48_mm_release_mm_conn(ms, 1, cause, 1);
+ gsm48_mm_release_mm_conn(ms, 1, cause, 1, 0);
/* return to MM IDLE */
return gsm48_mm_return_idle(ms, NULL);
@@ -3343,7 +3388,7 @@ static int gsm48_mm_timeout_mm_con(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_mmlayer *mm = &ms->mmlayer;
/* release pending connection */
- gsm48_mm_release_mm_conn(ms, 0, 102, 0);
+ gsm48_mm_release_mm_conn(ms, 0, 102, 0, 0);
/* state depends on the existance of remaining MM connections */
if (llist_empty(&mm->mm_conn)) {
@@ -3397,12 +3442,15 @@ static int gsm48_mm_data(struct osmocom_ms *ms, struct msgb *msg)
/* mirror message with REL_IND + cause */
return gsm48_mmxx_upmsg(ms, msg);
}
-
+
+ /* set SAPI, if upper layer does not do it correctly */
+ mmh->sapi = conn->sapi;
+
/* pull MM header */
msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
/* push RR header and send down */
- return gsm48_mm_to_rr(ms, msg, GSM48_RR_DATA_REQ, 0);
+ return gsm48_mm_to_rr(ms, msg, GSM48_RR_DATA_REQ, conn->sapi, 0);
}
/* release of MM connection (active state) */
@@ -3526,6 +3574,50 @@ static int gsm48_mm_rel_other(struct osmocom_ms *ms, struct msgb *msg)
}
/*
+ * sapi 3
+ */
+
+static int gsm48_rcv_rr_sapi3(struct osmocom_ms *ms, struct msgb *msg,
+ int msg_type, uint8_t sapi)
+{
+ struct gsm48_mmlayer *mm = &ms->mmlayer;
+ struct gsm48_mm_conn *conn;
+
+ switch (msg_type) {
+ case GSM48_RR_EST_CNF:
+ LOGP(DMM, LOGL_INFO, "SAPI 3 link up, confirming conns.\n");
+ mm->sapi3_link = 1;
+ /* indicate establishment to sapi 3 connections */
+ llist_for_each_entry(conn, &mm->mm_conn, list) {
+ if (conn->sapi == sapi
+ && conn->state == GSM48_MMXX_ST_DEDICATED) {
+ struct gsm48_mmxx_hdr *nmmh;
+ struct msgb *nmsg;
+
+ nmsg = gsm48_mmxx_msgb_alloc(
+ GSM48_MMSMS_EST_CNF, conn->ref,
+ conn->transaction_id, conn->sapi);
+ if (!nmsg)
+ return -ENOMEM;
+ nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
+ gsm48_mmxx_upmsg(ms, nmsg);
+ }
+ }
+ break;
+ case GSM48_RR_DATA_IND:
+ return gsm48_mm_data_ind(ms, msg);
+ case GSM48_RR_REL_IND:
+ LOGP(DMM, LOGL_INFO, "SAPI 3 link down, releasing conns.\n");
+ mm->sapi3_link = 0;
+ gsm48_mm_release_mm_conn(ms, 1, 16, 0, sapi);
+ break;
+ }
+ msgb_free(msg);
+
+ return 0;
+}
+
+/*
* state machines
*/
@@ -3802,11 +3894,15 @@ static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_mmlayer *mm = &ms->mmlayer;
struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data;
int msg_type = rrh->msg_type;
+ int sapi = rrh->sapi;
int i, rc;
- LOGP(DMM, LOGL_INFO, "(ms %s) Received '%s' from RR in state %s\n",
- ms->name, get_rr_name(msg_type),
- gsm48_mm_state_names[mm->state]);
+ LOGP(DMM, LOGL_INFO, "(ms %s) Received '%s' from RR in state %s "
+ "(sapi %d)\n", ms->name, get_rr_name(msg_type),
+ gsm48_mm_state_names[mm->state], sapi);
+
+ if (sapi)
+ return gsm48_rcv_rr_sapi3(ms, msg, msg_type, sapi);
/* find function for current state and message */
for (i = 0; i < RRDATASLLEN; i++)
@@ -3820,7 +3916,7 @@ static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg)
}
rc = rrdatastatelist[i].rout(ms, msg);
-
+
if (rrdatastatelist[i].rout != gsm48_mm_data_ind)
msgb_free(msg);
@@ -3870,6 +3966,8 @@ static struct mmdatastate {
static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_mmlayer *mm = &ms->mmlayer;
+ struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data;
+ int sapi = rrh->sapi;
struct gsm48_hdr *gh = msgb_l3(msg);
uint8_t pdisc = gh->proto_discr & 0x0f;
uint8_t msg_type = gh->msg_type & 0xbf;
@@ -3880,12 +3978,15 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
int i, rc;
/* 9.2.19 */
- if (msg_type == GSM48_MT_MM_NULL)
+ if (msg_type == GSM48_MT_MM_NULL) {
+ msgb_free(msg);
return 0;
+ }
if (mm->state == GSM48_MM_ST_IMSI_DETACH_INIT) {
LOGP(DMM, LOGL_NOTICE, "DATA IND ignored during IMSI "
"detach.\n");
+ msgb_free(msg);
return 0;
}
/* pull the RR header */
@@ -3897,7 +3998,6 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
rr_prim = GSM48_MMCC_DATA_IND;
rr_est = GSM48_MMCC_EST_IND;
break;
-#if 0
case GSM48_PDISC_NC_SS:
rr_prim = GSM48_MMSS_DATA_IND;
rr_est = GSM48_MMSS_EST_IND;
@@ -3906,7 +4006,6 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
rr_prim = GSM48_MMSMS_DATA_IND;
rr_est = GSM48_MMSMS_EST_IND;
break;
-#endif
}
if (rr_prim != -1) {
uint8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4;
@@ -3918,18 +4017,22 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
/* create MM connection instance */
if (!conn) {
- conn = mm_conn_new(mm, pdisc, transaction_id,
+ conn = mm_conn_new(mm, pdisc, transaction_id, sapi,
mm_conn_new_ref++);
rr_prim = rr_est;
}
- if (!conn)
+ if (!conn) {
+ msgb_free(msg);
return -ENOMEM;
+ }
/* push new header */
msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
mmh = (struct gsm48_mmxx_hdr *)msg->data;
mmh->msg_type = rr_prim;
mmh->ref = conn->ref;
+ mmh->transaction_id = conn->transaction_id;
+ mmh->sapi = conn->sapi;
/* go MM CONN ACTIVE state */
if (mm->state == GSM48_MM_ST_WAIT_NETWORK_CMD
@@ -3950,24 +4053,35 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
skip_ind = (gh->proto_discr & 0xf0) >> 4;
/* ignore if skip indicator is not B'0000' */
- if (skip_ind)
+ if (skip_ind) {
+ msgb_free(msg);
return 0;
+ }
break; /* follow the selection proceedure below */
case GSM48_PDISC_CC:
- return gsm48_rcv_cc(ms, msg);
+ rc = gsm48_rcv_cc(ms, msg);
+ msgb_free(msg);
+ return rc;
-#if 0
case GSM48_PDISC_NC_SS:
- return gsm48_rcv_ss(ms, msg);
+ rc = gsm480_rcv_ss(ms, msg);
+ msgb_free(msg);
+ return rc;
case GSM48_PDISC_SMS:
- return gsm48_rcv_sms(ms, msg);
-#endif
+ rc = gsm411_rcv_sms(ms, msg);
+ msgb_free(msg);
+ return rc;
+ case 0x0f: /* test TS 04.14 */
+ LOGP(DMM, LOGL_NOTICE, "Test protocol 0x%02x according to "
+ "TS 04.14 is not supported.\n", pdisc);
+ goto status;
default:
LOGP(DMM, LOGL_NOTICE, "Protocol type 0x%02x unsupported.\n",
pdisc);
+status:
msgb_free(msg);
return gsm48_mm_tx_mm_status(ms,
GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED);
@@ -4136,8 +4250,8 @@ static struct eventstate {
{ALL_STATES, ALL_STATES,
GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_delay},
- {GSM48_MM_ST_IMSI_DETACH_INIT, ALL_STATES,
- GSM48_MM_EVENT_TIMEOUT_T3220, gsm48_mm_imsi_detach_end},
+ {SBIT(GSM48_MM_ST_IMSI_DETACH_INIT), ALL_STATES,
+ GSM48_MM_EVENT_TIMEOUT_T3220, gsm48_mm_imsi_detach_abort},
/* location update in other cases */
{SBIT(GSM48_MM_ST_MM_IDLE), ALL_STATES,
@@ -4166,7 +4280,8 @@ static struct eventstate {
GSM48_MM_EVENT_TIMEOUT_T3240, gsm48_mm_abort_rr},
/* T3230 timed out */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
+ {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN) |
+ SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
GSM48_MM_EVENT_TIMEOUT_T3230, gsm48_mm_timeout_mm_con},
/* SIM reports SRES */
diff --git a/Src/osmolib/src/host/layer23/src/mobile/gsm48_rr.c b/Src/osmolib/src/host/layer23/src/mobile/gsm48_rr.c
index c1e386a..b6083af 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/gsm48_rr.c
@@ -145,7 +145,7 @@ static int gsm48_decode_ba_range(const uint8_t *ba, uint8_t ba_len,
*/
uint16_t lower, higher;
int i, n, required_octets;
-
+
/* find out how much ba ranges will be decoded */
n = *ba++;
ba_len --;
@@ -351,7 +351,7 @@ const char *gsm48_rr_state_names[] = {
static void new_rr_state(struct gsm48_rrlayer *rr, int state)
{
- if (state < 0 || state >=
+ if (state < 0 || state >=
(sizeof(gsm48_rr_state_names) / sizeof(char *)))
return;
@@ -422,6 +422,26 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
}
}
+const char *gsm48_sapi3_state_names[] = {
+ "idle",
+ "wait establishment",
+ "established",
+ "wait release",
+};
+
+static void new_sapi3_state(struct gsm48_rrlayer *rr, int state)
+{
+ if (state < 0 || state >=
+ (sizeof(gsm48_sapi3_state_names) / sizeof(char *)))
+ return;
+
+ LOGP(DRR, LOGL_INFO, "new SAPI 3 link state %s -> %s\n",
+ gsm48_sapi3_state_names[rr->sapi3_state],
+ gsm48_sapi3_state_names[state]);
+
+ rr->sapi3_state = state;
+}
+
/*
* messages
*/
@@ -504,7 +524,7 @@ int gsm48_rr_upmsg(struct osmocom_ms *ms, struct msgb *msg)
/* push rsl header and send (RSL-SAP) */
static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
- struct msgb *msg)
+ struct msgb *msg, uint8_t link_id)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
@@ -512,20 +532,19 @@ static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
LOGP(DRR, LOGL_ERROR, "FIX l3h\n");
return -EINVAL;
}
- rsl_rll_push_l3(msg, msg_type, rr->cd_now.chan_nr,
- rr->cd_now.link_id, 1);
+ rsl_rll_push_l3(msg, msg_type, rr->cd_now.chan_nr, link_id, 1);
return lapdm_rslms_recvmsg(msg, &ms->lapdm_channel);
}
-/* push rsl header + release mode and send (RSL-SAP) */
-static int gsm48_send_rsl_rel(struct osmocom_ms *ms, uint8_t msg_type,
- struct msgb *msg)
+/* push rsl header without L3 info and send (RSL-SAP) */
+static int gsm48_send_rsl_nol3(struct osmocom_ms *ms, uint8_t msg_type,
+ struct msgb *msg, uint8_t link_id)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
rsl_rll_push_hdr(msg, msg_type, rr->cd_now.chan_nr,
- rr->cd_now.link_id, 1);
+ link_id, 1);
return lapdm_rslms_recvmsg(msg, &ms->lapdm_channel);
}
@@ -547,13 +566,13 @@ int gsm48_rsl_dequeue(struct osmocom_ms *ms)
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct msgb *msg;
int work = 0;
-
+
while ((msg = msgb_dequeue(&rr->rsl_upqueue))) {
/* msg is freed there */
gsm48_rcv_rsl(ms, msg);
work = 1; /* work done */
}
-
+
return work;
}
@@ -571,6 +590,43 @@ int gsm48_rr_stop_monitor(struct osmocom_ms *ms)
return 0;
}
+/* release L3 link in both directions in case of main link release */
+static int gsm48_release_sapi3_link(struct osmocom_ms *ms)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_rr_hdr *nrrh;
+ struct msgb *nmsg;
+ uint8_t *mode;
+
+ if (rr->sapi3_state == GSM48_RR_SAPI3ST_IDLE)
+ return 0;
+
+ LOGP(DRR, LOGL_INFO, "Main signallin link is down, so release SAPI 3 "
+ "link locally.\n");
+
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE);
+
+ /* disconnect the SAPI 3 signalling link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 1; /* local release */
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, rr->sapi3_link_id);
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_NORMAL;
+ nrrh->sapi = rr->sapi3_link_id & 7;
+ gsm48_rr_upmsg(ms, nmsg);
+
+ return 0;
+}
+
/*
* timers handling
*/
@@ -598,7 +654,7 @@ static void timeout_rr_meas(void *arg)
snr = (meas->snr + meas->frames / 2) / meas->frames;
sprintf(text, "MON: f=%d lev=%s snr=%2d ber=%3d "
"LAI=%s %s %04x ID=%04x", cs->sel_arfcn,
- gsm_print_rxlev(rxlev), berr, snr,
+ gsm_print_rxlev(rxlev), berr, snr,
gsm_print_mcc(cs->sel_mcc),
gsm_print_mnc(cs->sel_mnc), cs->sel_lac, cs->sel_id);
if (rr->state == GSM48_RR_ST_DEDICATED) {
@@ -646,7 +702,11 @@ static void timeout_rr_t_starting(void *arg)
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return;
- gsm48_send_rsl(rr->ms, RSL_MT_SUSP_REQ, nmsg);
+ gsm48_send_rsl(rr->ms, RSL_MT_SUSP_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits
+ * FIXME: suspend and resume afterward */
+ gsm48_release_sapi3_link(rr->ms);
}
/* special timer to ensure that UA is sent before disconnecting channel */
@@ -679,7 +739,10 @@ static void timeout_rr_t3110(void *arg)
mode = msgb_put(nmsg, 2);
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 1; /* local release */
- gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits */
+ gsm48_release_sapi3_link(ms);
return;
}
@@ -857,7 +920,7 @@ static int gsm48_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
/* rr cause */
st->rr_cause = cause;
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
}
/*
@@ -892,7 +955,7 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
memcpy(tlv, buf, 2 + buf[1]);
}
- gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
/* send RR_SYNC_IND(ciphering) */
nmsg = gsm48_rr_msgb_alloc(GSM48_RR_SYNC_IND);
@@ -1224,7 +1287,7 @@ static int gsm48_rr_tx_cm_change(struct osmocom_ms *ms)
memcpy(tlv, cm3, 2 + cm3[1]);
}
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
}
/* receiving classmark enquiry */
@@ -1239,7 +1302,8 @@ static int gsm48_rr_rx_cm_enq(struct osmocom_ms *ms, struct msgb *msg)
*/
/* start random access */
-static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging)
+static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging,
+ int paging_mi_type)
{
struct gsm_settings *set = &ms->settings;
struct gsm48_rrlayer *rr = &ms->rrlayer;
@@ -1450,6 +1514,9 @@ rel_ind:
* after location updating */
rr->est_cause = cause;
+ /* store paging mobile identity type, if we respond to paging */
+ rr->paging_mi_type = paging_mi_type;
+
/* if channel is already active somehow */
if (cs->ccch_state == GSM322_CCCH_ST_DATA)
return gsm48_rr_tx_rand_acc(ms, NULL);
@@ -2037,7 +2104,7 @@ static int gsm48_rr_chan2cause[4] = {
};
/* given LV of mobile identity is checked agains ms */
-static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
+static uint8_t gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
{
struct gsm322_cellsel *cs = &ms->cellsel;
char imsi[16];
@@ -2059,7 +2126,7 @@ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n",
ntohl(tmsi));
- return 1;
+ return mi_type;
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(tmsi));
@@ -2069,7 +2136,7 @@ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi)
if (!strcmp(imsi, ms->subscr.imsi)) {
LOGP(DPAG, LOGL_INFO, " IMSI %s matches\n", imsi);
- return 1;
+ return mi_type;
} else
LOGP(DPAG, LOGL_INFO, " IMSI %s (not for us)\n", imsi);
break;
@@ -2089,7 +2156,7 @@ static int gsm48_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_paging1 *pa = msgb_l3(msg);
int payload_len = msgb_l3len(msg) - sizeof(*pa);
int chan_1, chan_2;
- uint8_t *mi;
+ uint8_t *mi, mi_type;
/* empty paging request */
if (payload_len >= 2 && (pa->data[1] & GSM_MI_TYPE_MASK) == 0)
@@ -2121,8 +2188,9 @@ static int gsm48_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
mi = pa->data;
if (payload_len < mi[0] + 1)
goto short_read;
- if (gsm_match_mi(ms, mi) > 0)
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ if ((mi_type = gsm_match_mi(ms, mi)) > 0)
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1,
+ mi_type);
/* second MI */
payload_len -= mi[0] + 1;
mi = pa->data + mi[0] + 1;
@@ -2132,8 +2200,9 @@ static int gsm48_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
return 0;
if (payload_len < mi[1] + 2)
goto short_read;
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ if ((mi_type = gsm_match_mi(ms, mi + 1)) > 0)
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1,
+ mi_type);
return 0;
}
@@ -2145,7 +2214,7 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
struct gsm322_cellsel *cs = &ms->cellsel;
struct gsm48_paging2 *pa = msgb_l3(msg);
int payload_len = msgb_l3len(msg) - sizeof(*pa);
- uint8_t *mi;
+ uint8_t *mi, mi_type;
int chan_1, chan_2, chan_3;
/* 3.3.1.1.2: ignore paging while not camping on a cell */
@@ -2176,7 +2245,8 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi1));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi1));
@@ -2186,7 +2256,8 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi2));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi2));
@@ -2199,8 +2270,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg)
if (payload_len < mi[1] + 2 + 1) /* must include "channel needed" */
goto short_read;
chan_3 = mi[mi[1] + 2] & 0x03; /* channel needed */
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
+ if ((mi_type = gsm_match_mi(ms, mi + 1)) > 0)
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1,
+ mi_type);
return 0;
}
@@ -2243,7 +2315,8 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi1));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi1));
@@ -2253,7 +2326,8 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi2));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi2));
@@ -2263,7 +2337,8 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi3));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi3));
@@ -2273,7 +2348,8 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg)
&& ms->subscr.mnc == cs->sel_mnc
&& ms->subscr.lac == cs->sel_lac) {
LOGP(DPAG, LOGL_INFO, " TMSI %08x matches\n", ntohl(pa->tmsi4));
- return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1,
+ GSM_MI_TYPE_TMSI);
} else
LOGP(DPAG, LOGL_INFO, " TMSI %08x (not for us)\n",
ntohl(pa->tmsi4));
@@ -2415,7 +2491,7 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
/* timing advance */
rr->cd_now.ind_ta = ia->timing_advance;
/* mobile allocation */
- memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
+ memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
ia->mob_alloc_len + 1);
rr->wait_assign = 2;
/* reset scheduler */
@@ -2850,7 +2926,10 @@ int gsm48_rr_los(struct osmocom_ms *ms)
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 1; /* local release */
/* start release */
- return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0);
+ /* release SAPI 3 link, if exits */
+ gsm48_release_sapi3_link(ms);
+ return 0;
case GSM48_RR_ST_REL_PEND:
LOGP(DRR, LOGL_INFO, "LOS during RR release procedure, release "
"locally\n");
@@ -2991,7 +3070,7 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd,
/* decode mobile allocation */
if (cd->mob_alloc_lv[0]) {
struct gsm_sysinfo_freq *freq = s->freq;
-
+
LOGP(DRR, LOGL_INFO, "decoding mobile allocation\n");
if (cd->cell_desc_lv[0]) {
@@ -3172,7 +3251,7 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
gh->msg_type = GSM48_MT_RR_PAG_RESP;
pr = (struct gsm48_pag_rsp *) msgb_put(nmsg, sizeof(*pr));
/* key sequence */
- pr->key_seq = subscr->key_seq;
+ pr->key_seq = gsm_subscr_get_key_seq(ms, subscr);
/* classmark 2 */
pr->cm2_len = sizeof(pr->cm2);
gsm48_rr_enc_cm2(ms, &pr->cm2, rr->cd_now.arfcn);
@@ -3180,7 +3259,8 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
if (ms->subscr.tmsi != 0xffffffff
&& ms->subscr.mcc == cs->sel_mcc
&& ms->subscr.mnc == cs->sel_mnc
- && ms->subscr.lac == cs->sel_lac) {
+ && ms->subscr.lac == cs->sel_lac
+ && rr->paging_mi_type == GSM_MI_TYPE_TMSI) {
gsm48_generate_mid_from_tmsi(mi, subscr->tmsi);
LOGP(DRR, LOGL_INFO, "sending paging response with "
"TMSI\n");
@@ -3216,7 +3296,7 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
#endif
/* start establishmnet */
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg, 0);
}
/* the link is established */
@@ -3237,7 +3317,7 @@ static int gsm48_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 0; /* normal release */
/* start release */
- return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ return gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0);
}
/* 3.3.1.1.4 */
@@ -3286,6 +3366,9 @@ static int gsm48_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg)
/* pending release */
new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+ /* also release SAPI 3 link, if exists */
+ gsm48_release_sapi3_link(ms);
+
return 0;
}
@@ -3308,7 +3391,7 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
}
tlv_parse(&tp, &gsm48_rr_att_tlvdef, cr->data, payload_len, 0, 0);
- LOGP(DRR, LOGL_INFO, "channel release request with cause 0x%02x)\n",
+ LOGP(DRR, LOGL_INFO, "channel release request with cause 0x%02x\n",
cr->rr_cause);
/* BA range */
@@ -3334,7 +3417,11 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
mode = msgb_put(nmsg, 2);
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 0; /* normal release */
- return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits */
+ gsm48_release_sapi3_link(ms);
+ return 0;
}
/*
@@ -3411,7 +3498,7 @@ static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg)
}
/* mobile allocation */
- memcpy(rr->cd_now.mob_alloc_lv, &fr->mob_alloc_len,
+ memcpy(rr->cd_now.mob_alloc_lv, &fr->mob_alloc_len,
fr->mob_alloc_len + 1);
/* starting time */
@@ -3469,7 +3556,7 @@ static int gsm48_rr_tx_chan_modify_ack(struct osmocom_ms *ms,
/* mode */
cm->mode = mode;
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
}
/* 9.1.5 CHANNEL MODE MODIFY is received */
@@ -3547,7 +3634,7 @@ static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
/* RR_CAUSE */
ac->rr_cause = cause;
- return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg, 0);
}
/* 9.1.4 sending ASSIGNMENT FAILURE */
@@ -3572,7 +3659,7 @@ static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause,
/* RR_CAUSE */
af->rr_cause = cause;
- return gsm48_send_rsl(ms, rsl_prim, nmsg);
+ return gsm48_send_rsl(ms, rsl_prim, nmsg, 0);
}
/* 9.1.2 ASSIGNMENT COMMAND is received */
@@ -3663,8 +3750,8 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
cda->start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432;
LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n");
#else
- if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) {
- gsm48_decode_start_time(cda, (struct gsm48_start_time *)
+ if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) {
+ gsm48_decode_start_time(cda, (struct gsm48_start_time *)
TLVP_VAL(&tp, GSM48_IE_START_TIME));
/* 9.1.2.5 "... before time IE is not present..." */
if (!before_time) {
@@ -3882,7 +3969,11 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg);
+ gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits
+ * FIXME: suspend and resume afterward */
+ gsm48_release_sapi3_link(ms);
return 0;
}
@@ -3910,7 +4001,7 @@ static int gsm48_rr_tx_hando_cpl(struct osmocom_ms *ms, uint8_t cause)
// FIXME: mobile observed time
- return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg, 0);
}
/* 9.1.4 sending HANDOVER FAILURE */
@@ -3935,7 +4026,7 @@ static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause,
/* RR_CAUSE */
hf->rr_cause = cause;
- return gsm48_send_rsl(ms, rsl_prim, nmsg);
+ return gsm48_send_rsl(ms, rsl_prim, nmsg, 0);
}
/* receiving HANDOVER COMMAND message (9.1.15) */
@@ -3984,8 +4075,8 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
tlv_parse(&tp, &gsm48_rr_att_tlvdef, ho->data, payload_len, 0, 0);
/* sync ind */
- if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND)) {
- gsm48_decode_sync_ind(rr, (struct gsm48_sync_ind *)
+ if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND)) {
+ gsm48_decode_sync_ind(rr, (struct gsm48_sync_ind *)
TLVP_VAL(&tp, GSM48_IE_SYNC_IND));
LOGP(DRR, LOGL_INFO, " (sync_ind=%d rot=%d nci=%d)\n",
rr->hando_sync_ind, rr->hando_rot, rr->hando_nci);
@@ -4043,8 +4134,8 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
cda->start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432;
LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n");
#else
- if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) {
- gsm48_decode_start_time(cda, (struct gsm48_start_time *)
+ if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) {
+ gsm48_decode_start_time(cda, (struct gsm48_start_time *)
TLVP_VAL(&tp, GSM48_IE_START_TIME));
/* 9.1.2.5 "... before time IE is not present..." */
if (!before_time) {
@@ -4268,7 +4359,11 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg);
+ gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits
+ * FIXME: suspend and resume afterward */
+ gsm48_release_sapi3_link(ms);
return 0;
}
@@ -4280,8 +4375,16 @@ static int gsm48_rr_dequeue_down(struct osmocom_ms *ms)
struct msgb *msg;
while((msg = msgb_dequeue(&rr->downqueue))) {
+ struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
+ uint8_t sapi = rrh->sapi;
+
LOGP(DRR, LOGL_INFO, "Sending queued message.\n");
- gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg);
+ if (sapi && rr->sapi3_state != GSM48_RR_SAPI3ST_ESTAB) {
+ LOGP(DRR, LOGL_INFO, "Dropping SAPI 3 msg, no link!\n");
+ msgb_free(msg);
+ return 0;
+ }
+ gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg, 0);
}
return 0;
@@ -4370,7 +4473,7 @@ static int gsm48_rr_susp_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
}
/*
- * radio ressource requests
+ * radio ressource requests
*/
/* establish request for dedicated mode */
@@ -4475,19 +4578,21 @@ static int gsm48_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
msgb_l3(msg), msgb_l3len(msg));
/* request channel */
- return gsm48_rr_chan_req(ms, rrh->cause, 0);
+ return gsm48_rr_chan_req(ms, rrh->cause, 0, 0);
}
/* 3.4.2 transfer data in dedicated mode */
static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
+ uint8_t sapi = rrh->sapi;
if (rr->state != GSM48_RR_ST_DEDICATED) {
msgb_free(msg);
return -EINVAL;
}
-
+
/* pull RR header */
msgb_pull(msg, sizeof(struct gsm48_rr_hdr));
@@ -4502,8 +4607,15 @@ static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
+ if (sapi && rr->sapi3_state != GSM48_RR_SAPI3ST_ESTAB) {
+ LOGP(DRR, LOGL_INFO, "Dropping SAPI 3 msg, no link!\n");
+ msgb_free(msg);
+ return 0;
+ }
+
/* forward message */
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg);
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg,
+ sapi ? rr->sapi3_link_id : 0);
}
/*
@@ -4684,7 +4796,7 @@ static int gsm48_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
struct tlv_parsed tv;
uint8_t ch_type, ch_subch, ch_ts;
-
+
DEBUGP(DRSL, "RSLms UNIT DATA IND chan_nr=0x%02x link_id=0x%02x\n",
rllh->chan_nr, rllh->link_id);
@@ -4765,7 +4877,11 @@ static int gsm48_rr_abort_req(struct osmocom_ms *ms, struct msgb *msg)
mode = msgb_put(nmsg, 2);
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 0; /* normal release */
- return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0);
+
+ /* release SAPI 3 link, if exits */
+ gsm48_release_sapi3_link(ms);
+ return 0;
}
LOGP(DRR, LOGL_INFO, "Abort in connection pending state, return to "
@@ -4853,6 +4969,7 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_rr_hdr *nrrh;
uint8_t *mode;
uint8_t cause = rllh->data[2];
+ uint8_t link_id = rllh->link_id;
switch (cause) {
case RLL_CAUSE_SEQ_ERR:
@@ -4865,14 +4982,14 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
LOGP(DRR, LOGL_NOTICE, "MDL-Error (cause %d) aborting\n", cause);
- /* disconnect the main signalling link */
+ /* disconnect the (main) signalling link */
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
mode = msgb_put(nmsg, 2);
mode[0] = RSL_IE_RELEASE_MODE;
mode[1] = 1; /* local release */
- gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
+ gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, link_id);
/* in case of modify/hando: wait for confirm */
if (rr->modify_state)
@@ -4884,13 +5001,191 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
return -ENOMEM;
nrrh = (struct gsm48_rr_hdr *)nmsg->data;
nrrh->cause = RR_REL_CAUSE_LINK_FAILURE;
+ nrrh->sapi = link_id & 7;
gsm48_rr_upmsg(ms, nmsg);
- /* return idle */
- new_rr_state(rr, GSM48_RR_ST_IDLE);
+ /* only for main signalling link */
+ if ((link_id & 7) == 0) {
+ /* return idle */
+ new_rr_state(rr, GSM48_RR_ST_IDLE);
+ /* release SAPI 3 link, if exits */
+ gsm48_release_sapi3_link(ms);
+ } else {
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE);
+ LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 failed\n");
+ }
return 0;
}
+static int gsm48_rr_estab_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ uint8_t link_id = rllh->link_id;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ if (rr->state != GSM48_RR_ST_DEDICATED) {
+ /* disconnect sapi 3 link */
+ gsm48_release_sapi3_link(ms);
+ return -EINVAL;
+ }
+
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_ESTAB);
+ rr->sapi3_link_id = link_id; /* set link ID */
+
+ LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is established\n");
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->sapi = link_id & 7;
+
+ return gsm48_rr_upmsg(ms, nmsg);
+}
+
+static int gsm48_rr_estab_cnf_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ uint8_t link_id = rllh->link_id;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ if (rr->state != GSM48_RR_ST_DEDICATED) {
+ gsm48_release_sapi3_link(ms);
+ return -EINVAL;
+ }
+
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_ESTAB);
+ rr->sapi3_link_id = link_id; /* set link ID, just to be sure */
+
+ LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is established\n");
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_CNF);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->sapi = link_id & 7;
+
+ return gsm48_rr_upmsg(ms, nmsg);
+}
+
+/* 3.4.2 data from layer 2 to RR and upper layer (sapi 3)*/
+static int gsm48_rr_data_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ uint8_t sapi = rllh->link_id & 7;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_rr_hdr *rrh;
+ uint8_t pdisc = gh->proto_discr & 0x0f;
+
+ if (pdisc == GSM48_PDISC_RR) {
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ /* pull off RSL header up to L3 message */
+ msgb_pull(msg, (long)msgb_l3(msg) - (long)msg->data);
+
+ /* push RR header */
+ msgb_push(msg, sizeof(struct gsm48_rr_hdr));
+ rrh = (struct gsm48_rr_hdr *)msg->data;
+ rrh->msg_type = GSM48_RR_DATA_IND;
+ rrh->sapi = sapi;
+
+ return gsm48_rr_upmsg(ms, msg);
+}
+
+static int gsm48_rr_rel_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ uint8_t link_id = rllh->link_id;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE);
+
+ LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is released\n");
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_NORMAL;
+ nrrh->sapi = link_id & 7;
+
+ return gsm48_rr_upmsg(ms, nmsg);
+}
+
+/* request SAPI 3 establishment */
+static int gsm48_rr_est_req_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t ch_type, ch_subch, ch_ts;
+ struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
+ uint8_t sapi = rrh->sapi;
+ struct msgb *nmsg;
+
+ if (rr->state != GSM48_RR_ST_DEDICATED) {
+ struct gsm48_rr_hdr *nrrh;
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_NORMAL;
+ nrrh->sapi = sapi;
+ return gsm48_rr_upmsg(ms, nmsg);
+ }
+
+ rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ch_type != RSL_CHAN_Bm_ACCHs
+ && ch_type != RSL_CHAN_Lm_ACCHs) {
+ LOGP(DRR, LOGL_INFO, "Requesting DCCH link, because no TCH "
+ "(sapi %d)\n", sapi);
+ rr->sapi3_link_id = 0x00 | sapi; /* SAPI 3, DCCH */
+ } else {
+ LOGP(DRR, LOGL_INFO, "Requesting ACCH link, because TCH "
+ "(sapi %d)\n", sapi);
+ rr->sapi3_link_id = 0x40 | sapi; /* SAPI 3, ACCH */
+ }
+
+ /* already established */
+ new_sapi3_state(rr, GSM48_RR_SAPI3ST_WAIT_EST);
+
+ /* send message */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ return gsm48_send_rsl_nol3(ms, RSL_MT_EST_REQ, nmsg, rr->sapi3_link_id);
+}
+
+static int gsm48_rr_est_req_estab_sapi3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
+ uint8_t sapi = rrh->sapi;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ LOGP(DRR, LOGL_INFO, "Radio link SAPI3 already established\n");
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_CNF);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->sapi = sapi;
+
+ return gsm48_rr_upmsg(ms, nmsg);
+}
+
/*
* state machines
*/
@@ -4901,6 +5196,8 @@ static struct dldatastate {
int type;
int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} dldatastatelist[] = {
+ /* SAPI 0 on DCCH */
+
/* data transfer */
{SBIT(GSM48_RR_ST_IDLE) |
SBIT(GSM48_RR_ST_CONN_PEND) |
@@ -4950,35 +5247,79 @@ static struct dldatastate {
#define DLDATASLLEN \
(sizeof(dldatastatelist) / sizeof(struct dldatastate))
+static struct dldatastate dldatastatelists3[] = {
+ /* SAPI 3 on DCCH */
+
+ /* establish */
+ {SBIT(GSM48_RR_SAPI3ST_IDLE),
+ RSL_MT_EST_IND, gsm48_rr_estab_ind_sapi3},
+
+ /* establish */
+ {SBIT(GSM48_RR_SAPI3ST_IDLE) | SBIT(GSM48_RR_SAPI3ST_WAIT_EST),
+ RSL_MT_EST_CONF, gsm48_rr_estab_cnf_sapi3},
+
+ /* data transfer */
+ {SBIT(GSM48_RR_SAPI3ST_ESTAB),
+ RSL_MT_DATA_IND, gsm48_rr_data_ind_sapi3},
+
+ /* release */
+ {SBIT(GSM48_RR_SAPI3ST_WAIT_EST) | SBIT(GSM48_RR_SAPI3ST_ESTAB),
+ RSL_MT_REL_IND, gsm48_rr_rel_ind_sapi3},
+
+ {ALL_STATES,
+ RSL_MT_ERROR_IND, gsm48_rr_mdl_error_ind},
+};
+
+#define DLDATASLLENS3 \
+ (sizeof(dldatastatelists3) / sizeof(struct dldatastate))
+
static int gsm48_rcv_rll(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
int msg_type = rllh->c.msg_type;
+ int link_id = rllh->link_id;
int i;
int rc;
- if (msg_type != RSL_MT_UNIT_DATA_IND) {
- LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state "
- "%s\n", ms->name, rsl_msg_name(msg_type),
- gsm48_rr_state_names[rr->state]);
- }
+ LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state "
+ "%s (link_id 0x%x)\n", ms->name, rsl_msg_name(msg_type),
+ gsm48_rr_state_names[rr->state], link_id);
/* find function for current state and message */
- for (i = 0; i < DLDATASLLEN; i++)
- if ((msg_type == dldatastatelist[i].type)
- && ((1 << rr->state) & dldatastatelist[i].states))
- break;
- if (i == DLDATASLLEN) {
- LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n");
- msgb_free(msg);
- return 0;
- }
+ if (!(link_id & 7)) {
+ /* SAPI 0 */
+ for (i = 0; i < DLDATASLLEN; i++)
+ if ((msg_type == dldatastatelist[i].type)
+ && ((1 << rr->state) & dldatastatelist[i].states))
+ break;
+ if (i == DLDATASLLEN) {
+ LOGP(DRSL, LOGL_NOTICE, "RSLms message '%s' "
+ "unhandled\n", rsl_msg_name(msg_type));
+ msgb_free(msg);
+ return 0;
+ }
+
+ rc = dldatastatelist[i].rout(ms, msg);
+ } else {
+ /* SAPI 3 */
+ for (i = 0; i < DLDATASLLENS3; i++)
+ if ((msg_type == dldatastatelists3[i].type)
+ && ((1 << rr->sapi3_state) &
+ dldatastatelists3[i].states))
+ break;
+ if (i == DLDATASLLENS3) {
+ LOGP(DRSL, LOGL_NOTICE, "RSLms message '%s' "
+ "unhandled\n", rsl_msg_name(msg_type));
+ msgb_free(msg);
+ return 0;
+ }
- rc = dldatastatelist[i].rout(ms, msg);
+ rc = dldatastatelists3[i].rout(ms, msg);
+ }
/* free msgb unless it is forwarded */
- if (dldatastatelist[i].rout != gsm48_rr_data_ind)
+ if (msg_type != RSL_MT_DATA_IND)
msgb_free(msg);
return rc;
@@ -5033,12 +5374,14 @@ static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
return rc;
}
-/* state trasitions for RR-SAP messages from up */
+/* state trasitions for RR-SAP messages from up (main link) */
static struct rrdownstate {
uint32_t states;
int type;
int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} rrdownstatelist[] = {
+ /* SAPI 0 */
+
/* NOTE: If not IDLE, it is rejected there. */
{ALL_STATES, /* 3.3.1.1 */
GSM48_RR_EST_REQ, gsm48_rr_est_req},
@@ -5054,33 +5397,69 @@ static struct rrdownstate {
#define RRDOWNSLLEN \
(sizeof(rrdownstatelist) / sizeof(struct rrdownstate))
+/* state trasitions for RR-SAP messages from up with (SAPI 3) */
+static struct rrdownstate rrdownstatelists3[] = {
+ /* SAPI 3 */
+
+ {SBIT(GSM48_RR_SAPI3ST_IDLE),
+ GSM48_RR_EST_REQ, gsm48_rr_est_req_sapi3},
+
+ {SBIT(GSM48_RR_SAPI3ST_ESTAB),
+ GSM48_RR_EST_REQ, gsm48_rr_est_req_estab_sapi3},
+
+ {SBIT(GSM48_RR_SAPI3ST_ESTAB),
+ GSM48_RR_DATA_REQ, gsm48_rr_data_req}, /* handles SAPI 3 too */
+};
+
+#define RRDOWNSLLENS3 \
+ (sizeof(rrdownstatelists3) / sizeof(struct rrdownstate))
+
int gsm48_rr_downmsg(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
int msg_type = rrh->msg_type;
+ int sapi = rrh->sapi;
int i;
int rc;
- LOGP(DRR, LOGL_INFO, "(ms %s) Message '%s' received in state %s\n",
- ms->name, get_rr_name(msg_type),
- gsm48_rr_state_names[rr->state]);
+ LOGP(DRR, LOGL_INFO, "(ms %s) Message '%s' received in state %s "
+ "(sapi %d)\n", ms->name, get_rr_name(msg_type),
+ gsm48_rr_state_names[rr->state], sapi);
- /* find function for current state and message */
- for (i = 0; i < RRDOWNSLLEN; i++)
- if ((msg_type == rrdownstatelist[i].type)
- && ((1 << rr->state) & rrdownstatelist[i].states))
- break;
- if (i == RRDOWNSLLEN) {
- LOGP(DRR, LOGL_NOTICE, "Message unhandled at this state.\n");
- msgb_free(msg);
- return 0;
- }
+ if (!sapi) {
+ /* SAPI 0: find function for current state and message */
+ for (i = 0; i < RRDOWNSLLEN; i++)
+ if ((msg_type == rrdownstatelist[i].type)
+ && ((1 << rr->state) & rrdownstatelist[i].states))
+ break;
+ if (i == RRDOWNSLLEN) {
+ LOGP(DRR, LOGL_NOTICE, "Message unhandled at this "
+ "state.\n");
+ msgb_free(msg);
+ return 0;
+ }
- rc = rrdownstatelist[i].rout(ms, msg);
+ rc = rrdownstatelist[i].rout(ms, msg);
+ } else {
+ /* SAPI 3: find function for current state and message */
+ for (i = 0; i < RRDOWNSLLENS3; i++)
+ if ((msg_type == rrdownstatelists3[i].type)
+ && ((1 << rr->sapi3_state)
+ & rrdownstatelists3[i].states))
+ break;
+ if (i == RRDOWNSLLENS3) {
+ LOGP(DRR, LOGL_NOTICE, "Message unhandled at this "
+ "state.\n");
+ msgb_free(msg);
+ return 0;
+ }
- /* free msgb uless it is forwarded */
- if (rrdownstatelist[i].rout != gsm48_rr_data_req)
+ rc = rrdownstatelists3[i].rout(ms, msg);
+ }
+
+ /* free msgb unless it is forwarded */
+ if (msg_type != GSM48_RR_DATA_REQ)
msgb_free(msg);
return rc;
@@ -5166,7 +5545,7 @@ static void timeout_rr_t3124(void *arg)
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_REEST_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_REEST_REQ, nmsg, 0);
todo
}
@@ -5179,7 +5558,7 @@ static int gsm48_rr_tx_hando_access(struct osmocom_ms *ms)
return -ENOMEM;
*msgb_put(nmsg, 1) = rr->hando_ref;
todo burst
- return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg, 0);
}
/* send next channel request in dedicated state */
@@ -5239,8 +5618,7 @@ int gsm48_rr_tx_voice(struct osmocom_ms *ms, struct msgb *msg)
return -ENOTSUP;
}
- return l1ctl_tx_traffic_req(ms, msg, rr->cd_now.chan_nr,
- rr->cd_now.link_id);
+ return l1ctl_tx_traffic_req(ms, msg, rr->cd_now.chan_nr, 0);
}
int gsm48_rr_audio_mode(struct osmocom_ms *ms, uint8_t mode)
diff --git a/Src/osmolib/src/host/layer23/src/mobile/main.c b/Src/osmolib/src/host/layer23/src/mobile/main.c
index 6e743df..89c9b94 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/main.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/main.c
@@ -67,6 +67,9 @@ int mobile_work(struct osmocom_ms *ms);
int mobile_exit(struct osmocom_ms *ms, int force);
+const char *debug_default =
+ "DCS:DNB:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DSS:DLSMS:DPAG:DSUM";
+
const char *openbsc_copyright =
"Copyright (C) 2008-2010 ...\n"
"Contributions by ...\n\n"
@@ -87,7 +90,8 @@ static void print_help()
printf(" -i --gsmtap-ip The destination IP used for GSMTAP.\n");
printf(" -v --vty-port The VTY port number to telnet to. "
"(default %u)\n", vty_port);
- printf(" -d --debug Change debug flags.\n");
+ printf(" -d --debug Change debug flags. default: %s\n",
+ debug_default);
printf(" -D --daemonize Run as daemon\n");
printf(" -m --mncc-sock Disable built-in MNCC handler and "
"offer socket\n");
@@ -147,13 +151,30 @@ void sighandler(int sigset)
fprintf(stderr, "Signal %d received.\n", sigset);
- /* in case there is a lockup during exit */
- signal(SIGINT, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGPIPE, SIG_DFL);
-
- osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+ switch (sigset) {
+ case SIGINT:
+ /* If another signal is received afterwards, the program
+ * is terminated without finishing shutdown process.
+ */
+ signal(SIGINT, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+ signal(SIGUSR2, SIG_DFL);
+
+ osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+ break;
+ case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report
+ * and then return to the caller, who will abort the process
+ */
+ case SIGUSR1:
+ case SIGUSR2:
+ talloc_report_full(l23_ctx, stderr);
+ break;
+ }
}
int main(int argc, char **argv)
@@ -176,11 +197,12 @@ int main(int argc, char **argv)
log_set_all_filter(stderr_target, 1);
l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
+ msgb_set_talloc_ctx(l23_ctx);
handle_options(argc, argv);
if (!debug_set)
- log_parse_category_mask(stderr_target, "DCS:DNB:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
+ log_parse_category_mask(stderr_target, debug_default);
log_set_log_level(stderr_target, LOGL_DEBUG);
if (gsmtap_ip) {
@@ -214,6 +236,9 @@ int main(int argc, char **argv)
signal(SIGHUP, sighandler);
signal(SIGTERM, sighandler);
signal(SIGPIPE, sighandler);
+ signal(SIGABRT, sighandler);
+ signal(SIGUSR1, sighandler);
+ signal(SIGUSR2, sighandler);
if (daemonize) {
printf("Running as daemon\n");
@@ -231,5 +256,9 @@ int main(int argc, char **argv)
l23_app_exit();
+ talloc_free(config_file);
+ talloc_free(config_dir);
+ talloc_report_full(l23_ctx, stderr);
+
return 0;
}
diff --git a/Src/osmolib/src/host/layer23/src/mobile/mnccms.c b/Src/osmolib/src/host/layer23/src/mobile/mnccms.c
index c6db1ab..9fdc45f 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/mnccms.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/mnccms.c
@@ -187,7 +187,7 @@ static void mncc_set_bearer(struct osmocom_ms *ms, int8_t speech_ver,
LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
}
/* if specific speech_ver is given (it must be supported) */
- } else
+ } else
mncc->bearer_cap.speech_ver[i++] = speech_ver;
mncc->bearer_cap.speech_ver[i] = -1; /* end of list */
mncc->bearer_cap.transfer = 0;
@@ -579,7 +579,7 @@ int mncc_call(struct osmocom_ms *ms, char *number)
setup.called.plan = 1; /* ISDN */
strncpy(setup.called.number, number,
sizeof(setup.called.number) - 1);
-
+
/* bearer capability (mandatory) */
mncc_set_bearer(ms, -1, &setup);
if (ms->settings.clir)
diff --git a/Src/osmolib/src/host/layer23/src/mobile/settings.c b/Src/osmolib/src/host/layer23/src/mobile/settings.c
index 592f8a8..e34db7e 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/settings.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/settings.c
@@ -47,8 +47,7 @@ int gsm_settings_init(struct osmocom_ms *ms)
sprintf(set->imeisv, "0000000000000000");
/* SIM type */
-#warning TODO: Enable after SIM reader is available in master branch.
-// set->sim_type = SIM_TYPE_READER;
+ set->sim_type = GSM_SIM_TYPE_READER;
/* test SIM */
strcpy(set->test_imsi, "001010000000000");
@@ -183,7 +182,7 @@ int gsm_random_imei(struct gsm_settings *set)
strcpy(set->imei + 15 - digits, rand + 15 - digits);
strncpy(set->imeisv, set->imei, 15);
-
+
return 0;
}
diff --git a/Src/osmolib/src/host/layer23/src/mobile/subscriber.c b/Src/osmolib/src/host/layer23/src/mobile/subscriber.c
index 6de742a..8ebb173 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/subscriber.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/subscriber.c
@@ -320,9 +320,9 @@ static int subscr_sim_msisdn(struct osmocom_ms *ms, uint8_t *data,
return 0;
/* number */
- if (adn->ton_npi == 1)
+ if (((adn->ton_npi & 0x70) >> 4) == 1)
strcpy(subscr->msisdn, "+");
- if (adn->ton_npi == 2)
+ if (((adn->ton_npi & 0x70) >> 4) == 2)
strcpy(subscr->msisdn, "0");
strncat(subscr->msisdn, sim_decode_bcd(adn->number, adn->len_bcd - 1),
sizeof(subscr->msisdn) - 2);
@@ -332,6 +332,36 @@ static int subscr_sim_msisdn(struct osmocom_ms *ms, uint8_t *data,
return 0;
}
+static int subscr_sim_smsp(struct osmocom_ms *ms, uint8_t *data,
+ uint8_t length)
+{
+ struct gsm_subscriber *subscr = &ms->subscr;
+ struct gsm1111_ef_smsp *smsp;
+
+ if (length < sizeof(*smsp))
+ return -EINVAL;
+ smsp = (struct gsm1111_ef_smsp *) (data + length - sizeof(*smsp));
+
+ /* empty */
+ subscr->sms_sca[0] = '\0';
+
+ /* TS-Service Centre Address */
+ if (!(smsp->par_ind & 0x02) && smsp->ts_sca[0] <= 11) {
+ if (((smsp->ts_sca[1] & 0x70) >> 4) == 1)
+ strcpy(subscr->sms_sca, "+");
+ if (((smsp->ts_sca[1] & 0x70) >> 4) == 2)
+ strcpy(subscr->sms_sca, "0");
+ gsm48_decode_bcd_number(subscr->sms_sca +
+ strlen(subscr->sms_sca), sizeof(subscr->sms_sca)
+ - strlen(subscr->sms_sca), smsp->ts_sca, 1);
+ }
+
+ LOGP(DMM, LOGL_INFO, "received SMSP from SIM (sca=%s)\n",
+ subscr->sms_sca);
+
+ return 0;
+}
+
static int subscr_sim_kc(struct osmocom_ms *ms, uint8_t *data,
uint8_t length)
{
@@ -497,20 +527,22 @@ static struct subscr_sim_file {
uint8_t mandatory;
uint16_t path[MAX_SIM_PATH_LENGTH];
uint16_t file;
+ uint8_t sim_job;
int (*func)(struct osmocom_ms *ms, uint8_t *data,
uint8_t length);
} subscr_sim_files[] = {
- { 1, { 0 }, 0x2fe2, subscr_sim_iccid },
- { 1, { 0x7f20, 0 }, 0x6f07, subscr_sim_imsi },
- { 1, { 0x7f20, 0 }, 0x6f7e, subscr_sim_loci },
- { 0, { 0x7f10, 0 }, 0x6f40, subscr_sim_msisdn },
- { 0, { 0x7f20, 0 }, 0x6f20, subscr_sim_kc },
- { 0, { 0x7f20, 0 }, 0x6f30, subscr_sim_plmnsel },
- { 0, { 0x7f20, 0 }, 0x6f31, subscr_sim_hpplmn },
- { 0, { 0x7f20, 0 }, 0x6f46, subscr_sim_spn },
- { 0, { 0x7f20, 0 }, 0x6f78, subscr_sim_acc },
- { 0, { 0x7f20, 0 }, 0x6f7b, subscr_sim_fplmn },
- { 0, { 0 }, 0, NULL }
+ { 1, { 0 }, 0x2fe2, SIM_JOB_READ_BINARY, subscr_sim_iccid },
+ { 1, { 0x7f20, 0 }, 0x6f07, SIM_JOB_READ_BINARY, subscr_sim_imsi },
+ { 1, { 0x7f20, 0 }, 0x6f7e, SIM_JOB_READ_BINARY, subscr_sim_loci },
+ { 0, { 0x7f20, 0 }, 0x6f20, SIM_JOB_READ_BINARY, subscr_sim_kc },
+ { 0, { 0x7f20, 0 }, 0x6f30, SIM_JOB_READ_BINARY, subscr_sim_plmnsel },
+ { 0, { 0x7f20, 0 }, 0x6f31, SIM_JOB_READ_BINARY, subscr_sim_hpplmn },
+ { 0, { 0x7f20, 0 }, 0x6f46, SIM_JOB_READ_BINARY, subscr_sim_spn },
+ { 0, { 0x7f20, 0 }, 0x6f78, SIM_JOB_READ_BINARY, subscr_sim_acc },
+ { 0, { 0x7f20, 0 }, 0x6f7b, SIM_JOB_READ_BINARY, subscr_sim_fplmn },
+ { 0, { 0x7f10, 0 }, 0x6f40, SIM_JOB_READ_RECORD, subscr_sim_msisdn },
+ { 0, { 0x7f10, 0 }, 0x6f42, SIM_JOB_READ_RECORD, subscr_sim_smsp },
+ { 0, { 0 }, 0, 0, NULL }
};
/* request file from SIM */
@@ -553,7 +585,7 @@ static int subscr_sim_request(struct osmocom_ms *ms)
/* trigger SIM reading */
nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_query,
- SIM_JOB_READ_BINARY);
+ sf->sim_job);
if (!nmsg)
return -ENOMEM;
nsh = (struct sim_hdr *) nmsg->data;
@@ -564,6 +596,8 @@ static int subscr_sim_request(struct osmocom_ms *ms)
}
nsh->path[i] = 0; /* end of path */
nsh->file = sf->file;
+ nsh->rec_no = 1;
+ nsh->rec_mode = 0x04;
LOGP(DMM, LOGL_INFO, "Requesting SIM file 0x%04x\n", nsh->file);
sim_job(ms, nmsg);
@@ -1110,6 +1144,14 @@ int gsm_subscr_is_forbidden_plmn(struct gsm_subscriber *subscr, uint16_t mcc,
return 0;
}
+int gsm_subscr_get_key_seq(struct osmocom_ms *ms, struct gsm_subscriber *subscr)
+{
+ if (ms->settings.force_rekey)
+ return 7;
+ else
+ return subscr->key_seq;
+}
+
int gsm_subscr_dump_forbidden_plmn(struct osmocom_ms *ms,
void (*print)(void *, const char *, ...), void *priv)
{
@@ -1148,6 +1190,9 @@ void gsm_subscr_dump(struct gsm_subscriber *subscr,
print(priv, " Service Provider Name: %s\n", subscr->sim_spn);
if (subscr->msisdn[0])
print(priv, " MSISDN: %s\n", subscr->msisdn);
+ if (subscr->sms_sca[0])
+ print(priv, " SMS Service Center Address: %s\n",
+ subscr->sms_sca);
print(priv, " Status: %s IMSI %s", subscr_ustate_names[subscr->ustate],
(subscr->imsi_attached) ? "attached" : "detached");
if (subscr->tmsi != 0xffffffff)
diff --git a/Src/osmolib/src/host/layer23/src/mobile/support.c b/Src/osmolib/src/host/layer23/src/mobile/support.c
index c4269ac..bfc6180 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/support.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/support.c
@@ -41,7 +41,7 @@ void gsm_support_init(struct osmocom_ms *ms)
/* support of VBS */
sup->vbs = 0; /* no */
/* support of SMS */
- sup->sms_ptp = 0; /* no */
+ sup->sms_ptp = 1; /* no */
/* screening indicator */
sup->ss_ind = 1; /* phase 2 error handling */
/* pseudo synchronised capability */
diff --git a/Src/osmolib/src/host/layer23/src/mobile/transaction.c b/Src/osmolib/src/host/layer23/src/mobile/transaction.c
index 4b66050..45bf2b4 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/transaction.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/transaction.c
@@ -33,6 +33,8 @@
extern void *l23_ctx;
void _gsm48_cc_trans_free(struct gsm_trans *trans);
+void _gsm480_ss_trans_free(struct gsm_trans *trans);
+void _gsm411_sms_trans_free(struct gsm_trans *trans);
struct gsm_trans *trans_find_by_id(struct osmocom_ms *ms,
uint8_t proto, uint8_t trans_id)
@@ -90,14 +92,12 @@ void trans_free(struct gsm_trans *trans)
case GSM48_PDISC_CC:
_gsm48_cc_trans_free(trans);
break;
-#if 0
- case GSM48_PDISC_SS:
- _gsm411_ss_trans_free(trans);
+ case GSM48_PDISC_NC_SS:
+ _gsm480_ss_trans_free(trans);
break;
case GSM48_PDISC_SMS:
_gsm411_sms_trans_free(trans);
break;
-#endif
}
DEBUGP(DCC, "ms %s frees transaction (mem %p)\n", trans->ms->name,
@@ -108,7 +108,7 @@ void trans_free(struct gsm_trans *trans)
talloc_free(trans);
}
-/* allocate an unused transaction ID
+/* allocate an unused transaction ID
* in the given protocol using the ti_flag specified */
int trans_assign_trans_id(struct osmocom_ms *ms,
uint8_t protocol, uint8_t ti_flag)
diff --git a/Src/osmolib/src/host/layer23/src/mobile/vty_interface.c b/Src/osmolib/src/host/layer23/src/mobile/vty_interface.c
index c0a7cef..dc9e09d 100644
--- a/Src/osmolib/src/host/layer23/src/mobile/vty_interface.c
+++ b/Src/osmolib/src/host/layer23/src/mobile/vty_interface.c
@@ -37,6 +37,8 @@
#include <osmocom/bb/mobile/transaction.h>
#include <osmocom/bb/mobile/vty.h>
#include <osmocom/bb/mobile/app_mobile.h>
+#include <osmocom/bb/mobile/gsm480_ss.h>
+#include <osmocom/bb/mobile/gsm411_sms.h>
#include <osmocom/vty/telnet_interface.h>
void *l23_ctx;
@@ -837,6 +839,84 @@ DEFUN(call_dtmf, call_dtmf_cmd, "call MS_NAME dtmf DIGITS",
return CMD_SUCCESS;
}
+DEFUN(sms, sms_cmd, "sms MS_NAME NUMBER .LINE",
+ "Send an SMS\nName of MS (see \"show ms\")\nPhone number to send SMS "
+ "(Use digits '0123456789*#abc', and '+' to dial international)\n"
+ "SMS text\n")
+{
+ struct osmocom_ms *ms;
+ struct gsm_settings *set;
+ struct gsm_settings_abbrev *abbrev;
+ char *number, *sms_sca = NULL;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+ set = &ms->settings;
+
+ if (!set->sms_ptp) {
+ vty_out(vty, "SMS not supported by this mobile, please enable "
+ "SMS support%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ms->subscr.sms_sca[0])
+ sms_sca = ms->subscr.sms_sca;
+ else if (set->sms_sca[0])
+ sms_sca = set->sms_sca;
+
+ if (!sms_sca) {
+ vty_out(vty, "SMS sms-service-center not defined on SIM card, "
+ "please define one at settings.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ number = (char *)argv[1];
+ llist_for_each_entry(abbrev, &set->abbrev, list) {
+ if (!strcmp(number, abbrev->abbrev)) {
+ number = abbrev->number;
+ vty_out(vty, "Using number '%s'%s", number,
+ VTY_NEWLINE);
+ break;
+ }
+ }
+ if (vty_check_number(vty, number))
+ return CMD_WARNING;
+
+ sms_send(ms, sms_sca, number, argv_concat(argv, argc, 2));
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(service, service_cmd, "service MS_NAME (*#06#|*#21#|*#67#|*#61#|*#62#"
+ "|*#002#|*#004#|*xx*number#|*xx#|#xx#|##xx#|STRING|hangup)",
+ "Send a Supplementary Service request\nName of MS (see \"show ms\")\n"
+ "Query IMSI\n"
+ "Query Call Forwarding Unconditional (CFU)\n"
+ "Query Call Forwarding when Busy (CFB)\n"
+ "Query Call Forwarding when No Response (CFNR)\n"
+ "Query Call Forwarding when Not Reachable\n"
+ "Query all Call Forwardings\n"
+ "Query all conditional Call Forwardings\n"
+ "Set and activate Call Forwarding (xx = Service Code, see above)\n"
+ "Activate Call Forwarding (xx = Service Code, see above)\n"
+ "Deactivate Call Forwarding (xx = Service Code, see above)\n"
+ "Erase and deactivate Call Forwarding (xx = Service Code, see above)\n"
+ "Service string "
+ "(Example: '*100#' requests account balace on some networks.)\n"
+ "Hangup existing service connection")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ ss_send(ms, argv[1], 0);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(test_reselection, test_reselection_cmd, "test re-selection NAME",
"Manually trigger cell re-selection\nName of MS (see \"show ms\")")
{
@@ -1208,12 +1288,21 @@ static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
else
if (!hide_default)
vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE);
+ if (set->sms_sca[0])
+ vty_out(vty, " sms-service-center %s%s", set->sms_sca,
+ VTY_NEWLINE);
+ else
+ if (!hide_default)
+ vty_out(vty, " no sms-service-center%s", VTY_NEWLINE);
if (!hide_default || set->cw)
vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ",
VTY_NEWLINE);
if (!hide_default || set->auto_answer)
vty_out(vty, " %sauto-answer%s",
(set->auto_answer) ? "" : "no ", VTY_NEWLINE);
+ if (!hide_default || set->force_rekey)
+ vty_out(vty, " %sforce-rekey%s",
+ (set->force_rekey) ? "" : "no ", VTY_NEWLINE);
if (!hide_default || set->clip)
vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ",
VTY_NEWLINE);
@@ -1569,6 +1658,37 @@ DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
return CMD_SUCCESS;
}
+DEFUN(cfg_ms_sms_sca, cfg_ms_sms_sca_cmd, "sms-service-center NUMBER",
+ "Use Service center address for outgoing SMS\nNumber of service center "
+ "(Use digits '0123456789*#abc', and '+' to dial international)")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+ const char *number = argv[0];
+
+ if ((strlen(number) > 20 && number[0] != '+') || strlen(number) > 21) {
+ vty_out(vty, "Number too long%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (vty_check_number(vty, number))
+ return CMD_WARNING;
+
+ strcpy(set->sms_sca, number);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_sms_sca, cfg_ms_no_sms_sca_cmd, "no sms-service-center",
+ NO_STR "Use Service center address for outgoing SMS")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->sms_sca[0] = '\0';
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
NO_STR "Disallow waiting calls")
{
@@ -1613,6 +1733,28 @@ DEFUN(cfg_auto_answer, cfg_ms_auto_answer_cmd, "auto-answer",
return CMD_SUCCESS;
}
+DEFUN(cfg_no_force_rekey, cfg_ms_no_force_rekey_cmd, "no force-rekey",
+ NO_STR "Disable key renew forcing after every event")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->force_rekey = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_force_rekey, cfg_ms_force_rekey_cmd, "force-rekey",
+ "Enable key renew forcing after every event")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->force_rekey = 1;
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip",
"Force caller ID presentation")
{
@@ -2624,6 +2766,8 @@ int ms_vty_init(void)
install_element(ENABLE_NODE, &call_cmd);
install_element(ENABLE_NODE, &call_retr_cmd);
install_element(ENABLE_NODE, &call_dtmf_cmd);
+ install_element(ENABLE_NODE, &sms_cmd);
+ install_element(ENABLE_NODE, &service_cmd);
install_element(ENABLE_NODE, &test_reselection_cmd);
install_element(ENABLE_NODE, &delete_forbidden_plmn_cmd);
@@ -2657,10 +2801,14 @@ int ms_vty_init(void)
install_element(MS_NODE, &cfg_ms_imei_random_cmd);
install_element(MS_NODE, &cfg_ms_no_emerg_imsi_cmd);
install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd);
+ install_element(MS_NODE, &cfg_ms_no_sms_sca_cmd);
+ install_element(MS_NODE, &cfg_ms_sms_sca_cmd);
install_element(MS_NODE, &cfg_ms_cw_cmd);
install_element(MS_NODE, &cfg_ms_no_cw_cmd);
install_element(MS_NODE, &cfg_ms_auto_answer_cmd);
install_element(MS_NODE, &cfg_ms_no_auto_answer_cmd);
+ install_element(MS_NODE, &cfg_ms_force_rekey_cmd);
+ install_element(MS_NODE, &cfg_ms_no_force_rekey_cmd);
install_element(MS_NODE, &cfg_ms_clip_cmd);
install_element(MS_NODE, &cfg_ms_clir_cmd);
install_element(MS_NODE, &cfg_ms_no_clip_cmd);