diff options
Diffstat (limited to 'tests/sgsn')
-rw-r--r-- | tests/sgsn/Makefile.am | 26 | ||||
-rw-r--r-- | tests/sgsn/gprs_gb_parse.c | 688 | ||||
-rw-r--r-- | tests/sgsn/gprs_gb_parse.h | 61 | ||||
-rw-r--r-- | tests/sgsn/sgsn_test.c | 93 |
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; } |