diff options
Diffstat (limited to 'src/sgsn/gprs_gmm.c')
-rw-r--r-- | src/sgsn/gprs_gmm.c | 509 |
1 files changed, 353 insertions, 156 deletions
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c index afae369a2..653c42527 100644 --- a/src/sgsn/gprs_gmm.c +++ b/src/sgsn/gprs_gmm.c @@ -30,7 +30,7 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include "bscconfig.h" +#include "config.h" #include <osmocom/core/msgb.h> #include <osmocom/gsm/tlv.h> @@ -41,13 +41,14 @@ #include <osmocom/core/utils.h> #include <osmocom/core/tdef.h> #include <osmocom/crypt/auth.h> +#include <osmocom/crypt/utran_cipher.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_llc.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_utils.h> #include <osmocom/sgsn/gprs_subscriber.h> @@ -59,17 +60,17 @@ #include <osmocom/sgsn/signal.h> #include <osmocom/sgsn/gprs_sndcp.h> #include <osmocom/sgsn/gprs_ranap.h> +#include <osmocom/sgsn/gprs_sm.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> #include <pdp.h> #define PTMSI_ALLOC -extern struct sgsn_instance *sgsn; -extern void *tall_sgsn_ctx; - static const struct tlv_definition gsm48_gmm_att_tlvdef = { .def = { - [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 }, + [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 }, [GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 }, [GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 }, @@ -78,6 +79,7 @@ static const struct tlv_definition gsm48_gmm_att_tlvdef = { [GSM48_IE_GMM_AUTH_RES_EXT] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_AUTH_FAIL_PAR] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_RX_NPDU_NUM_LIST] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 }, [GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 }, @@ -109,9 +111,14 @@ static void mmctx_timer_start(struct sgsn_mm_ctx *mm, unsigned int T) static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T) { - if (mm->T != T) + if (!osmo_timer_pending(&mm->timer)) { + LOGMMCTXP(LOGL_NOTICE, mm, "Stopping *inactive* MM timer %u\n", T); + return; + } + if (mm->T != T) { LOGMMCTXP(LOGL_ERROR, mm, "Stopping MM timer %u but " "%u is running\n", T, mm->T); + } osmo_timer_del(&mm->timer); } @@ -131,7 +138,7 @@ int gsm48_gmm_sendmsg(struct msgb *msg, int command, struct sgsn_mm_ctx *mm, bool encryptable) { if (mm) { - rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]); + rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_SIG_OUT)); #ifdef BUILD_IU if (mm->ran_type == MM_CTX_T_UTRAN_Iu) return ranap_iu_tx(msg, GPRS_SAPI_GMM); @@ -197,10 +204,10 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text) switch(ctx->ran_type) { case MM_CTX_T_UTRAN_Iu: - osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL); + osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL); break; case MM_CTX_T_GERAN_Gb: - osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL); + osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL); break; } @@ -215,7 +222,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause, /* MMCTX might be NULL! */ - DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n", + DEBUGP(DMM, "<- GMM STATUS (cause: %s)\n", get_value_string(gsm48_gmm_cause_names, cause)); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); @@ -241,7 +248,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause, /* MMCTX might be NULL! */ - DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n", + DEBUGP(DMM, "<- GMM DETACH REQ (type: %s, cause: %s)\n", get_value_string(gprs_det_t_mt_strs, detach_type), get_value_string(gsm48_gmm_cause_names, cause)); @@ -280,14 +287,18 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm) struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK"); struct gsm48_hdr *gh; struct gsm48_attach_ack *aa; - uint8_t *mid; unsigned long t; +#ifdef PTMSI_ALLOC + struct osmo_mobile_identity mi; + uint8_t *l; + int rc; +#endif #if 0 uint8_t *ptsig; #endif - LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi); - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]); + LOGMMCTXP(LOGL_INFO, mm, "<- GMM ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_ACKED)); mmctx2msgid(msg, mm); @@ -300,7 +311,7 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm) aa->att_result = 1; /* GPRS only */ t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1); aa->ra_upd_timer = gprs_secs_to_tmr_floor(t); - aa->radio_prio = 4; /* lowest */ + aa->radio_prio = 0x44; /* lowest */ gsm48_encode_ra(&aa->ra_id, &mm->ra); #if 0 @@ -321,14 +332,26 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm) #ifdef PTMSI_ALLOC /* Optional: Allocated P-TMSI */ - mid = msgb_put(msg, GSM48_MID_TMSI_LEN); - gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi); - mid[0] = GSM48_IE_GMM_ALLOC_PTMSI; + mi = (struct osmo_mobile_identity){ + .type = GSM_MI_TYPE_TMSI, + .tmsi = mm->p_tmsi, + }; + l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI); + rc = osmo_mobile_identity_encode_msgb(msg, &mi, false); + if (rc < 0) { + LOGMMCTXP(LOGL_ERROR, mm, "Cannot encode Mobile Identity\n"); + msgb_free(msg); + return -EINVAL; + } + *l = rc; #endif /* Optional: MS-identity (combined attach) */ /* Optional: GMM cause (partial attach result for combined attach) */ + /* Optional: Network feature support 10.5.5.23 */ + /* msgb_v_put(msg, GSM48_IE_GMM_NET_FEAT_SUPPORT | 0x00);*/ + return gsm48_gmm_sendmsg(msg, 0, mm, true); } @@ -338,9 +361,9 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause, { struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n", + LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM ATTACH REJECT: %s\n", get_value_string(gsm48_gmm_cause_names, gmm_cause)); - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REJECTED)); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -372,8 +395,8 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby, /* MMCTX might be NULL! */ - DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby); - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]); + DEBUGP(DMM, "<- GMM DETACH ACC (force-standby: %d)\n", force_stby); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_ACKED)); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -405,7 +428,7 @@ int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type) struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ"); struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n", + LOGMMCTXP(LOGL_DEBUG, mm, "<- GMM IDENTITY REQUEST: mi_type=%s\n", gsm48_mi_type_name(id_type)); mmctx2msgid(msg, mm); @@ -429,6 +452,17 @@ static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm) return false; } +static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) { + uint8_t common_mask = net_mask & ms_mask; + uint8_t r = 0; + + while (common_mask >>= 1) { + r++; + } + + return r; +} + /* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, const struct osmo_auth_vector *vec, @@ -440,7 +474,7 @@ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *m_rand, *m_cksn, rbyte; int rc; - LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s," + LOGMMCTXP(LOGL_INFO, mm, "<- GMM AUTH AND CIPHERING REQ (rand = %s," " mmctx_is_r99=%d, vec->auth_types=0x%x", osmo_hexdump(vec->rand, sizeof(vec->rand)), mmctx_is_r99(mm), vec->auth_types); @@ -503,7 +537,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm) struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ"); struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n"); + LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM AUTH AND CIPH REJECT\n"); mmctx2msgid(msg, mm); @@ -583,7 +617,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, uint8_t res_len; int rc; - LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n"); + LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH RESPONSE\n"); if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) { LOGMMCTXP(LOGL_NOTICE, ctx, @@ -634,7 +668,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len); if (!sgsn_mm_ctx_is_authenticated(ctx)) { rc = gsm48_tx_gmm_auth_ciph_rej(ctx); - mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT"); + mm_ctx_cleanup_free(ctx, "GMM AUTH AND CIPH REJECT"); return rc; } @@ -657,7 +691,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx, const uint8_t *auts; int rc; - LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n", + LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n", get_value_string(gsm48_gmm_cause_names, gmm_cause)); tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0); @@ -697,7 +731,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx, LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n"); rc = gsm48_tx_gmm_auth_ciph_rej(ctx); - mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE"); + mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE"); return rc; } @@ -776,7 +810,7 @@ static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm) struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK"); struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi); + LOGMMCTXP(LOGL_INFO, mm, "<- GMM SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi); mmctx2msgid(msg, mm); @@ -797,7 +831,7 @@ static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause, { struct gsm48_hdr *gh; - LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n", + LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM SERVICE REJECT: %s\n", get_value_string(gsm48_gmm_cause_names, gmm_cause)); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); @@ -889,7 +923,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) /* The MS is authorized */ #ifdef BUILD_IU if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) { - rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key); + /* Is any encryption above UEA0 enabled? */ + bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0); + LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n", + send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask); + /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this + * is not possible in the iu_client API. See OS#5487. */ + rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key); ctx->iu.new_key = 0; return rc; } @@ -911,16 +951,16 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) ctx->t3350_mode = GMM_T3350_MODE_ATT; #else memset(&sig_data, 0, sizeof(sig_data)); - sig_data.mm = mmctx; + sig_data.mm = ctx; osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data); - osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL); + osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL); #endif return gsm48_tx_gmm_att_ack(ctx); #ifdef BUILD_IU case GSM48_MT_GMM_SERVICE_REQ: ctx->pending_req = 0; - osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL); + osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL); rc = gsm48_tx_gmm_service_ack(ctx); if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING) @@ -1026,31 +1066,35 @@ void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx, int gmm_cause) static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; - long mi_typel = mi_type; - char mi_string[GSM48_MI_SIZE]; + long mi_typel; + char mi_log_string[32]; + struct osmo_mobile_identity mi; - gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); if (!ctx) { DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg)); return -EINVAL; } - LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n", - gsm48_mi_type_name(mi_type), mi_string); + if (osmo_mobile_identity_decode(&mi, &gh->data[1], gh->data[0], false)) { + LOGMMCTXP(LOGL_ERROR, ctx, "-> GMM IDENTITY RESPONSE: cannot decode Mobile Identity\n"); + return -EINVAL; + } + osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi); + + LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n", mi_log_string); if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) { LOGMMCTXP(LOGL_NOTICE, ctx, - "Got unexpected IDENTITY RESPONSE: MI(%s)=%s, " + "Got unexpected IDENTITY RESPONSE: MI=%s, " "ignoring message\n", - gsm48_mi_type_name(mi_type), mi_string); + mi_log_string); return -EINVAL; } - if (mi_type == ctx->t3370_id_type) + if (mi.type == ctx->t3370_id_type) mmctx_timer_stop(ctx, 3370); - switch (mi_type) { + switch (mi.type) { case GSM_MI_TYPE_IMSI: /* we already have a mm context with current TLLI, but no * P-TMSI / IMSI yet. What we now need to do is to fill @@ -1058,7 +1102,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) if (strlen(ctx->imsi) == 0) { /* Check if we already have a MM context for this IMSI */ struct sgsn_mm_ctx *ictx; - ictx = sgsn_mm_ctx_by_imsi(mi_string); + ictx = sgsn_mm_ctx_by_imsi(mi.imsi); if (ictx) { /* Handle it like in gsm48_rx_gmm_det_req, * except that no messages are sent to the BSS */ @@ -1067,19 +1111,20 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) "p_tmsi_old=0x%08x\n", ictx->p_tmsi); - mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use"); + mm_ctx_cleanup_free(ictx, "GMM IMSI re-use"); } } - osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); + OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi); break; case GSM_MI_TYPE_IMEI: - osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei)); + OSMO_STRLCPY_ARRAY(ctx->imei, mi.imei); break; case GSM_MI_TYPE_IMEISV: break; } /* Check if we can let the mobile station enter */ + mi_typel = mi.type; return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel); } @@ -1099,23 +1144,65 @@ static inline void ptmsi_update(struct sgsn_mm_ctx *ctx) osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); } +/* Detect if RAT has changed */ +static bool mmctx_did_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg) +{ + if (MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_UTRAN_Iu) + return true; + if (!MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_GERAN_Gb) + return true; + return false; +} + +/* Notify the FSM of a RAT change */ +static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_llc_llme *llme) +{ + struct gmm_rat_change_data rat_chg = { + .llme = llme + }; + + rat_chg.new_ran_type = MSG_IU_UE_CTX(msg) ? MM_CTX_T_UTRAN_Iu : MM_CTX_T_GERAN_Gb; + + if (rat_chg.new_ran_type != mmctx->ran_type) + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAT_CHANGE, (void *) &rat_chg); + else + LOGMMCTXP(LOGL_ERROR, mmctx, "RAT didn't change or not implemented (ran_type=%u, " + "msg_iu_ue_ctx=%p\n", mmctx->ran_type, MSG_IU_UE_CTX(msg)); + +} + +static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len) +{ + uint8_t mask = (1 << GPRS_ALGO_GEA0); + mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0; + + if (cap_len < 2) + return mask; + + /* extended GEA bits start from 2nd bit of the next byte */ + mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0; + mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0; + mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0; + return mask; +} + /* 3GPP TS 24.008 § 9.4.1 Attach request */ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap; - uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len; + uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap; + uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len; uint16_t drx_par; - uint32_t tmsi; - char mi_string[GSM48_MI_SIZE]; + char mi_log_string[32]; struct gprs_ra_id ra_id; uint16_t cid = 0; enum gsm48_gmm_cause reject_cause; + struct osmo_mobile_identity mi; int rc; LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST "); - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST)); /* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either * with a foreign TLLI (P-TMSI that was allocated to the MS before), @@ -1155,15 +1242,15 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ mi_len = *cur++; - mi = cur; - if (mi_len > 8) - goto err_inval; - mi_type = *mi & GSM_MI_TYPE_MASK; + mi_data = cur; cur += mi_len; - gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false); + if (rc) + goto err_inval; + osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi); - DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string, get_value_string(gprs_att_t_strs, att_type)); /* Old routing area identification 10.5.5.15. Skip it */ @@ -1180,11 +1267,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */ - switch (mi_type) { + switch (mi.type) { case GSM_MI_TYPE_IMSI: /* Try to find MM context based on IMSI */ if (!ctx) - ctx = sgsn_mm_ctx_by_imsi(mi_string); + ctx = sgsn_mm_ctx_by_imsi(mi.imsi); if (!ctx) { if (MSG_IU_UE_CTX(msg)) ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg)); @@ -1194,15 +1281,13 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, reject_cause = GMM_CAUSE_NET_FAIL; goto rejected; } - osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); + OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi); } break; case GSM_MI_TYPE_TMSI: - memcpy(&tmsi, mi+1, 4); - tmsi = ntohl(tmsi); /* Try to find MM context based on P-TMSI */ if (!ctx) - ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi); if (!ctx) { /* Allocate a context as most of our code expects one. * Context will not have an IMSI ultil ID RESP is received */ @@ -1214,16 +1299,19 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, reject_cause = GMM_CAUSE_NET_FAIL; goto rejected; } - ctx->p_tmsi = tmsi; + ctx->p_tmsi = mi.tmsi; } break; default: LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with " - "MI type %s\n", gsm48_mi_type_name(mi_type)); + "MI %s\n", mi_log_string); reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED; goto rejected; } + if (mmctx_did_rat_change(ctx, msg)) + mmctx_handle_rat_change(ctx, msg, llme); + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { ctx->gb.tlli = msgb_tlli(msg); ctx->gb.llme = llme; @@ -1241,15 +1329,27 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, ctx->ms_radio_access_capa.len); ctx->ms_network_capa.len = msnc_len; memcpy(ctx->ms_network_capa.buf, msnc, msnc_len); - if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len, - ctx->ciph_algo)) { + + ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len); + + if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) { reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI " - "type %s because MS do not support required %s " - "encryption\n", gsm48_mi_type_name(mi_type), - get_value_string(gprs_cipher_names,ctx->ciph_algo)); + "%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n", + mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask); goto rejected; } + + /* just assume that everythig is fine if the phone offers a5/4: + * it requires a valid umts security context which we can only have after + * 1) IDENTITY REQUEST to know what to ask the HLR for + * 2) and AUTHENTICATION AND CIPHERING REQUEST + * ... but 2) already requires selecting a cipher mode. + * So let's just assume we will have the auth data required to make it work. + */ + + ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask); + #ifdef PTMSI_ALLOC /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */ ptmsi_update(ctx); @@ -1281,7 +1381,7 @@ rejected: get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause); rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause); if (ctx) - mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ"); + mm_ctx_cleanup_free(ctx, "GMM ATTACH REJ"); else if (llme) gprs_llgmm_unassign(llme); @@ -1294,13 +1394,13 @@ static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx) { struct sgsn_signal_data sig_data; /* only in case SGSN offered new P-TMSI */ - LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n"); + LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n"); - #ifdef BUILD_IU +#ifdef BUILD_IU if (mmctx->iu.ue_ctx) { ranap_iu_tx_release(mmctx->iu.ue_ctx, NULL); } - #endif +#endif mmctx_timer_stop(mmctx, 3350); mmctx->t3350_mode = GMM_T3350_MODE_NONE; @@ -1361,7 +1461,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) power_off = gh->data[0] & 0x8; /* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */ - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_REQUEST)); LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n", msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type), power_off ? "Power-off" : ""); @@ -1381,7 +1481,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) memset(&sig_data, 0, sizeof(sig_data)); sig_data.mm = ctx; osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data); - mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST"); + mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST"); } return rc; @@ -1393,11 +1493,15 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm) struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK"); struct gsm48_hdr *gh; struct gsm48_ra_upd_ack *rua; - uint8_t *mid; unsigned long t; +#ifdef PTMSI_ALLOC + uint8_t *l; + int rc; + struct osmo_mobile_identity mi; +#endif - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]); - LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n"); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_ACKED)); + LOGMMCTXP(LOGL_INFO, mm, "<- GMM ROUTING AREA UPDATE ACCEPT\n"); mmctx2msgid(msg, mm); @@ -1424,9 +1528,17 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm) #ifdef PTMSI_ALLOC /* Optional: Allocated P-TMSI */ - mid = msgb_put(msg, GSM48_MID_TMSI_LEN); - gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi); - mid[0] = GSM48_IE_GMM_ALLOC_PTMSI; + mi = (struct osmo_mobile_identity){ + .type = GSM_MI_TYPE_TMSI, + .tmsi = mm->p_tmsi, + }; + l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI); + rc = osmo_mobile_identity_encode_msgb(msg, &mi, false); + if (rc < 0) { + msgb_free(msg); + return -EINVAL; + } + *l = rc; #endif /* Optional: Negotiated READY timer value */ @@ -1444,7 +1556,7 @@ int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) struct gsm48_hdr *gh; LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n"); - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]); + rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT)); gmm_copy_id(msg, old_msg); @@ -1470,21 +1582,19 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx, * being in state PDP-INACTIVE. */ llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) { - if (pdp->nsapi < 8) { - if (!(pdp_status[0] & (1 << pdp->nsapi))) { - LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u " - "due to PDP CTX STATUS IE= 0x%02x%02x\n", - pdp->nsapi, pdp_status[1], pdp_status[0]); - sgsn_delete_pdp_ctx(pdp); - } - } else { - if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) { - LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u " - "due to PDP CTX STATUS IE= 0x%02x%02x\n", - pdp->nsapi, pdp_status[1], pdp_status[0]); - sgsn_delete_pdp_ctx(pdp); - } - } + bool inactive = (pdp->nsapi < 8) ? + !(pdp_status[0] & (1 << pdp->nsapi)) : + !(pdp_status[1] & (1 << (pdp->nsapi - 8))); + if (!inactive) + continue; + + LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u " + "due to PDP CTX STATUS IE=0x%02x%02x\n", + pdp->nsapi, pdp_status[1], pdp_status[0]); + if (pdp->ggsn) + sgsn_delete_pdp_ctx(pdp); + else /* GTP side already detached, freeing */ + sgsn_pdp_ctx_free(pdp); } } @@ -1526,7 +1636,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* Update Type 10.5.5.18 */ upd_type = *cur++ & 0x07; - rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]); + 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)); @@ -1576,19 +1686,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { #ifdef BUILD_IU /* In Iu mode search only for ptmsi */ - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI); - const uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI); - uint8_t mi_type = *mi & GSM_MI_TYPE_MASK; - uint32_t tmsi; - - gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); - - if (mi_type == GSM_MI_TYPE_TMSI) { - memcpy(&tmsi, mi+1, 4); - tmsi = ntohl(tmsi); - mmctx = sgsn_mm_ctx_by_ptmsi(tmsi); + 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) + || mi.type != GSM_MI_TYPE_TMSI) { + LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n"); + goto rejected; } + mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi); #else LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Rejecting GMM RA Update Request: No Iu support\n"); @@ -1604,29 +1709,44 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx->p_tmsi, mmctx->p_tmsi_old, mmctx->gb.tlli, mmctx->gb.tlli_new, osmo_rai_name(&mmctx->ra)); - osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + /* A RAT change will trigger the common procedure + * below after handling the RAT change. Protect it + * here from being called twice */ + if (!mmctx_did_rat_change(mmctx, msg)) + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + } } else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) || mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED) { - /* We cannot use the mmctx */ - LOGMMCTXP(LOGL_INFO, mmctx, - "The MM context cannot be used, RA: %s\n", - osmo_rai_name(&mmctx->ra)); - /* mmctx is set to NULL and gprs_llgmm_unassign(llme) will be - called below, let's make sure we don't keep dangling llme - pointers in mmctx (OS#3957). */ - if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) - OSMO_ASSERT(mmctx->gb.llme == NULL); - mmctx = NULL; + /* We've received either a RAU for a MS which isn't registered + * or a RAU with an unknown RA ID. As long the SGSN doesn't support + * PS handover we treat this as invalid RAU */ + struct gprs_ra_id new_ra_id; + char new_ra[32]; + + bssgp_parse_cell_id(&new_ra_id, msgb_bcid(msg)); + osmo_rai_name_buf(new_ra, sizeof(new_ra), &new_ra_id); + + 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_name(&old_ra_id), new_ra); + else + LOGMMCTXP(LOGL_INFO, mmctx, + "Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n", + osmo_rai_name(&old_ra_id), new_ra); + + reject_cause = GMM_CAUSE_IMPL_DETACHED; + goto rejected; } if (!mmctx) { if (llme) { /* send a XID reset to re-set all LLC sequence numbers * in the MS */ - LOGGBP(llme, LOGL_NOTICE, "LLC XID RESET\n"); - gprs_llgmm_reset(llme); + LOGGBP(llme, DMM, LOGL_NOTICE, "LLC XID RESET\n"); + gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme); } /* The MS has to perform GPRS attach */ /* Device is still IMSI attached for CS but initiate GPRS ATTACH, @@ -1636,21 +1756,30 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, goto rejected; } + if (mmctx_did_rat_change(mmctx, msg)) { + mmctx_handle_rat_change(mmctx, msg, llme); + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + } + /* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */ msgid2mmctx(mmctx, msg); /* Bump the statistics of received signalling msgs for this MM context */ - rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN)); /* Update the MM context with the new RA-ID */ - if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) { bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg)); /* Update the MM context with the new (i.e. foreign) TLLI */ 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)); + /* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ - rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]); + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE)); #ifdef PTMSI_ALLOC ptmsi_update(mmctx); @@ -1660,7 +1789,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx_timer_start(mmctx, 3350); #else /* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */ - osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL); + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL); memset(&sig_data, 0, sizeof(sig_data)); sig_data.mm = mmctx; @@ -1696,9 +1825,15 @@ rejected: get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause); rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause); if (mmctx) - mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ"); + mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ"); else if (llme) gprs_llgmm_unassign(llme); +#ifdef BUILD_IU + else if (MSG_IU_UE_CTX(msg)) { + unsigned long X1001 = osmo_tdef_get(sgsn->cfg.T_defs, -1001, OSMO_TDEF_S, -1); + ranap_iu_tx_release_free(MSG_IU_UE_CTX(msg), NULL, (int) X1001); + } +#endif return rc; } @@ -1756,11 +1891,11 @@ static int gsm48_rx_gmm_ptmsi_reall_compl(struct sgsn_mm_ctx *mmctx) static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t *cur = gh->data, *mi; - uint8_t service_type, mi_len, mi_type; - uint32_t tmsi; + uint8_t *cur = gh->data, *mi_data; + uint8_t service_type, mi_len; struct tlv_parsed tp; - char mi_string[GSM48_MI_SIZE]; + struct osmo_mobile_identity mi; + char mi_log_string[32]; enum gsm48_gmm_cause reject_cause; int rc; @@ -1780,15 +1915,14 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ mi_len = *cur++; - mi = cur; - if (mi_len > 8) - goto err_inval; - mi_type = *mi & GSM_MI_TYPE_MASK; + mi_data = cur; cur += mi_len; + rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false); + if (rc) + goto err_inval; + osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi); - gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); - - DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string, get_value_string(gprs_service_t_strs, service_type)); LOGPC(DMM, LOGL_INFO, "\n"); @@ -1796,11 +1930,11 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) /* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */ tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0); - switch (mi_type) { + switch (mi.type) { case GSM_MI_TYPE_IMSI: /* Try to find MM context based on IMSI */ if (!ctx) - ctx = sgsn_mm_ctx_by_imsi(mi_string); + ctx = sgsn_mm_ctx_by_imsi(mi.imsi); if (!ctx) { /* FIXME: We need to have a context for service request? */ reject_cause = GMM_CAUSE_IMPL_DETACHED; @@ -1809,11 +1943,9 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) msgid2mmctx(ctx, msg); break; case GSM_MI_TYPE_TMSI: - memcpy(&tmsi, mi+1, 4); - tmsi = ntohl(tmsi); /* Try to find MM context based on P-TMSI */ if (!ctx) - ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi); if (!ctx) { /* FIXME: We need to have a context for service request? */ reject_cause = GMM_CAUSE_IMPL_DETACHED; @@ -1823,7 +1955,7 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) break; default: LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with " - "MI type %s\n", gsm48_mi_type_name(mi_type)); + "MI %s\n", mi_log_string); reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED; goto rejected; } @@ -1875,7 +2007,7 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); - LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n", + LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM STATUS (cause: %s)\n", get_value_string(gsm48_gmm_cause_names, gh->data[0])); return 0; @@ -1899,7 +2031,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, if (llme && !mmctx && gh->msg_type != GSM48_MT_GMM_ATTACH_REQ && gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) { - LOGGBP(llme, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n"); + LOGGBP(llme, DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n"); /* 4.7.10 */ if (gh->msg_type == GSM48_MT_GMM_STATUS) { /* TLLI unassignment */ @@ -1938,6 +2070,23 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, return rc; } + /* A RAT change is only expected/allowed for RAU/Attach Req */ + if (mmctx && mmctx_did_rat_change(mmctx, msg)) { + switch (gh->msg_type) { + case GSM48_MT_GMM_RA_UPD_REQ: + case GSM48_MT_GMM_ATTACH_REQ: + break; + default: + /* This shouldn't happen with other message types and + * we need to error out to prevent a crash */ + LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping GMM %s which was received on different " + "RAT (mmctx ran_type=%u, msg_iu_ue_ctx=%p\n", + get_value_string(gprs_msgt_gmm_names, gh->msg_type), + mmctx->ran_type, MSG_IU_UE_CTX(msg)); + return -EINVAL; + } + } + /* * For a few messages, mmctx may be NULL. For most, we want to ensure a * non-NULL mmctx. At the same time, we want to keep the message @@ -1977,7 +2126,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, if (!mmctx) goto null_mmctx; LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n"); - mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK"); + mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK"); rc = 0; break; case GSM48_MT_GMM_ATTACH_COMPL: @@ -2017,9 +2166,9 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, null_mmctx: LOGGBIUP(llme, msg, LOGL_ERROR, - "Received GSM 04.08 message type 0x%02x," + "Received GSM 04.08 message type %s," " but no MM context available\n", - gh->msg_type); + get_value_string(gprs_msgt_gmm_names, gh->msg_type)); return -EINVAL; } @@ -2086,7 +2235,7 @@ static void mmctx_timer_cb(void *_mm) if (mm->num_T_exp >= 5) { LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n"); gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED); - mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)"); + mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)"); break; } /* re-tranmit IDENTITY REQUEST and re-start timer */ @@ -2174,3 +2323,51 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli, osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RESUME, NULL); return 0; } + +/* Has to be called whenever any PDU (signaling, data, ...) has been received */ +void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) +{ + msgid2mmctx(mmctx, msg); + if (mmctx->gb.llme) + osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL); +} + +/* Main entry point for incoming 04.08 GPRS messages from Gb */ +int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, + bool drop_cipherable) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + struct gprs_ra_id ra_id; + int rc = -EINVAL; + + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); + if (mmctx) { + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN)); + mmctx->gb.llme = llme; + gprs_gb_recv_pdu(mmctx, msg); + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable); + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, llme); + break; + default: + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Unknown GSM 04.08 discriminator 0x%02x: %s\n", + pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); + /* FIXME: return status message */ + break; + } + + /* MMCTX can be invalid */ + + return rc; +} |