aboutsummaryrefslogtreecommitdiffstats
path: root/tests/sgsn
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sgsn')
-rw-r--r--tests/sgsn/Makefile.am26
-rw-r--r--tests/sgsn/gprs_gb_parse.c688
-rw-r--r--tests/sgsn/gprs_gb_parse.h61
-rw-r--r--tests/sgsn/sgsn_test.c93
4 files changed, 816 insertions, 52 deletions
diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am
index b72c44634..c6c1f4a68 100644
--- a/tests/sgsn/Makefile.am
+++ b/tests/sgsn/Makefile.am
@@ -7,6 +7,7 @@ AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOGSUPCLIENT_CFLAGS) \
@@ -21,16 +22,23 @@ AM_CFLAGS += \
$(NULL)
endif
+AM_LDFLAGS = -no-install
+
EXTRA_DIST = \
sgsn_test.ok \
$(NULL)
-noinst_PROGRAMS = \
+check_PROGRAMS = \
sgsn_test \
$(NULL)
+noinst_HEADERS = \
+ gprs_gb_parse.h \
+ $(NULL)
+
sgsn_test_SOURCES = \
sgsn_test.c \
+ gprs_gb_parse.c \
$(NULL)
sgsn_test_LDFLAGS = \
@@ -39,17 +47,26 @@ sgsn_test_LDFLAGS = \
-Wl,--wrap=gprs_subscr_request_update_location \
-Wl,--wrap=gprs_subscr_request_auth_info \
-Wl,--wrap=osmo_gsup_client_send \
+ $(AM_LDFLAGS) \
$(NULL)
sgsn_test_LDADD = \
+ $(top_builddir)/src/sgsn/apn.o \
+ $(top_builddir)/src/sgsn/gprs_bssgp.o \
$(top_builddir)/src/sgsn/gprs_llc.o \
- $(top_builddir)/src/sgsn/gprs_gb.o \
+ $(top_builddir)/src/sgsn/gprs_ns.o \
$(top_builddir)/src/sgsn/gprs_sndcp.o \
$(top_builddir)/src/sgsn/gprs_gmm_attach.o \
$(top_builddir)/src/sgsn/gprs_gmm.o \
$(top_builddir)/src/sgsn/gprs_gmm_fsm.o \
$(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \
- $(top_builddir)/src/sgsn/gprs_sgsn.o \
+ $(top_builddir)/src/sgsn/gtp_ggsn.o \
+ $(top_builddir)/src/sgsn/gtp_mme.o \
+ $(top_builddir)/src/sgsn/mmctx.o \
+ $(top_builddir)/src/sgsn/pdpctx.o \
+ $(top_builddir)/src/sgsn/sgsn.o \
+ $(top_builddir)/src/sgsn/sgsn_cdr.o \
+ $(top_builddir)/src/sgsn/sgsn_ctrl.o \
$(top_builddir)/src/sgsn/sgsn_vty.o \
$(top_builddir)/src/sgsn/sgsn_libgtp.o \
$(top_builddir)/src/sgsn/sgsn_auth.o \
@@ -62,13 +79,14 @@ sgsn_test_LDADD = \
$(top_builddir)/src/sgsn/gprs_sndcp_pcomp.o \
$(top_builddir)/src/sgsn/v42bis.o \
$(top_builddir)/src/sgsn/gprs_sndcp_dcomp.o \
+ $(top_builddir)/src/sgsn/sgsn_rim.o \
$(top_builddir)/src/gprs/gprs_utils.o \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
- $(top_builddir)/src/gprs/gprs_gb_parse.o \
$(top_builddir)/src/gprs/crc24.o \
$(top_builddir)/src/gprs/sgsn_ares.o \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOGSUPCLIENT_LIBS) \
diff --git a/tests/sgsn/gprs_gb_parse.c b/tests/sgsn/gprs_gb_parse.c
new file mode 100644
index 000000000..670839f73
--- /dev/null
+++ b/tests/sgsn/gprs_gb_parse.c
@@ -0,0 +1,688 @@
+/* GPRS Gb message parser */
+
+/* (C) 2014 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <arpa/inet.h>
+
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
+
+#include "gprs_gb_parse.h"
+
+#include <osmocom/sgsn/gprs_utils.h>
+
+#include <osmocom/sgsn/debug.h>
+
+#include <osmocom/gprs/gprs_bssgp.h>
+
+static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "ATTACH_REQ";
+
+ /* Skip MS network capability */
+ if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
+ value_len < 1 || value_len > 8)
+ /* invalid */
+ return 0;
+
+ /* Skip Attach type */
+ /* Skip Ciphering key sequence number */
+ /* Skip DRX parameter */
+ if (osmo_shift_v_fixed(&data, &data_len, 3, NULL) < 3)
+ return 0;
+
+ /* Get Mobile identity */
+ if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
+ value_len < 5 || value_len > 8)
+ /* invalid */
+ return 0;
+
+ if (gprs_is_mi_tmsi(value, value_len)) {
+ parse_ctx->ptmsi_enc = value + 1;
+ } else if (gprs_is_mi_imsi(value, value_len)) {
+ parse_ctx->imsi = value;
+ parse_ctx->imsi_len = value_len;
+ }
+
+ if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
+ return 0;
+
+ parse_ctx->old_raid_enc = value;
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "ATTACH_ACK";
+
+ /* Skip Attach result */
+ /* Skip Force to standby */
+ /* Skip Periodic RA update timer */
+ /* Skip Radio priority for SMS */
+ /* Skip Spare half octet */
+ if (osmo_shift_v_fixed(&data, &data_len, 3, NULL) < 3)
+ return 0;
+
+ if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
+ return 0;
+
+ parse_ctx->raid_enc = value;
+
+ /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
+ osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
+
+ /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */
+ osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL);
+
+ /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
+ if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
+ &value, &value_len) > 0 &&
+ gprs_is_mi_tmsi(value, value_len))
+ parse_ctx->new_ptmsi_enc = value + 1;
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_attach_rej(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+
+ parse_ctx->llc_msg_name = "ATTACH_REJ";
+
+ /* GMM cause */
+ if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
+ return 0;
+
+ parse_ctx->invalidate_tlli = 1;
+
+ return 1;
+}
+
+
+static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+ int detach_type;
+ int power_off;
+
+ parse_ctx->llc_msg_name = "DETACH_REQ";
+
+ /* Skip spare half octet */
+ /* Get Detach type */
+ if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
+ /* invalid */
+ return 0;
+
+ detach_type = *value & 0x07;
+ power_off = *value & 0x08 ? 1 : 0;
+
+ if (parse_ctx->to_bss) {
+ /* Network originated */
+ if (detach_type == GPRS_DET_T_MT_REATT_REQ)
+ parse_ctx->await_reattach = 1;
+ } else {
+ /* Mobile originated */
+
+ if (power_off)
+ parse_ctx->invalidate_tlli = 1;
+
+ /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */
+ if (osmo_match_shift_tlv(&data, &data_len,
+ GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0)
+ {
+ if (gprs_is_mi_tmsi(value, value_len))
+ parse_ctx->ptmsi_enc = value + 1;
+ }
+ }
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+
+ parse_ctx->llc_msg_name = "RA_UPD_REQ";
+
+ /* Skip Update type */
+ /* Skip GPRS ciphering key sequence number */
+ if (osmo_shift_v_fixed(&data, &data_len, 1, NULL) < 1)
+ return 0;
+
+ if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
+ return 0;
+
+ parse_ctx->old_raid_enc = value;
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_ra_upd_rej(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ uint8_t cause;
+ int force_standby;
+
+ parse_ctx->llc_msg_name = "RA_UPD_REJ";
+
+ /* GMM cause */
+ if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
+ return 0;
+
+ cause = value[0];
+
+ /* Force to standby, 1/2 */
+ /* spare bits, 1/2 */
+ if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
+ return 0;
+
+ force_standby = (value[0] & 0x07) == 0x01;
+
+ if (cause == GMM_CAUSE_IMPL_DETACHED && !force_standby)
+ parse_ctx->await_reattach = 1;
+
+ parse_ctx->invalidate_tlli = 1;
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "RA_UPD_ACK";
+
+ /* Skip Force to standby */
+ /* Skip Update result */
+ /* Skip Periodic RA update timer */
+ if (osmo_shift_v_fixed(&data, &data_len, 2, NULL) < 2)
+ return 0;
+
+ if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
+ return 0;
+
+ parse_ctx->raid_enc = value;
+
+ /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
+ osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
+
+ /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
+ if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
+ &value, &value_len) > 0 &&
+ gprs_is_mi_tmsi(value, value_len))
+ parse_ctx->new_ptmsi_enc = value + 1;
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "PTMSI_REALL_CMD";
+
+ LOGP(DLLC, LOGL_NOTICE,
+ "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n");
+
+ /* Allocated P-TMSI */
+ if (osmo_shift_lv(&data, &data_len, &value, &value_len) > 0 &&
+ gprs_is_mi_tmsi(value, value_len))
+ parse_ctx->new_ptmsi_enc = value + 1;
+
+ if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
+ return 0;
+
+ parse_ctx->raid_enc = value;
+
+ return 1;
+}
+
+static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "ID_RESP";
+
+ /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */
+ if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
+ value_len < 1 || value_len > 9)
+ /* invalid */
+ return 0;
+
+ if (gprs_is_mi_tmsi(value, value_len)) {
+ parse_ctx->ptmsi_enc = value + 1;
+ } else if (gprs_is_mi_imsi(value, value_len)) {
+ parse_ctx->imsi = value;
+ parse_ctx->imsi_len = value_len;
+ }
+
+ return 1;
+}
+
+static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ ssize_t old_len;
+ uint8_t *value;
+ size_t value_len;
+
+ parse_ctx->llc_msg_name = "ACT_PDP_REQ";
+
+ /* Skip Requested NSAPI */
+ /* Skip Requested LLC SAPI */
+ if (osmo_shift_v_fixed(&data, &data_len, 2, NULL) < 2)
+ return 0;
+
+ /* Skip Requested QoS (support 04.08 and 24.008) */
+ if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
+ value_len < 4 || value_len > 14)
+ /* invalid */
+ return 0;
+
+ /* Skip Requested PDP address */
+ if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
+ value_len < 2 || value_len > 18)
+ /* invalid */
+ return 0;
+
+ /* Access point name */
+ old_len = osmo_match_shift_tlv(&data, &data_len,
+ GSM48_IE_GSM_APN, &value, &value_len);
+
+ if (old_len > 0 && value_len >=1 && value_len <= 100) {
+ parse_ctx->apn_ie = data - old_len;
+ parse_ctx->apn_ie_len = old_len;
+ }
+
+ return 1;
+}
+
+int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ struct gsm48_hdr *g48h;
+ uint8_t pdisc;
+ uint8_t msg_type;
+
+ if (osmo_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0)
+ return 0;
+
+ parse_ctx->g48_hdr = g48h;
+
+ pdisc = gsm48_hdr_pdisc(g48h);
+ if (pdisc != GSM48_PDISC_MM_GPRS && pdisc != GSM48_PDISC_SM_GPRS)
+ return 1;
+
+ msg_type = gsm48_hdr_msg_type(g48h);
+ switch (msg_type) {
+ case GSM48_MT_GMM_ATTACH_REQ:
+ return gprs_gb_parse_gmm_attach_req(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_ATTACH_REJ:
+ return gprs_gb_parse_gmm_attach_rej(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_ATTACH_ACK:
+ return gprs_gb_parse_gmm_attach_ack(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_RA_UPD_REQ:
+ return gprs_gb_parse_gmm_ra_upd_req(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_RA_UPD_REJ:
+ return gprs_gb_parse_gmm_ra_upd_rej(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_RA_UPD_ACK:
+ return gprs_gb_parse_gmm_ra_upd_ack(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_PTMSI_REALL_CMD:
+ return gprs_gb_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx);
+
+ case GSM48_MT_GSM_ACT_PDP_REQ:
+ return gprs_gb_parse_gsm_act_pdp_req(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_ID_RESP:
+ return gprs_gb_parse_gmm_id_resp(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_DETACH_REQ:
+ return gprs_gb_parse_gmm_detach_req(data, data_len, parse_ctx);
+
+ case GSM48_MT_GMM_DETACH_ACK:
+ parse_ctx->llc_msg_name = "DETACH_ACK";
+ parse_ctx->invalidate_tlli = 1;
+ break;
+
+ case GSM48_MT_GSM_DEACT_PDP_REQ:
+ parse_ctx->llc_msg_name = "DEACT_PDP_REQ";
+ break;
+
+ case GSM48_MT_GSM_DEACT_PDP_ACK:
+ parse_ctx->llc_msg_name = "DEACT_PDP_ACK";
+ break;
+
+ default:
+ LOGP(DLLC, LOGL_NOTICE,
+ "Unhandled GSM 04.08 message type %s for protocol discriminator %s.\n",
+ get_value_string(gprs_msgt_gmm_names, msg_type), get_value_string(gsm48_pdisc_names, pdisc));
+ break;
+ };
+
+ return 1;
+}
+
+int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
+ int rc;
+ int fcs;
+
+ /* parse LLC */
+ rc = gprs_llc_hdr_parse(ghp, llc, llc_len);
+ gprs_llc_hdr_dump(ghp, NULL);
+ if (rc != 0) {
+ LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
+ return 0;
+ }
+
+ fcs = gprs_llc_fcs(llc, ghp->crc_length);
+ LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n",
+ ghp->fcs, fcs);
+
+ if (!ghp->data)
+ return 0;
+
+ if (ghp->sapi != GPRS_SAPI_GMM)
+ return 1;
+
+ if (ghp->cmd != GPRS_LLC_UI)
+ return 1;
+
+ if (ghp->is_encrypted) {
+ parse_ctx->need_decryption = 1;
+ return 0;
+ }
+
+ return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
+}
+
+/*! Determine the TLLI from the given BSSGP message.
+ * \param[in] bssgp pointer to start of BSSGP header
+ * \param[in] bssgp_len length of BSSGP message in octets
+ * \param[out] tlli TLLI (if any) in host byte order
+ * \returns 1 if TLLI found; 0 if none found; negative on parse error */
+int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli)
+{
+ const struct bssgp_normal_hdr *bgph;
+ uint8_t pdu_type;
+
+ if (bssgp_len < sizeof(struct bssgp_normal_hdr))
+ return -EINVAL;
+
+ bgph = (struct bssgp_normal_hdr *)bssgp;
+ pdu_type = bgph->pdu_type;
+
+ if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
+ pdu_type == BSSGP_PDUT_DL_UNITDATA) {
+ const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *)bssgp;
+ if (bssgp_len < sizeof(struct bssgp_ud_hdr))
+ return -EINVAL;
+ *tlli = osmo_load32be((const uint8_t *)&budh->tlli);
+ return 1;
+ } else {
+ const uint8_t *data = bgph->data;
+ size_t data_len = bssgp_len - sizeof(*bgph);
+ struct tlv_parsed tp;
+
+ if (bssgp_tlv_parse(&tp, data, data_len) < 0)
+ return -EINVAL;
+
+ if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
+ *tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
+ return 1;
+ }
+ }
+
+ /* No TLLI present in message */
+ return 0;
+}
+
+int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ struct bssgp_normal_hdr *bgph;
+ struct bssgp_ud_hdr *budh = NULL;
+ struct tlv_parsed *tp = &parse_ctx->bssgp_tp;
+ uint8_t pdu_type;
+ uint8_t *data;
+ size_t data_len;
+ int rc;
+
+ if (bssgp_len < sizeof(struct bssgp_normal_hdr))
+ return 0;
+
+ bgph = (struct bssgp_normal_hdr *)bssgp;
+ pdu_type = bgph->pdu_type;
+
+ if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
+ pdu_type == BSSGP_PDUT_DL_UNITDATA) {
+ if (bssgp_len < sizeof(struct bssgp_ud_hdr))
+ return 0;
+ budh = (struct bssgp_ud_hdr *)bssgp;
+ bgph = NULL;
+ data = budh->data;
+ data_len = bssgp_len - sizeof(*budh);
+ } else {
+ data = bgph->data;
+ data_len = bssgp_len - sizeof(*bgph);
+ }
+
+ parse_ctx->pdu_type = pdu_type;
+ parse_ctx->bud_hdr = budh;
+ parse_ctx->bgp_hdr = bgph;
+ parse_ctx->bssgp_data = data;
+ parse_ctx->bssgp_data_len = data_len;
+
+ if (bssgp_tlv_parse(tp, data, data_len) < 0)
+ return 0;
+
+ if (budh)
+ parse_ctx->tlli_enc = (uint8_t *)&budh->tlli;
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA))
+ parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID))
+ parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID);
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) {
+ parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI);
+ parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
+ }
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) {
+ if (parse_ctx->tlli_enc)
+ /* This is TLLI old, don't confuse it with TLLI current */
+ parse_ctx->old_tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
+ else
+ parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
+ }
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS)
+ parse_ctx->bssgp_ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI);
+
+ if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) {
+ uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
+ size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
+
+ rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx);
+ if (!rc)
+ return 0;
+
+ parse_ctx->llc = llc;
+ parse_ctx->llc_len = llc_len;
+ }
+
+ if (parse_ctx->tlli_enc) {
+ uint32_t tmp_tlli;
+ memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli));
+ parse_ctx->tlli = ntohl(tmp_tlli);
+ }
+
+ if (parse_ctx->bssgp_raid_enc && parse_ctx->old_raid_enc &&
+ memcmp(parse_ctx->bssgp_raid_enc, parse_ctx->old_raid_enc, 6) != 0)
+ parse_ctx->old_raid_is_foreign = 1;
+
+ return 1;
+}
+
+void gprs_gb_log_parse_context(int log_level,
+ struct gprs_gb_parse_context *parse_ctx,
+ const char *default_msg_name)
+{
+ const char *msg_name;
+ const char *sep = "";
+
+ if (!parse_ctx->tlli_enc &&
+ !parse_ctx->ptmsi_enc &&
+ !parse_ctx->new_ptmsi_enc &&
+ !parse_ctx->bssgp_ptmsi_enc &&
+ !parse_ctx->imsi)
+ return;
+
+ msg_name = gprs_gb_message_name(parse_ctx, default_msg_name);
+
+ if (parse_ctx->llc_msg_name)
+ msg_name = parse_ctx->llc_msg_name;
+
+ LOGP(DGPRS, log_level, "%s: Got", msg_name);
+
+ if (parse_ctx->tlli_enc) {
+ LOGPC(DGPRS, log_level, "%s TLLI %08x", sep, parse_ctx->tlli);
+ sep = ",";
+ }
+
+ if (parse_ctx->old_tlli_enc) {
+ LOGPC(DGPRS, log_level, "%s old TLLI %02x%02x%02x%02x", sep,
+ parse_ctx->old_tlli_enc[0],
+ parse_ctx->old_tlli_enc[1],
+ parse_ctx->old_tlli_enc[2],
+ parse_ctx->old_tlli_enc[3]);
+ sep = ",";
+ }
+
+ if (parse_ctx->bssgp_raid_enc) {
+ struct gprs_ra_id raid;
+ gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc);
+ LOGPC(DGPRS, log_level, "%s BSSGP RAID %s", sep, osmo_rai_name(&raid));
+ sep = ",";
+ }
+
+ if (parse_ctx->raid_enc) {
+ struct gprs_ra_id raid;
+ gsm48_parse_ra(&raid, parse_ctx->raid_enc);
+ LOGPC(DGPRS, log_level, "%s RAID %s", sep, osmo_rai_name(&raid));
+ sep = ",";
+ }
+
+ if (parse_ctx->old_raid_enc) {
+ struct gprs_ra_id raid;
+ gsm48_parse_ra(&raid, parse_ctx->old_raid_enc);
+ LOGPC(DGPRS, log_level, "%s old RAID %s", sep, osmo_rai_name(&raid));
+ sep = ",";
+ }
+
+ if (parse_ctx->bssgp_ptmsi_enc) {
+ uint32_t ptmsi = GSM_RESERVED_TMSI;
+ gprs_parse_tmsi(parse_ctx->bssgp_ptmsi_enc, &ptmsi);
+ LOGPC(DGPRS, log_level, "%s BSSGP PTMSI %08x", sep, ptmsi);
+ sep = ",";
+ }
+
+ if (parse_ctx->ptmsi_enc) {
+ uint32_t ptmsi = GSM_RESERVED_TMSI;
+ gprs_parse_tmsi(parse_ctx->ptmsi_enc, &ptmsi);
+ LOGPC(DGPRS, log_level, "%s PTMSI %08x", sep, ptmsi);
+ sep = ",";
+ }
+
+ if (parse_ctx->new_ptmsi_enc) {
+ uint32_t new_ptmsi = GSM_RESERVED_TMSI;
+ gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
+ LOGPC(DGPRS, log_level, "%s new PTMSI %08x", sep, new_ptmsi);
+ sep = ",";
+ }
+
+ if (parse_ctx->imsi) {
+ struct osmo_mobile_identity mi;
+ if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0
+ && mi.type == GSM_MI_TYPE_IMSI) {
+ LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);
+ sep = ",";
+ }
+ }
+ if (parse_ctx->invalidate_tlli) {
+ LOGPC(DGPRS, log_level, "%s invalidate", sep);
+ sep = ",";
+ }
+ if (parse_ctx->await_reattach) {
+ LOGPC(DGPRS, log_level, "%s re-attach", sep);
+ sep = ",";
+ }
+
+ LOGPC(DGPRS, log_level, "\n");
+}
+
+const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
+ const char *default_msg_name)
+{
+ if (parse_ctx->llc_msg_name)
+ return parse_ctx->llc_msg_name;
+
+ if (parse_ctx->g48_hdr)
+ return "GMM";
+
+ if (parse_ctx->llc)
+ return "LLC";
+
+ if (parse_ctx->bud_hdr)
+ return "BSSGP-UNITDATA";
+
+ if (parse_ctx->bgp_hdr)
+ return "BSSGP";
+
+ return "unknown";
+}
diff --git a/tests/sgsn/gprs_gb_parse.h b/tests/sgsn/gprs_gb_parse.h
new file mode 100644
index 000000000..58de17f81
--- /dev/null
+++ b/tests/sgsn/gprs_gb_parse.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <osmocom/sgsn/gprs_llc.h>
+
+#include <sys/types.h>
+
+struct gprs_gb_parse_context {
+ /* Pointer to protocol specific parts */
+ struct gsm48_hdr *g48_hdr;
+ struct bssgp_normal_hdr *bgp_hdr;
+ struct bssgp_ud_hdr *bud_hdr;
+ uint8_t *bssgp_data;
+ size_t bssgp_data_len;
+ uint8_t *llc;
+ size_t llc_len;
+
+ /* Extracted information */
+ struct gprs_llc_hdr_parsed llc_hdr_parsed;
+ struct tlv_parsed bssgp_tp;
+ int to_bss;
+ uint8_t *tlli_enc;
+ uint8_t *old_tlli_enc;
+ uint8_t *imsi;
+ size_t imsi_len;
+ uint8_t *apn_ie;
+ size_t apn_ie_len;
+ uint8_t *ptmsi_enc;
+ uint8_t *new_ptmsi_enc;
+ uint8_t *raid_enc;
+ uint8_t *old_raid_enc;
+ uint8_t *bssgp_raid_enc;
+ uint8_t *bssgp_ptmsi_enc;
+
+ /* General info */
+ const char *llc_msg_name;
+ int invalidate_tlli;
+ int await_reattach;
+ int need_decryption;
+ uint32_t tlli;
+ int pdu_type;
+ int old_raid_is_foreign;
+ int peer_nsei;
+};
+
+int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
+ struct gprs_gb_parse_context *parse_ctx);
+
+int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
+ struct gprs_gb_parse_context *parse_ctx);
+
+int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
+ struct gprs_gb_parse_context *parse_ctx);
+
+int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli);
+
+const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
+ const char *default_msg_name);
+
+void gprs_gb_log_parse_context(int log_level,
+ struct gprs_gb_parse_context *parse_ctx,
+ const char *default_msg_name);
diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c
index 057462062..a149b8e2c 100644
--- a/tests/sgsn/sgsn_test.c
+++ b/tests/sgsn/sgsn_test.c
@@ -19,43 +19,38 @@
*
*/
+#include <osmocom/core/application.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/apn.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsup.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/gsupclient/gsup_client.h>
+
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_subscriber.h>
-#include <osmocom/gsm/gsup.h>
-#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/gprs_utils.h>
-#include <osmocom/sgsn/gprs_gb_parse.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
-
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/vty/vty.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
#include <stdio.h>
+#include "gprs_gb_parse.h"
+
void *tall_sgsn_ctx;
-static struct sgsn_instance sgsn_inst = {
- .config_file = "osmo_sgsn.cfg",
- .cfg = {
- .gtp_statedir = "./",
- .auth_policy = SGSN_AUTH_POLICY_CLOSED,
- },
-};
-struct sgsn_instance *sgsn = &sgsn_inst;
+struct sgsn_instance *sgsn;
unsigned sgsn_tx_counter = 0;
struct msgb *last_msg = NULL;
struct gprs_gb_parse_context last_dl_parse_ctx;
-static void reset_last_msg()
+static void reset_last_msg(void)
{
if (last_msg)
msgb_free(last_msg);
@@ -64,9 +59,10 @@ static void reset_last_msg()
memset(&last_dl_parse_ctx, 0, sizeof(last_dl_parse_ctx));
}
-static void cleanup_test()
+static void cleanup_test(void)
{
reset_last_msg();
+ TALLOC_FREE(sgsn);
}
static uint32_t get_new_ptmsi(const struct gprs_gb_parse_context *parse_ctx)
@@ -281,7 +277,7 @@ static void show_subscrs(FILE *out)
}
}
-static void assert_no_subscrs()
+static void assert_no_subscrs(void)
{
show_subscrs(stdout);
fflush(stdout);
@@ -383,6 +379,7 @@ static void test_auth_triplets(void)
uint32_t local_tlli = 0xffeeddcc;
printf("Testing authentication triplet handling\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -571,6 +568,7 @@ static void test_subscriber_gsup(void)
printf("Testing subscriber GSUP handling\n");
update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data;
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -747,6 +745,7 @@ static void test_gmm_detach(void)
uint32_t local_tlli;
printf("Testing GMM detach\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 0 */
@@ -788,6 +787,7 @@ static void test_gmm_detach_power_off(void)
uint32_t local_tlli;
printf("Testing GMM detach (power off)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 1 */
@@ -828,6 +828,7 @@ static void test_gmm_detach_no_mmctx(void)
uint32_t local_tlli;
printf("Testing GMM detach (no MMCTX)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 0 */
@@ -864,6 +865,7 @@ static void test_gmm_detach_accept_unexpected(void)
uint32_t local_tlli;
printf("Testing GMM detach accept (unexpected)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Accept (MT) */
/* normal detach */
@@ -900,6 +902,7 @@ static void test_gmm_status_no_mmctx(void)
uint32_t local_tlli;
printf("Testing GMM Status (no MMCTX)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - GMM Status, protocol error */
static const unsigned char gmm_status[] = {
@@ -1194,6 +1197,7 @@ static void test_gmm_reject(void)
};
printf("Testing GMM reject\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* reset the PRNG used by sgsn_alloc_ptmsi */
srand(1);
@@ -1240,6 +1244,9 @@ static void test_gmm_cancel(void)
uint32_t foreign_tlli;
uint32_t local_tlli = 0;
struct gprs_llc_lle *lle;
+
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
+ sgsn->cfg.gea_encryption_mask = 0x1;
const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy;
/* DTAP - Attach Request */
@@ -1270,8 +1277,7 @@ static void test_gmm_cancel(void)
};
printf("Testing cancellation\n");
-
- sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_OPEN;
+ sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN;
foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN);
@@ -1343,6 +1349,7 @@ static void test_apn_matching(void)
struct apn_ctx *actx, *actxs[9];
printf("Testing APN matching\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
actxs[0] = sgsn_apn_ctx_find_alloc("*.test", "");
actxs[1] = sgsn_apn_ctx_find_alloc("*.def.test", "");
@@ -1432,9 +1439,6 @@ static void test_apn_matching(void)
cleanup_test();
}
-struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
- struct sgsn_subscriber_data *sdata);
-
static void test_ggsn_selection(void)
{
struct apn_ctx *actxs[4];
@@ -1453,6 +1457,7 @@ static void test_ggsn_selection(void)
printf("Testing GGSN selection\n");
osmo_gsup_client_send_cb = my_gsup_client_send_dummy;
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -1471,9 +1476,9 @@ static void test_ggsn_selection(void)
/* TODO: Add PDP info entries to s1 */
- ggcs[0] = sgsn_ggsn_ctx_find_alloc(0);
- ggcs[1] = sgsn_ggsn_ctx_find_alloc(1);
- ggcs[2] = sgsn_ggsn_ctx_find_alloc(2);
+ ggcs[0] = sgsn_ggsn_ctx_find_alloc(sgsn, 0);
+ ggcs[1] = sgsn_ggsn_ctx_find_alloc(sgsn, 1);
+ ggcs[2] = sgsn_ggsn_ctx_find_alloc(sgsn, 2);
actxs[0] = sgsn_apn_ctx_find_alloc("test.apn", "123456");
actxs[0]->ggsn = ggcs[0];
@@ -1484,13 +1489,14 @@ static void test_ggsn_selection(void)
pdp_data = sgsn_subscriber_pdp_data_alloc(s1->sgsn_data);
pdp_data->context_id = 1;
- pdp_data->pdp_type = 0x0121;
+ pdp_data->pdp_type_org = PDP_TYPE_ORG_IETF;
+ pdp_data->pdp_type_nr = PDP_TYPE_N_IETF_IPv4;
osmo_strlcpy(pdp_data->apn_str, "*", sizeof(pdp_data->apn_str));
/* Resolve GGSNs */
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1498,7 +1504,7 @@ static void test_ggsn_selection(void)
OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0);
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1524,7 +1530,7 @@ static void test_ggsn_selection(void)
tp.lv[GSM48_IE_GSM_APN].val = apn_enc;
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Foo.Bar");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Foo.Bar");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc == NULL);
@@ -1541,7 +1547,7 @@ static void test_ggsn_selection(void)
osmo_strlcpy(pdp_data->apn_str, "Test.Apn", sizeof(pdp_data->apn_str));
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1549,7 +1555,7 @@ static void test_ggsn_selection(void)
OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0);
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc == NULL);
@@ -1620,11 +1626,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
- [DNS] = {
- .name = "DNS",
- .description = "GPRS Network Service (NS)",
- .enabled = 1, .loglevel = LOGL_INFO,
- },
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",
@@ -1656,11 +1657,7 @@ int main(int argc, char **argv)
tall_sgsn_ctx = talloc_named_const(osmo_sgsn_ctx, 0, "sgsn");
msgb_ctx = msgb_talloc_ctx_init(osmo_sgsn_ctx, 0);
- sgsn_rate_ctr_init();
- sgsn_auth_init(sgsn);
- gprs_subscr_init(sgsn);
vty_init(&vty_info);
- sgsn_vty_init(&sgsn->cfg);
test_llme();
test_subscriber();
@@ -1680,7 +1677,7 @@ int main(int argc, char **argv)
talloc_report_full(osmo_sgsn_ctx, stderr);
OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
- OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 2);
+ OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 1);
return 0;
}