aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_gmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/gprs_gmm.c')
-rw-r--r--openbsc/src/gprs/gprs_gmm.c512
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 */