diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index baa513b2f..8de636293 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -63,6 +63,7 @@ #define GPRS_UPD_T_PERIODIC 3 enum gsm48_gprs_ie_mm { + GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */ GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */ @@ -120,6 +121,22 @@ struct gsm48_attach_ack { uint8_t data[0]; } __attribute__((packed)); +/* Chapter 9.4.9 / Table 9.4.9 */ +struct gsm48_auth_ciph_req { + uint8_t ciph_alg:4, /* 10.5.5.3 */ + imeisv_req:4; /* 10.5.5.10 */ + uint8_t force_stby:4, /* 10.5.5.7 */ + ac_ref_nr:4; /* 10.5.5.19 */ + uint8_t data[0]; +} __attribute__((packed)); +/* optional: TV RAND, TV CKSN */ + +struct gsm48_auth_ciph_resp { + uint8_t ac_ref_nr:4, + spare:4; + uint8_t data[0]; +} __attribute__((packed)); + /* Chapter 9.5.1 / Table 9.5.1 */ struct gsm48_act_pdp_ctx_req { uint8_t req_nsapi; diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 07be90296..e07180272 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -167,13 +167,14 @@ const struct value_string gprs_det_t_mo_strs[] = { static const struct tlv_definition gsm48_gmm_att_tlvdef = { .def = { + [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 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_TV, 3 }, - [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_TV, 16 }, - [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_TV, 4 }, + [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 }, + [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_FIXED, 16 }, + [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_FIXED, 4 }, [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 }, - [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_TV, 2 }, + [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 }, [GSM48_IE_GMM_PS_LCS_CAPA] = { TLV_TYPE_TLV, 0 }, @@ -189,8 +190,8 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = { [GSM48_IE_GSM_AA_TMR] = { TLV_TYPE_TV, 1 }, [GSM48_IE_GSM_NAME_FULL] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GSM_NAME_SHORT] = { TLV_TYPE_TLV, 0 }, - [GSM48_IE_GSM_TIMEZONE] = { TLV_TYPE_TV, 1 }, - [GSM48_IE_GSM_UTC_AND_TZ] = { TLV_TYPE_TV, 7 }, + [GSM48_IE_GSM_TIMEZONE] = { TLV_TYPE_FIXED, 1 }, + [GSM48_IE_GSM_UTC_AND_TZ] = { TLV_TYPE_FIXED, 7 }, [GSM48_IE_GSM_LSA_ID] = { TLV_TYPE_TLV, 0 }, }, }; @@ -447,6 +448,92 @@ static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type) return gsm48_gmm_sendmsg(msg, 1, mm); } +/* Section 9.4.9: Authentication and Ciphering Request */ +static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rand, + uint8_t key_seq, uint8_t algo) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm48_auth_ciph_req *acreq; + uint8_t *m_rand, *m_cksn; + + DEBUGP(DMM, "<- GPRS AUTH AND CIPHERING REQ (rand = %s)\n", + hexdump(rand, 16)); + + 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_AUTH_CIPH_REQ; + + acreq = (struct gsm48_auth_ciph_req *) msgb_put(msg, sizeof(*acreq)); + acreq->ciph_alg = algo & 0xf; + acreq->imeisv_req = 0x1; + acreq->force_stby = 0x0; + acreq->ac_ref_nr = 0x0; /* FIXME: increment this? */ + + /* Only if authentication is requested we need to set RAND + CKSN */ + if (rand) { + m_rand = msgb_put(msg, 16+1); + m_rand[0] = GSM48_IE_GMM_AUTH_RAND; + memcpy(m_rand+1, rand, 16); + + m_cksn = msgb_put(msg, 1+1); + m_cksn[0] = GSM48_IE_GMM_CIPH_CKSN; + m_cksn[1] = key_seq; + } + + /* Start T3360 */ + mmctx_timer_start(mm, 3360, GSM0408_T3360_SECS); + + /* FIXME: make sure we don't send any other messages to the MS */ + + return gsm48_gmm_sendmsg(msg, 1, mm); +} + +/* Section 9.4.11: Authentication and Ciphering Reject */ +static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "<- GPRS AUTH AND CIPH REJECT\n"); + + 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_AUTH_CIPH_REJ; + + return gsm48_gmm_sendmsg(msg, 0, mm); +} + +/* Section 9.4.10: Authentication and Ciphering Response */ +static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, + struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + struct gsm48_auth_ciph_resp *acr = (struct gsm48_auth_ciph_resp *)gh->data; + struct tlv_parsed tp; + int rc; + + /* FIXME: Stop T3360 */ + + rc = tlv_parse(&tp, &gsm48_gmm_att_tlvdef, acr->data, + (msg->data + msg->len) - acr->data, 0, 0); + + /* FIXME: compare ac_ref? */ + + if (!TLVP_PRESENT(&tp, GSM48_IE_GMM_AUTH_SRES) || + !TLVP_PRESENT(&tp, GSM48_IE_GMM_IMEISV)) { + /* FIXME: missing mandatory IE */ + } + + /* FIXME: compare SRES with what we expected */ + /* FIXME: enable LLC cipheirng */ + return 0; +} + /* Check if we can already authorize a subscriber */ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, enum gprs_t3350_mode t3350_mode) @@ -925,9 +1012,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, //gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, GPRS_ALGO_GEA0, NULL); break; case GSM48_MT_GMM_AUTH_CIPH_RESP: - DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n", - gh->msg_type); - rc = gsm48_tx_gmm_status(mmctx, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL); + rc = gsm48_rx_gmm_auth_ciph_resp(mmctx, msg); break; default: DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n", @@ -967,6 +1052,15 @@ static void mmctx_timer_cb(void *_mm) } bsc_schedule_timer(&mm->timer, GSM0408_T3350_SECS, 0); break; + case 3360: /* waiting for AUTH AND CIPH RESP */ + if (mm->num_T_exp >= 5) { + LOGP(DMM, LOGL_NOTICE, "T3360 expired >= 5 times\n"); + mm->mm_state = GMM_DEREGISTERED; + break; + } + /* FIXME: re-transmit the respective msg and re-start timer */ + bsc_schedule_timer(&mm->timer, GSM0408_T3360_SECS, 0); + break; case 3370: /* waiting for IDENTITY RESPONSE */ if (mm->num_T_exp >= 5) { LOGP(DMM, LOGL_NOTICE, "T3370 expired >= 5 times\n");