From 5a38f6470e74b0d7d7746fa65573f2acf76197eb Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 21 Oct 2014 13:09:55 +0200 Subject: sgsn: Handle Detach Requests even when there is no mmctx Currently, when a Detach Request is received with an unknown TLLI, it is answered by another Detach Request (!), even when a power_off Type is used. This patch uses gsm48_rx_gmm_det_req to handle the message instead. So this function is changed to cope with a NULL mmctx. In that case it doesn't unassign the llme, so this must be done manually afterwards. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gprs_sgsn.h | 3 ++- openbsc/src/gprs/gprs_gmm.c | 41 +++++++++++++++++++++++++++---------- openbsc/tests/sgsn/sgsn_test.c | 36 ++++++++++++++++++++++++++++++++ openbsc/tests/sgsn/sgsn_test.ok | 1 + 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 5c82227d7..73731fe97 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -114,7 +114,8 @@ struct sgsn_mm_ctx { }; #define LOGMMCTXP(level, mm, fmt, args...) \ - LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm)->imsi, (mm)->p_tmsi, ## args) + LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \ + (mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args) /* look-up a SGSN MM context based on TLLI + RAI */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index ff852eb80..4a71ba400 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -497,14 +497,14 @@ static int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm, } /* Chapter 9.4.6.2 Detach accept */ -static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby) +static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby, + struct sgsn_mm_ctx *mm) { - struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_INFO, mm, "<- GPRS DETACH ACCEPT\n"); + /* MMCTX might be NULL! */ - mmctx2msgid(msg, mm); + DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -514,6 +514,22 @@ static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby) return gsm48_gmm_sendmsg(msg, 0, mm); } +static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby) +{ + struct msgb *msg = gsm48_msgb_alloc(); + + mmctx2msgid(msg, mm); + return _tx_detach_ack(msg, force_stby, mm); +} + +static int gsm48_tx_gmm_det_ack_oldmsg(struct msgb *oldmsg, uint8_t force_stby) +{ + struct msgb *msg = gsm48_msgb_alloc(); + + gmm_copy_id(msg, oldmsg); + return _tx_detach_ack(msg, force_stby, NULL); +} + /* Transmit Chapter 9.4.12 Identity Request */ static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type) { @@ -864,7 +880,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t detach_type, power_off; - int rc; + int rc = 0; detach_type = gh->data[0] & 0x7; power_off = gh->data[0] & 0x8; @@ -875,14 +891,18 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type), power_off ? "Power-off" : ""); - /* Only sent the Detach Accept (MO) if power off isn't indicated, + /* Only send the Detach Accept (MO) if power off isn't indicated, * see 04.08, 4.7.4.1.2/3 for details */ if (!power_off) { /* force_stby = 0 */ - rc = gsm48_tx_gmm_det_ack(ctx, 0); + if (ctx) + rc = gsm48_tx_gmm_det_ack(ctx, 0); + else + rc = gsm48_tx_gmm_det_ack_oldmsg(msg, 0); } - mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST"); + if (ctx) + mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST"); return rc; } @@ -1117,9 +1137,8 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* Don't force it into re-attachment */ if (gh->msg_type == GSM48_MT_GMM_DETACH_REQ) { - rc = gsm48_tx_gmm_detach_req_oldmsg( - msg, GPRS_DET_T_MT_REATT_NOTREQ, - GMM_CAUSE_IMPL_DETACHED); + /* Handle Detach Request */ + rc = gsm48_rx_gmm_det_req(NULL, msg); /* TLLI unassignment */ gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index cb3c29472..05d1ee0ef 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -221,6 +221,41 @@ static void test_gmm_detach_power_off(void) OSMO_ASSERT(!ictx); } +/* + * Test that a GMM Detach will remove the associated LLME if there is no MMCTX. + */ +static void test_gmm_detach_no_mmctx(void) +{ + struct gprs_llc_lle *lle; + uint32_t local_tlli; + struct msgb *msg; + + printf("Testing GMM detach (no MMCTX)\n"); + + /* DTAP - Detach Request (MO) */ + /* normal detach, power_off = 0 */ + static const unsigned char detach_req[] = { + 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2, + 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb + }; + + /* Create an LLME */ + OSMO_ASSERT(count(gprs_llme_list()) == 0); + local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); + lle = gprs_lle_get_or_create(local_tlli, 3); + + OSMO_ASSERT(count(gprs_llme_list()) == 1); + + /* inject the detach */ + msg = create_msg(detach_req, ARRAY_SIZE(detach_req)); + msgb_tlli(msg) = local_tlli; + gsm0408_gprs_rcvmsg(msg, lle->llme); + msgb_free(msg); + + /* verify that the LLME is gone */ + OSMO_ASSERT(count(gprs_llme_list()) == 0); +} + static struct log_info_cat gprs_categories[] = { [DMM] = { .name = "DMM", @@ -285,6 +320,7 @@ int main(int argc, char **argv) test_llme(); test_gmm_detach(); test_gmm_detach_power_off(); + test_gmm_detach_no_mmctx(); printf("Done\n"); return 0; } diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index 4c475d936..bca2b4bc4 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -1,4 +1,5 @@ Testing LLME allocations Testing GMM detach Testing GMM detach (power off) +Testing GMM detach (no MMCTX) Done -- cgit v1.2.3