From 489499caa9cf09cdc9ee44f8937fa34090f2d60d Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 25 May 2023 17:31:20 +0200 Subject: [PATCH] gmm: Implement P-TMSI Reallocation Cmd/Compl Change-Id: I1bf8bf5f4299db7b026fed2e2c21c07f15690942 --- include/osmocom/gprs/gmm/gmm_pdu.h | 1 + src/gmm/gmm.c | 132 ++++++++++++++++++++++++++--- src/gmm/gmm_pdu.c | 11 +++ tests/gmm/gmm_prim_test.c | 16 ++++ 4 files changed, 146 insertions(+), 14 deletions(-) diff --git a/include/osmocom/gprs/gmm/gmm_pdu.h b/include/osmocom/gprs/gmm/gmm_pdu.h index a0a840f..249c94f 100644 --- a/include/osmocom/gprs/gmm/gmm_pdu.h +++ b/include/osmocom/gprs/gmm/gmm_pdu.h @@ -25,6 +25,7 @@ int gprs_gmm_build_attach_req(struct gprs_gmm_entity *gmme, struct msgb *msg); int gprs_gmm_build_attach_compl(struct gprs_gmm_entity *gmme, struct msgb *msg); +int gprs_gmm_build_ptmsi_realloc_compl(struct gprs_gmm_entity *gmme, struct msgb *msg); int gprs_gmm_build_identity_resp(struct gprs_gmm_entity *gmme, uint8_t mi_type, diff --git a/src/gmm/gmm.c b/src/gmm/gmm.c index 141ef79..1944b86 100644 --- a/src/gmm/gmm.c +++ b/src/gmm/gmm.c @@ -480,6 +480,17 @@ int gprs_gmm_submit_llgmm_assing_req(const struct gprs_gmm_entity *gmme) return rc; } +static void gprs_gmm_gmme_update_allocated_ptmsi(struct gprs_gmm_entity *gmme, uint32_t new_ptmsi) +{ + gmme->old_ptmsi = gmme->ptmsi; + gmme->ptmsi = new_ptmsi; + /* TS 24.008 4.7.1.4.1:"Upon receipt of the assigned P-TMSI, the MS + * shall derive the local TLLI from this P-TMSI and shall use it for + * addressing at lower layers": */ + gmme->old_tlli = gmme->tlli; + gmme->tlli = gprs_tmsi2tlli(gmme->ptmsi, TLLI_LOCAL); +} + /* Tx Identity Response, 9.2.11 */ static int gprs_gmm_tx_id_resp(struct gprs_gmm_entity *gmme, uint8_t mi_type) @@ -650,6 +661,39 @@ int gprs_gmm_tx_detach_req(struct gprs_gmm_entity *gmme, return rc; } +/* Tx GMM Atach Complete, 9.4.3 */ +static int gprs_gmm_tx_ptmsi_realloc_compl(struct gprs_gmm_entity *gmme) +{ + struct osmo_gprs_llc_prim *llc_prim; + int rc; + struct msgb *msg; + + LOGGMME(gmme, LOGL_INFO, "Tx P-TMSI REALLOCATION COMPL\n"); + + llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req( + gmme->tlli, OSMO_GPRS_LLC_SAPI_GMM, NULL, GPRS_GMM_ALLOC_SIZE); + msg = llc_prim->oph.msg; + msg->l3h = msg->tail; + rc = gprs_gmm_build_ptmsi_realloc_compl(gmme, msg); + if (rc < 0) { + msgb_free(msg); + return -EBADMSG; + } + llc_prim->ll.l3_pdu = msg->l3h; + llc_prim->ll.l3_pdu_len = msgb_l3len(msg); + /* TODO: + llc_prim->ll.qos_params.*; + llc_prim->ll.radio_prio; + llc_prim->ll.apply_gea; + llc_prim->ll.apply_gia; + */ + + rc = gprs_gmm_prim_call_llc_down_cb(llc_prim); + if (rc < 0) + return rc; + return rc; +} + /* Tx GMM Routing area update request, 9.4.14 */ int gprs_gmm_tx_rau_req(struct gprs_gmm_entity *gmme, enum gprs_gmm_upd_type rau_type) @@ -777,13 +821,7 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g LOGGMME(gmme, LOGL_ERROR, "Cannot decode P-TMSI\n"); goto rejected; } - gmme->old_ptmsi = gmme->ptmsi; - gmme->ptmsi = mi.tmsi; - /* TS 24.008 4.7.1.4.1:"Upon receipt of the assigned P-TMSI, the MS - * shall derive the local TLLI from this P-TMSI and shall use it for - * addressing at lower layers": */ - gmme->old_tlli = gmme->tlli; - gmme->tlli = gprs_tmsi2tlli(gmme->ptmsi, TLLI_LOCAL); + gprs_gmm_gmme_update_allocated_ptmsi(gmme, mi.tmsi); } if (TLVP_PRES_LEN(&tp, GSM48_IE_GMM_TIMER_T3302, 1)) @@ -938,13 +976,7 @@ static int gprs_gmm_rx_rau_acc(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g LOGGMME(gmme, LOGL_ERROR, "Cannot decode P-TMSI\n"); goto rejected; } - gmme->old_ptmsi = gmme->ptmsi; - gmme->ptmsi = mi.tmsi; - /* TS 24.008 4.7.1.4.1:"Upon receipt of the assigned P-TMSI, the MS - * shall derive the local TLLI from this P-TMSI and shall use it for - * addressing at lower layers": */ - gmme->old_tlli = gmme->tlli; - gmme->tlli = gprs_tmsi2tlli(gmme->ptmsi, TLLI_LOCAL); + gprs_gmm_gmme_update_allocated_ptmsi(gmme, mi.tmsi); } /* FIXME! what to do it PTMSI changes? probably need to update other layers... Check GPRS ATTACH ACCEPT func */ @@ -1034,6 +1066,75 @@ static int gprs_gmm_rx_id_req(struct gprs_gmm_entity *gmme, struct gsm48_hdr *gh return gprs_gmm_tx_id_resp(gmme, id_type); } +/* Rx GMM P-TMSI reallocation command, 9.4.7 */ +static int gprs_gmm_rx_ptmsi_realloc_cmd(struct gprs_gmm_entity *gmme, const struct gsm48_hdr *gh, unsigned int len) +{ + const uint8_t *buf = &gh->data[0]; + uint8_t mi_len; + struct osmo_mobile_identity mi; + bool force_standby_indicated; + struct tlv_parsed tp; + int rc; + + if (len != 15) { + LOGGMME(gmme, LOGL_ERROR, "Rx GMM P-TMSI REALLOCATION COMMAND with wrong size %u\n", len); + goto rejected; + } + + mi_len = *buf; + if (mi_len != 5) + goto rejected; + buf++; + if (osmo_mobile_identity_decode(&mi, buf, mi_len, false) || mi.type != GSM_MI_TYPE_TMSI) { + LOGGMME(gmme, LOGL_ERROR, "Rx GMM P-TMSI REALLOCATION COMMAND: Cannot decode P-TMSI\n"); + goto rejected; + } + gprs_gmm_gmme_update_allocated_ptmsi(gmme, mi.tmsi); + buf += mi_len; + + gsm48_parse_ra(&gmme->ra, (const uint8_t *)buf); + buf += 6; + + force_standby_indicated = (*buf >> 4) == 0x01; + if (force_standby_indicated) + gprs_gmm_gmme_ready_timer_stop(gmme); + buf++; + + /* Optional: */ + if (len > (buf - (uint8_t *)gh)) { + rc = gprs_gmm_tlv_parse(&tp, buf, len - (buf - (uint8_t *)gh)); + if (rc < 0) { + LOGGMME(gmme, LOGL_ERROR, "Rx GMM P-TMSI REALLOCATION COMMAND: failed to parse TLVs %d\n", rc); + goto rejected; + } + + /* 10.5.5.8 P-TMSI signature */ + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PTMSI_SIG)) { + const uint8_t *ptmsi_sig = TLVP_VAL(&tp, GSM48_IE_GMM_PTMSI_SIG); + gmme->ptmsi_sig = (ptmsi_sig[0] << 8) | (ptmsi_sig[1] << 4) | ptmsi_sig[2]; + } else { + gmme->ptmsi_sig = GSM_RESERVED_TMSI; + } + + /* TODO: 10.5.5.35 DCN-ID */ + } + + /* Submit LLGMM-ASSIGN-REQ as per TS 24.007 Annex C.1 */ + rc = gprs_gmm_submit_llgmm_assing_req(gmme); + if (rc < 0) + goto rejected; + + /* Submit GMMRR-ASSIGN-REQ as per TS 24.007 Annex C.1 */ + rc = gprs_gmm_submit_gmmrr_assing_req(gmme); + if (rc < 0) + goto rejected; + + return gprs_gmm_tx_ptmsi_realloc_compl(gmme); + +rejected: + return -EINVAL; /* TODO: what to do on error? */ +} + /* Rx GMM Authentication and ciphering request, 9.4.9 */ static int gprs_gmm_rx_auth_ciph_req(struct gprs_gmm_entity *gmme, struct gsm48_hdr *gh, unsigned int len) { @@ -1120,6 +1221,9 @@ int gprs_gmm_rx(struct gprs_gmm_entity *gmme, struct gsm48_hdr *gh, unsigned int case GSM48_MT_GMM_ID_REQ: rc = gprs_gmm_rx_id_req(gmme, gh, len); break; + case GSM48_MT_GMM_PTMSI_REALL_CMD: + rc = gprs_gmm_rx_ptmsi_realloc_cmd(gmme, gh, len); + break; case GSM48_MT_GMM_AUTH_CIPH_REQ: rc = gprs_gmm_rx_auth_ciph_req(gmme, gh, len); break; diff --git a/src/gmm/gmm_pdu.c b/src/gmm/gmm_pdu.c index ae0baef..d213e70 100644 --- a/src/gmm/gmm_pdu.c +++ b/src/gmm/gmm_pdu.c @@ -284,6 +284,17 @@ int gprs_gmm_build_attach_compl(struct gprs_gmm_entity *gmme, struct msgb *msg) return 0; } +/* 9.4.8 P-TMSI reallocation complete */ +int gprs_gmm_build_ptmsi_realloc_compl(struct gprs_gmm_entity *gmme, struct msgb *msg) +{ + struct gsm48_hdr *gh; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_PTMSI_REALL_COMPL; + return 0; +} + /* Chapter 9.4.14: Routing area update request */ int gprs_gmm_build_rau_req(struct gprs_gmm_entity *gmme, enum gprs_gmm_upd_type rau_type, diff --git a/tests/gmm/gmm_prim_test.c b/tests/gmm/gmm_prim_test.c index 89f621c..50d40d8 100644 --- a/tests/gmm/gmm_prim_test.c +++ b/tests/gmm/gmm_prim_test.c @@ -464,6 +464,22 @@ static void test_gmm_prim_ms_gmmreg(void) rc = osmo_gprs_gmm_prim_lower_up(gmm_prim); OSMO_ASSERT(rc == 0); + /* ... */ + + /* Test Network sends P-TMSI Reallocation Cmd */ +#if 0 + /* TODO: find a pcap with a P-TMSI Reallocation Cmd */ + llc_prim = gprs_llc_prim_alloc_ll_unitdata_ind(tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_ptmsi_realloc_cmd, sizeof(pdu_gmm_ptmsi_realloc_cmd)); + OSMO_ASSERT(llc_prim); + rc = osmo_gprs_gmm_prim_llc_lower_up(llc_prim); + OSMO_ASSERT(rc == 0); + /* update the used ptmsi to align with what was assigned from the network: */ + ptmsi = 0xea711b41; + tlli = gprs_tmsi2tlli(ptmsi, TLLI_LOCAL); + /* As a result, MS answers GMM P-TMSI Reallocation Complete */ +#endif + + /* ... */ /* DETACH */