aboutsummaryrefslogtreecommitdiffstats
path: root/src/sgsn/gprs_gmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sgsn/gprs_gmm.c')
-rw-r--r--src/sgsn/gprs_gmm.c509
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;
+}