aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_gmm.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-07-03 11:09:06 +0200
committerHarald Welte <laforge@gnumonks.org>2010-07-03 11:09:06 +0200
commit4b6ac1edb95f40022bb1cf918a61412a4358b648 (patch)
tree2985c659738fbc76b1ad67c9f0f08ebcfa28c251 /openbsc/src/gprs/gprs_gmm.c
parent3e2e159707c48e8eb52549989eee849417264c97 (diff)
[SGSN] Initial work on GMM authentication and ciphering
Diffstat (limited to 'openbsc/src/gprs/gprs_gmm.c')
-rw-r--r--openbsc/src/gprs/gprs_gmm.c112
1 files changed, 103 insertions, 9 deletions
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");