diff options
Diffstat (limited to 'src/sgsn/gprs_gmm.c')
-rw-r--r-- | src/sgsn/gprs_gmm.c | 218 |
1 files changed, 163 insertions, 55 deletions
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c index 0ad600376..c3f5cd3d2 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 }, @@ -131,7 +133,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 +199,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 +217,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 +243,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)); @@ -281,15 +283,17 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm) struct gsm48_hdr *gh; struct gsm48_attach_ack *aa; 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); @@ -340,6 +344,9 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm) /* 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); } @@ -349,9 +356,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; @@ -383,8 +390,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; @@ -416,7 +423,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); @@ -440,6 +447,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, @@ -451,7 +469,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); @@ -514,7 +532,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); @@ -594,7 +612,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, @@ -645,7 +663,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; } @@ -668,7 +686,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); @@ -708,7 +726,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; } @@ -787,7 +805,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); @@ -808,7 +826,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); @@ -900,7 +918,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; } @@ -922,16 +946,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) @@ -1082,7 +1106,7 @@ 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_ARRAY(ctx->imsi, mi.imsi); @@ -1142,6 +1166,21 @@ static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *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) @@ -1158,7 +1197,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, 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), @@ -1285,15 +1324,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 " - "%s because MS do not support required %s " - "encryption\n", mi_log_string, - 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); @@ -1325,7 +1376,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); @@ -1338,7 +1389,7 @@ 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 if (mmctx->iu.ue_ctx) { @@ -1405,7 +1456,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" : ""); @@ -1425,7 +1476,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; @@ -1438,12 +1489,14 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm) struct gsm48_hdr *gh; struct gsm48_ra_upd_ack *rua; 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); @@ -1498,7 +1551,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); @@ -1533,7 +1586,10 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx, 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); + if (pdp->ggsn) + sgsn_delete_pdp_ctx(pdp); + else /* GTP side already detached, freeing */ + sgsn_pdp_ctx_free(pdp); } } @@ -1575,7 +1631,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)); @@ -1703,7 +1759,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* 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 && msgb_bcid(msg)) { @@ -1711,10 +1767,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *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); @@ -1724,7 +1784,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; @@ -1760,7 +1820,7 @@ 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 @@ -1942,7 +2002,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; @@ -2061,7 +2121,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: @@ -2101,9 +2161,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; } @@ -2170,7 +2230,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 */ @@ -2258,3 +2318,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; +} |