lynxis lazus has submitted this change. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/37869?usp=email )
Change subject: GMM: split parsing of a RA Update Request in a separate file ......................................................................
GMM: split parsing of a RA Update Request in a separate file
gprs_gmm.c is huge. Further split the general validation and parsing of the message into an own function.
Change-Id: I413da1b6b4b7c0c4781393acd8564661bc74ce2d --- M include/osmocom/sgsn/gprs_gmm_util.h M src/sgsn/gprs_gmm.c M src/sgsn/gprs_gmm_util.c 3 files changed, 104 insertions(+), 44 deletions(-)
Approvals: pespin: Looks good to me, but someone else must approve daniel: Looks good to me, approved Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve
diff --git a/include/osmocom/sgsn/gprs_gmm_util.h b/include/osmocom/sgsn/gprs_gmm_util.h index be89c35..c136cce 100644 --- a/include/osmocom/sgsn/gprs_gmm_util.h +++ b/include/osmocom/sgsn/gprs_gmm_util.h @@ -1,5 +1,25 @@ #pragma once
+#include <stdbool.h> +#include <stdint.h> + +#include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/tlv.h>
+struct msgb; + extern const struct tlv_definition gsm48_gmm_ie_tlvdef; + +/* 9.4.14 RAU Request */ +struct gprs_gmm_ra_upd_req { + uint8_t skip_ind; /* 10.3.1 */ + uint8_t update_type; /* 10.5.5.18 */ + bool follow_up_req; /* 10.5.5.18 */ + uint8_t cksq; /* 10.5.1.2 */ + struct osmo_routing_area_id old_rai; /* 10.5.5.15 */ + uint8_t *ms_radio_cap; /* 10.5.5.12a */ + uint8_t ms_radio_cap_len; + struct tlv_parsed tlv; +}; + +int gprs_gmm_parse_ra_upd_req(struct msgb *msg, struct gprs_gmm_ra_upd_req *rau_req); diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c index 324c6bf..6122421 100644 --- a/src/sgsn/gprs_gmm.c +++ b/src/sgsn/gprs_gmm.c @@ -1594,52 +1594,30 @@ #ifndef PTMSI_ALLOC struct sgsn_signal_data sig_data; #endif - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t *cur = gh->data; - uint8_t ms_ra_acc_cap_len; - struct osmo_routing_area_id old_ra_id; - struct tlv_parsed tp; - uint8_t upd_type; enum gsm48_gmm_cause reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; + struct gprs_gmm_ra_upd_req req; int rc;
+ rc = gprs_gmm_parse_ra_upd_req(msg, &req); + if (rc) { + reject_cause = rc; + goto rejected; + } + /* TODO: In iu mode - handle follow-on request. * The follow-on request can be signaled in an Attach Request on IuPS. * This means the MS/UE asks to keep the PS connection open for further requests * after the Attach Request succeed. * The SGSN can decide if it close the connection or not. Both are spec conform. */
- /* Update Type 10.5.5.18 */ - upd_type = *cur++ & 0x07; - rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REQUEST)); LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM RA UPDATE REQUEST type="%s"\n", - get_value_string(gprs_upd_t_strs, upd_type)); + get_value_string(gprs_upd_t_strs, req.update_type));
- /* Old routing area identification 10.5.5.15 */ - osmo_routing_area_id_decode(&old_ra_id, cur, msgb_l3len(msg) - (cur - msgb_gmmh(msg))); - cur += 6; - - /* MS Radio Access Capability 10.5.5.12a */ - ms_ra_acc_cap_len = *cur++; - if (ms_ra_acc_cap_len > 52) { - LOGMMCTXP(LOGL_ERROR, mmctx, - "Rejecting GMM RA Update Request: MS Radio Access Capability too long" - " (ms_ra_acc_cap_len = %u > 52)\n", ms_ra_acc_cap_len); - reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; - goto rejected; - } - cur += ms_ra_acc_cap_len; - - /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status, - * DRX parameter, MS network capability */ - tlv_parse(&tp, &gsm48_gmm_ie_tlvdef, cur, - (msg->data + msg->len) - cur, 0, 0); - - switch (upd_type) { + switch (req.update_type) { case GPRS_UPD_T_RA_LA: case GPRS_UPD_T_RA_LA_IMSI_ATT: - LOGMMCTXP(LOGL_NOTICE, mmctx, "Update type %i unsupported in Mode III, is your SI13 corrupt?\n", upd_type); + LOGMMCTXP(LOGL_NOTICE, mmctx, "Update type %d unsupported in Mode III, is your SI13 corrupt?\n", req.update_type); reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; goto rejected; case GPRS_UPD_T_RA: @@ -1658,13 +1636,13 @@ /* Look-up the MM context based on old RA-ID and TLLI */ if (!MSG_IU_UE_CTX(msg)) { /* Gb */ - mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); - } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { + mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &req.old_rai); + } else if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI)) { #ifdef BUILD_IU /* In Iu mode search only for ptmsi */ struct osmo_mobile_identity mi; - if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI), - TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI), false) + if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI), + TLVP_LEN(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI), false) || mi.type != GSM_MI_TYPE_TMSI) { LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n"); goto rejected; @@ -1692,7 +1670,7 @@ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
} - } else if (osmo_rai_cmp(&mmctx->ra, &old_ra_id) || + } else if (osmo_rai_cmp(&mmctx->ra, &req.old_rai) || mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED) { /* We've received either a RAU for a MS which isn't registered @@ -1707,11 +1685,11 @@ if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED) LOGMMCTXP(LOGL_INFO, mmctx, "Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n", - osmo_rai_name2(&old_ra_id), new_ra); + osmo_rai_name2(&req.old_rai), new_ra); else LOGMMCTXP(LOGL_INFO, mmctx, "Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n", - osmo_rai_name2(&old_ra_id), new_ra); + osmo_rai_name2(&req.old_rai), new_ra);
reject_cause = GMM_CAUSE_IMPL_DETACHED; goto rejected; @@ -1732,7 +1710,7 @@ mmctx = sgsn_mm_ctx_by_llme(llme); if (mmctx) { char old_ra_id_name[32]; - osmo_rai_name2_buf(old_ra_id_name, sizeof(old_ra_id_name), &old_ra_id); + osmo_rai_name2_buf(old_ra_id_name, sizeof(old_ra_id_name), &req.old_rai); LOGMMCTXP(LOGL_NOTICE, mmctx, "Rx RA Update Request with unexpected TLLI=%08x Old RA=%s (expected Old RA: %s)!\n", msgb_tlli(msg), old_ra_id_name, osmo_rai_name2(&mmctx->ra)); @@ -1764,8 +1742,8 @@ mmctx->gb.tlli = msgb_tlli(msg); } /* Update the MM context with the new DRX params */ - if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM)) - memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms)); + if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_DRX_PARAM)) + memcpy(&mmctx->drx_parms, TLVP_VAL(&req.tlv, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms));
/* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ @@ -1798,8 +1776,8 @@
/* Look at PDP Context Status IE and see if MS's view of * activated/deactivated NSAPIs agrees with our view */ - if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) { - const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS); + if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS)) { + const uint8_t *pdp_status = TLVP_VAL(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS); process_ms_ctx_status(mmctx, pdp_status); }
diff --git a/src/sgsn/gprs_gmm_util.c b/src/sgsn/gprs_gmm_util.c index 1248e93..0cf730f 100644 --- a/src/sgsn/gprs_gmm_util.c +++ b/src/sgsn/gprs_gmm_util.c @@ -23,10 +23,14 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */
+#include <osmocom/core/msgb.h> +#include <osmocom/gprs/gprs_msgb.h> #include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gsm/tlv.h>
+#include <osmocom/sgsn/gprs_gmm_util.h> + const struct tlv_definition gsm48_gmm_ie_tlvdef = { .def = { [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 }, @@ -47,3 +51,61 @@ }, };
+/*! Parse 24.008 9.4.14 RAU Request + * \param[in] msg l3 pointers must point to gmm. + * \param[out] rau_req parsed RA update request + * \returns 0 on success or GMM cause + */ +int gprs_gmm_parse_ra_upd_req(struct msgb *msg, struct gprs_gmm_ra_upd_req *rau_req) +{ + uint8_t *cur, len; + size_t mandatory_fields_len; + struct gsm48_hdr *gh; + int ret; + + OSMO_ASSERT(msg); + OSMO_ASSERT(rau_req); + + memset(rau_req, 0, sizeof(struct gprs_gmm_ra_upd_req)); + + /* all mandatory fields + variable length MS Radio Cap (min value) */ + if (msgb_l3len(msg) < 16) + return GMM_CAUSE_PROTO_ERR_UNSPEC; + + gh = (struct gsm48_hdr *) msgb_gmmh(msg); + cur = gh->data; + + rau_req->skip_ind = gh->proto_discr >> 4; + + /* V: Update Type 10.5.5.18 */ + rau_req->update_type = *cur & 0x07; + rau_req->follow_up_req = !!(*cur & 0x08); + /* V: GPRS Ciphering Key Sequence 10.5.1.2 */ + rau_req->cksq = *cur >> 4; + cur++; + + /* V: Old routing area identification 10.5.5.15 */ + osmo_routing_area_id_decode(&rau_req->old_rai, cur, 6); + cur += 6; + + /* LV: MS radio cap 10.5.5.12a */ + len = *cur++; + if (msgb_l3len(msg) < (len + (cur - msgb_gmmh(msg)))) + return GMM_CAUSE_PROTO_ERR_UNSPEC; + + rau_req->ms_radio_cap = cur; + rau_req->ms_radio_cap_len = len; + cur += len; + + mandatory_fields_len = (cur - msgb_gmmh(msg)); + if (msgb_l3len(msg) == mandatory_fields_len) + return 0; + + ret = tlv_parse(&rau_req->tlv, &gsm48_gmm_ie_tlvdef, + cur, msgb_l3len(msg) - mandatory_fields_len, 0, 0); + + if (ret < 0) + return GMM_CAUSE_COND_IE_ERR; + + return 0; +}