diff --git a/include/osmocom/sgsn/gprs_gmm_util.h b/include/osmocom/sgsn/gprs_gmm_util.h index be89c35a8..c136cce4a 100644 --- a/include/osmocom/sgsn/gprs_gmm_util.h +++ b/include/osmocom/sgsn/gprs_gmm_util.h @@ -1,5 +1,25 @@ #pragma once +#include +#include + +#include #include +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 324c6bf12..6122421c1 100644 --- a/src/sgsn/gprs_gmm.c +++ b/src/sgsn/gprs_gmm.c @@ -1594,52 +1594,30 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, #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)); - - /* 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); + get_value_string(gprs_upd_t_strs, req.update_type)); - 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, 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 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* 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 1248e9395..0cf730f67 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 . */ +#include +#include #include #include #include +#include + const struct tlv_definition gsm48_gmm_ie_tlvdef = { .def = { [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 }, @@ -47,3 +51,61 @@ const struct tlv_definition gsm48_gmm_ie_tlvdef = { }, }; +/*! 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; +}