diff options
Diffstat (limited to 'openbsc/src/gprs/gprs_gmm.c')
-rw-r--r-- | openbsc/src/gprs/gprs_gmm.c | 512 |
1 files changed, 451 insertions, 61 deletions
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 2bbc5ff34..2304c1a01 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -31,6 +31,8 @@ #include <arpa/inet.h> #include <netdb.h> +#include <openssl/rand.h> + #include <openbsc/db.h> #include <osmocom/core/msgb.h> #include <osmocom/gsm/tlv.h> @@ -38,15 +40,17 @@ #include <osmocom/core/signal.h> #include <osmocom/core/talloc.h> #include <osmocom/core/rate_ctr.h> +#include <osmocom/crypt/auth.h> #include <osmocom/gsm/apn.h> -#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/ranap/ranap_ies_defs.h> #include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <openbsc/gsm_subscriber.h> #include <openbsc/gsm_04_08.h> +#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/paging.h> #include <openbsc/transaction.h> #include <openbsc/gprs_llc.h> @@ -55,6 +59,7 @@ #include <openbsc/gprs_utils.h> #include <openbsc/sgsn.h> #include <openbsc/signal.h> +#include <openbsc/iu.h> #include <pdp.h> @@ -95,6 +100,46 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = { static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx); +int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies); +int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data) +{ + struct sgsn_mm_ctx *mm; + int rc = -1; + + mm = sgsn_mm_ctx_by_ue_ctx(ctx); + if (!mm) { + LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type); + return rc; + } + + switch (type) { + case IU_EVENT_RAB_ASSIGN: + rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data); + break; + case IU_EVENT_IU_RELEASE: + /* fall thru */ + case IU_EVENT_LINK_INVALIDATED: + /* Clean up ue_conn_ctx here */ + LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); + if (mm->pmm_state == PMM_CONNECTED) + mm->pmm_state = PMM_IDLE; + + rc = 0; + break; + case IU_EVENT_SECURITY_MODE_COMPLETE: + /* Continue authentication here */ + mm->iu.ue_ctx->integrity_active = 1; + rc = gsm48_gmm_authorize(mm); + break; + default: + LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type); + rc = -1; + break; + } + return rc; +} + + /* Our implementation, should be kept in SGSN */ static void mmctx_timer_cb(void *_mm); @@ -135,6 +180,9 @@ static int gsm48_gmm_sendmsg(struct msgb *msg, int command, if (mm) rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]); + if (msg->dst) + return iu_tx(msg, GPRS_SAPI_GMM); + /* caller needs to provide TLLI, BVCI and NSEI */ return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm); } @@ -146,21 +194,24 @@ static void gmm_copy_id(struct msgb *msg, const struct msgb *old) msgb_tlli(msg) = msgb_tlli(old); msgb_bvci(msg) = msgb_bvci(old); msgb_nsei(msg) = msgb_nsei(old); + msg->dst = old->dst; } /* Store BVCI/NSEI in MM context */ static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg) { - mm->bvci = msgb_bvci(msg); - mm->nsei = msgb_nsei(msg); + mm->gb.bvci = msgb_bvci(msg); + mm->gb.nsei = msgb_nsei(msg); + mm->iu.ue_ctx = msg->dst; } /* Store BVCI/NSEI in MM context */ static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm) { - msgb_tlli(msg) = mm->tlli; - msgb_bvci(msg) = mm->bvci; - msgb_nsei(msg) = mm->nsei; + msgb_tlli(msg) = mm->gb.tlli; + msgb_bvci(msg) = mm->gb.bvci; + msgb_nsei(msg) = mm->gb.nsei; + msg->dst = mm->iu.ue_ctx; } static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text) @@ -169,6 +220,7 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text) /* Mark MM state as deregistered */ ctx->mm_state = GMM_DEREGISTERED; + ctx->pmm_state = PMM_DETACHED; sgsn_mm_ctx_cleanup_free(ctx); } @@ -524,10 +576,15 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, ctx->is_authenticated = 1; + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) + ctx->iu.new_key = 1; + /* FIXME: enable LLC cipheirng */ /* Check if we can let the mobile station enter */ - return gsm48_gmm_authorize(ctx); + rc = gsm48_gmm_authorize(ctx); + + return rc; } static void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx) @@ -599,9 +656,72 @@ static void extract_subscr_hlr(struct sgsn_mm_ctx *ctx) strncpy(&ctx->hlr[0], called.number, sizeof(ctx->hlr) - 1); } +/* Chapter 9.4.21: Service accept */ +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); + + mmctx2msgid(msg, mm); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_SERVICE_ACK; + + /* Optional: PDP context status */ + /* Optional: MBMS context status */ + + return gsm48_gmm_sendmsg(msg, 0, mm); +} + +/* Chapter 9.4.22: Service reject */ +static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause, + const struct sgsn_mm_ctx *mm) +{ + struct gsm48_hdr *gh; + + LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n", + get_value_string(gsm48_gmm_cause_names, gmm_cause)); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_SERVICE_REJ; + gh->data[0] = gmm_cause; + + return gsm48_gmm_sendmsg(msg, 0, NULL); +} +static int gsm48_tx_gmm_service_rej_oldmsg(const struct msgb *old_msg, + uint8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ OLD"); + gmm_copy_id(msg, old_msg); + return _tx_gmm_service_rej(msg, gmm_cause, NULL); +} +static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm, + uint8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ"); + mmctx2msgid(msg, mm); + return _tx_gmm_service_rej(msg, gmm_cause, mm); +} + +static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm); + +void activate_pdp_rabs(struct sgsn_mm_ctx *ctx) +{ + /* Send RAB activation requests for all PDP contexts */ + struct sgsn_pdp_ctx *pdp; + llist_for_each_entry(pdp, &ctx->pdp_list, list) { + iu_rab_act_ps(pdp->nsapi, pdp, 1); + } +} + /* Check if we can already authorize a subscriber */ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) { + int rc; #ifndef PTMSI_ALLOC struct sgsn_signal_data sig_data; #endif @@ -656,6 +776,11 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) } /* The MS is authorized */ + if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) { + rc = iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet, 0, ctx->iu.new_key); + ctx->iu.new_key = 0; + return rc; + } switch (ctx->pending_req) { case 0: @@ -663,6 +788,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) "no pending request, authorization completed\n"); break; case GSM48_MT_GMM_ATTACH_REQ: + ctx->pending_req = 0; extract_subscr_msisdn(ctx); extract_subscr_hlr(ctx); @@ -678,6 +804,22 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) #endif return gsm48_tx_gmm_att_ack(ctx); + case GSM48_MT_GMM_SERVICE_REQ: + /* TODO: PMM State transition */ + ctx->pending_req = 0; + ctx->pmm_state = PMM_CONNECTED; + rc = gsm48_tx_gmm_service_ack(ctx); + + if (ctx->iu.service.type == 1) { + activate_pdp_rabs(ctx); + } + + return rc; + case GSM48_MT_GMM_RA_UPD_REQ: + ctx->pending_req = 0; + /* Send RA UPDATE ACCEPT */ + return gsm48_tx_gmm_ra_upd_ack(ctx); + default: LOGMMCTXP(LOGL_ERROR, ctx, "only Attach Request is supported yet, " @@ -834,7 +976,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, uint32_t tmsi; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; - uint16_t cid; + uint16_t cid = 0; enum gsm48_gmm_cause reject_cause; int rc; @@ -844,7 +986,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + if (!msg->dst) + cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -853,8 +996,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, goto err_inval; cur += msnc_len; + /* TODO: In iu mode - handle follow-on request */ + /* aTTACH Type 10.5.5.2 */ - att_type = *cur++ & 0x0f; + att_type = *cur++ & 0x07; /* DRX parameter 10.5.5.6 */ drx_par = *cur++ << 8; @@ -896,7 +1041,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, #if 0 return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); #else - ctx = sgsn_mm_ctx_alloc(0, &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(0, &ra_id); if (!ctx) { reject_cause = GMM_CAUSE_NET_FAIL; goto rejected; @@ -904,8 +1052,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi) - 1); #endif } - ctx->tlli = msgb_tlli(msg); - ctx->llme = llme; + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { + ctx->gb.tlli = msgb_tlli(msg); + ctx->gb.llme = llme; + } msgid2mmctx(ctx, msg); break; case GSM_MI_TYPE_TMSI: @@ -917,11 +1067,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, if (!ctx) { /* Allocate a context as most of our code expects one. * Context will not have an IMSI ultil ID RESP is received */ - ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); + if (msg->dst) + ctx = sgsn_mm_ctx_alloc_iu(msg->dst); + else + ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); ctx->p_tmsi = tmsi; } - ctx->tlli = msgb_tlli(msg); - ctx->llme = llme; + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { + ctx->gb.tlli = msgb_tlli(msg); + ctx->gb.llme = llme; + } msgid2mmctx(ctx, msg); break; default: @@ -932,7 +1087,32 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, } /* Update MM Context with currient RA and Cell ID */ ctx->ra = ra_id; - ctx->cell_id = cid; + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) + ctx->gb.cell_id = cid; + else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) { + unsigned char tmp_rand[16]; + /* Ki 000102030405060708090a0b0c0d0e0f */ + struct osmo_sub_auth_data auth = { + .type = OSMO_AUTH_TYPE_GSM, + .algo = OSMO_AUTH_ALG_COMP128v1, + .u.gsm.ki = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }, + }; + //ctx->iu.sac = sac; + /* XXX: Hack to make 3G auth work with special SIM card */ + ctx->auth_state = SGSN_AUTH_AUTHENTICATE; + + RAND_bytes(tmp_rand, 16); + + memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec)); + osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand); + + ctx->auth_triplet.key_seq = 0; + } + /* Update MM Context with other data */ ctx->drx_parms = drx_par; ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len; @@ -950,13 +1130,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, } ctx->mm_state = GMM_COMMON_PROC_INIT; #endif - /* Even if there is no P-TMSI allocated, the MS will switch from - * foreign TLLI to local TLLI */ - ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); - /* Inform LLC layer about new TLLI but keep old active */ - gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new, - GPRS_ALGO_GEA0, NULL); + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { + /* Even if there is no P-TMSI allocated, the MS will + * switch from foreign TLLI to local TLLI */ + ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); + + /* Inform LLC layer about new TLLI but keep old active */ + gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new, + GPRS_ALGO_GEA0, NULL); + } ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ; return gsm48_gmm_authorize(ctx); @@ -1131,8 +1314,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, enum gsm48_gmm_cause reject_cause; int rc; + /* TODO: In iu mode - handle follow-on request */ + /* Update Type 10.5.5.18 */ - upd_type = *cur++ & 0x0f; + upd_type = *cur++ & 0x07; LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n", get_value_string(gprs_upd_t_strs, upd_type)); @@ -1165,6 +1350,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, break; } +#warning "Differentiate look-up between Iu and Gb" if (!mmctx) { /* BSSGP doesn't give us an mmctx */ @@ -1174,7 +1360,24 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, * is an optimization to avoid the RA reject (impl detached) * below, which will cause a new attach cycle. */ /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + if (!msg->dst) { + mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id); + } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { + /* 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); + 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); + } + } if (mmctx) { LOGMMCTXP(LOGL_INFO, mmctx, "Looked up by matching TLLI and P_TMSI. " @@ -1182,7 +1385,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, "TLLI: %08x (%08x), RA: %d-%d-%d-%d\n", msgb_tlli(msg), mmctx->p_tmsi, mmctx->p_tmsi_old, - mmctx->tlli, mmctx->tlli_new, + mmctx->gb.tlli, mmctx->gb.tlli_new, mmctx->ra.mcc, mmctx->ra.mnc, mmctx->ra.lac, mmctx->ra.rac); @@ -1200,10 +1403,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, } if (!mmctx) { - /* send a XID reset to re-set all LLC sequence numbers - * in the MS */ - LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n"); - gprs_llgmm_reset(llme); + if (llme) { + /* send a XID reset to re-set all LLC sequence numbers + * in the MS */ + LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n"); + gprs_llgmm_reset(llme); + } /* The MS has to perform GPRS attach */ /* Device is still IMSI attached for CS but initiate GPRS ATTACH, * see GSM 04.08, 4.7.5.1.4 and G.6 */ @@ -1217,9 +1422,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); /* Update the MM context with the new RA-ID */ - bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg)); - /* Update the MM context with the new (i.e. foreign) TLLI */ - mmctx->tlli = msgb_tlli(msg); +#warning "how to obtain RA_ID in Iu case?" + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + 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); + } /* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ @@ -1244,13 +1452,16 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, sig_data.mm = mmctx; osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data); #endif - /* Even if there is no P-TMSI allocated, the MS will switch from - * foreign TLLI to local TLLI */ - mmctx->tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL); - - /* Inform LLC layer about new TLLI but keep old active */ - gprs_llgmm_assign(mmctx->llme, mmctx->tlli, mmctx->tlli_new, - GPRS_ALGO_GEA0, NULL); + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + /* Even if there is no P-TMSI allocated, the MS will switch from + * foreign TLLI to local TLLI */ + mmctx->gb.tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL); + + /* Inform LLC layer about new TLLI but keep old active */ + gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli, + mmctx->gb.tlli_new, GPRS_ALGO_GEA0, + NULL); + } /* Look at PDP Context Status IE and see if MS's view of * activated/deactivated NSAPIs agrees with our view */ @@ -1259,8 +1470,9 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, process_ms_ctx_status(mmctx, pdp_status); } + mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ; /* Send RA UPDATE ACCEPT */ - return gsm48_tx_gmm_ra_upd_ack(mmctx); + return gsm48_gmm_authorize(mmctx); rejected: /* Send RA UPDATE REJECT */ @@ -1270,14 +1482,126 @@ rejected: rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause); if (mmctx) mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ"); - else - /* TLLI unassignment */ - gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, - NULL); + else { + if (llme) { + /* TLLI unassignment */ + gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, + GPRS_ALGO_GEA0, NULL); + } + } return rc; } +/* 3GPP TS 24.008 Section 9.4.20 Service request */ +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 ciph_seq_nr, service_type, mi_len, mi_type; + uint32_t tmsi; + struct tlv_parsed tp; + char mi_string[GSM48_MI_SIZE]; + uint16_t cid = 0; + enum gsm48_gmm_cause reject_cause; + int rc; + + LOGMMCTXP(LOGL_INFO, ctx, "-> GMM SERVICE REQUEST "); + + /* This message is only valid in Iu mode */ + if (!msg->dst) { + LOGPC(DMM, LOGL_INFO, "Invalid if not in Iu mode\n"); + return -1; + } + + /* Skip Ciphering key sequence number 10.5.1.2 */ + ciph_seq_nr = *cur & 0x07; + + /* Service type 10.5.5.20 */ + service_type = (*cur++ >> 4) & 0x07; + + /* 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; + cur += mi_len; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, + get_value_string(gprs_service_t_strs, service_type)); + + LOGPC(DMM, LOGL_INFO, "\n"); + + /* 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) { + case GSM_MI_TYPE_IMSI: + /* Try to find MM context based on IMSI */ + if (!ctx) + ctx = sgsn_mm_ctx_by_imsi(mi_string); + if (!ctx) { + /* FIXME: We need to have a context for service request? */ + reject_cause = GMM_CAUSE_NET_FAIL; + goto rejected; + } + 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); + if (!ctx) { + /* FIXME: We need to have a context for service request? */ + reject_cause = GMM_CAUSE_NET_FAIL; + goto rejected; + } + msgid2mmctx(ctx, msg); + break; + default: + LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with " + "MI type %s\n", gsm48_mi_type_name(mi_type)); + reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED; + goto rejected; + } + + ctx->mm_state = GMM_COMMON_PROC_INIT; + + ctx->iu.service.type = service_type; + + /* TODO: Handle those only in case of accept? */ + /* Look at PDP Context Status IE and see if MS's view of + * activated/deactivated NSAPIs agrees with our view */ + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) { + const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS); + process_ms_ctx_status(ctx, pdp_status); + } + + + ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ; + return gsm48_gmm_authorize(ctx); + +err_inval: + LOGPC(DMM, LOGL_INFO, "\n"); + reject_cause = GMM_CAUSE_SEM_INCORR_MSG; + +rejected: + /* Send SERVICE REJECT */ + LOGMMCTXP(LOGL_NOTICE, ctx, + "Rejecting Service Request with cause '%s' (%d)\n", + get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause); + rc = gsm48_tx_gmm_service_rej_oldmsg(msg, reject_cause); + + return rc; + +} + + static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -1298,7 +1622,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* MMCTX can be NULL when called */ - if (!mmctx && + if (llme && !mmctx && gh->msg_type != GSM48_MT_GMM_ATTACH_REQ && gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) { LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n"); @@ -1346,7 +1670,20 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, case GSM48_MT_GMM_ATTACH_REQ: rc = gsm48_rx_gmm_att_req(mmctx, msg, llme); break; + case GSM48_MT_GMM_SERVICE_REQ: + rc = gsm48_rx_gmm_service_req(mmctx, msg); + break; + default: + break; + } + /* For all the following types mmctx can not be NULL */ + if (!mmctx) { + /* FIXME: return some error? */ + return -1; + } + + switch (gh->msg_type) { case GSM48_MT_GMM_ID_RESP: rc = gsm48_rx_gmm_id_resp(mmctx, msg); break; @@ -1368,11 +1705,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx->t3350_mode = GMM_T3350_MODE_NONE; mmctx->p_tmsi_old = 0; mmctx->pending_req = 0; - /* Unassign the old TLLI */ - mmctx->tlli = mmctx->tlli_new; - gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, - GPRS_ALGO_GEA0, NULL); + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + /* Unassign the old TLLI */ + mmctx->gb.tlli = mmctx->gb.tlli_new; + gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, + mmctx->gb.tlli_new, + GPRS_ALGO_GEA0, NULL); + } mmctx->mm_state = GMM_REGISTERED_NORMAL; + mmctx->pmm_state = PMM_CONNECTED; rc = 0; memset(&sig_data, 0, sizeof(sig_data)); @@ -1386,11 +1727,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx->t3350_mode = GMM_T3350_MODE_NONE; mmctx->p_tmsi_old = 0; mmctx->pending_req = 0; - /* Unassign the old TLLI */ - mmctx->tlli = mmctx->tlli_new; - gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, - GPRS_ALGO_GEA0, NULL); + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + /* Unassign the old TLLI */ + mmctx->gb.tlli = mmctx->gb.tlli_new; + gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new, + GPRS_ALGO_GEA0, NULL); + } mmctx->mm_state = GMM_REGISTERED_NORMAL; + mmctx->pmm_state = PMM_CONNECTED; + activate_pdp_rabs(mmctx); rc = 0; memset(&sig_data, 0, sizeof(sig_data)); @@ -1403,9 +1748,11 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx->t3350_mode = GMM_T3350_MODE_NONE; mmctx->p_tmsi_old = 0; mmctx->pending_req = 0; - /* Unassign the old TLLI */ - mmctx->tlli = mmctx->tlli_new; - //gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, GPRS_ALGO_GEA0, NULL); + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) { + /* Unassign the old TLLI */ + mmctx->gb.tlli = mmctx->gb.tlli_new; + //gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new, GPRS_ALGO_GEA0, NULL); + } rc = 0; break; case GSM48_MT_GMM_AUTH_CIPH_RESP: @@ -2077,7 +2424,8 @@ int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg) int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx) { int rc; - gprs_llgmm_reset(mmctx->llme); + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) + gprs_llgmm_reset(mmctx->gb.llme); rc = gsm48_tx_gmm_detach_req( mmctx, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED); @@ -2087,8 +2435,50 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx) return rc; } -/* Main entry point for incoming 04.08 GPRS messages */ -int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme) +/* Main entry point for incoming 04.08 GPRS messages from Iu */ +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + int rc = -EINVAL; + + DEBUGP(DMM, "grps_rcvmsg_iu(%s)\n", osmo_hexdump(msgb_gmmh(msg), msgb_l3len(msg))); + + mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst); + if (mmctx) { + rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + if (ra_id) + memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra)); + //if (sai) + //mmctx->iu.sai = *sai; + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, NULL); + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, NULL); + 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; +} + +/* Main entry point for incoming 04.08 GPRS messages from Gb */ +int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t pdisc = gsm48_hdr_pdisc(gh); @@ -2101,7 +2491,7 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme) if (mmctx) { msgid2mmctx(mmctx, msg); rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); - mmctx->llme = llme; + mmctx->gb.llme = llme; } /* MMCTX can be NULL */ |