[PATCH] openbsc[master]: Add preliminary support for GPRS encryption

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Max gerrit-no-reply at lists.osmocom.org
Tue Jul 5 10:10:38 UTC 2016


Review at  https://gerrit.osmocom.org/460

Add preliminary support for GPRS encryption

It is already functional enough to allow testing with real
phones. However, note - there are several limitations in the current
implementation:

* only default value for IOV-UI is supported at the moment
* A&C reference number is not validated
* incorrect cleartext frames are not dropped
* AUTN-based key material is not supported

FCS-related corrections were contributed by Dieter Spaar.

Change-Id: I8900b906693496e4e6b35be5a86937c58039ed9e
Related: OS#1582
---
M openbsc/include/openbsc/gprs_gmm.h
M openbsc/include/openbsc/gprs_llc.h
M openbsc/include/openbsc/gprs_sgsn.h
M openbsc/src/gprs/gprs_gmm.c
M openbsc/src/gprs/gprs_llc.c
M openbsc/src/gprs/gprs_sgsn.c
M openbsc/src/gprs/gprs_sndcp.c
M openbsc/src/gprs/sgsn_main.c
8 files changed, 118 insertions(+), 90 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/60/460/1

diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h
index e0d8f77..044978b 100644
--- a/openbsc/include/openbsc/gprs_gmm.h
+++ b/openbsc/include/openbsc/gprs_gmm.h
@@ -12,7 +12,8 @@
 
 int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme);
 int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
-int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg);
+int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
+				       struct gprs_llc_llme *llme);
 void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
 void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause);
 void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause);
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index 8cd0c26..8a44741 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -2,6 +2,7 @@
 #define _GPRS_LLC_H
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <openbsc/gprs_sgsn.h>
 
 /* Section 4.7 LLC Layer Structure */
@@ -155,7 +156,10 @@
 
 	/* Crypto parameters */
 	enum gprs_ciph_algo algo;
-	uint8_t kc[8];
+	uint8_t kc[16];
+	uint8_t cksn;
+	/* 3GPP TS 44.064 § 8.9.2: */
+	uint32_t iov_ui;
 
 	/* over which BSSGP BTS ctx do we need to transmit */
 	uint16_t bvci;
@@ -208,16 +212,16 @@
 
 /* LL-UNITDATA.req */
 int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
-		   void *mmctx);
+		   struct sgsn_mm_ctx *mmctx, bool encryptable);
 
 /* Chapter 7.2.1.2 LLGMM-RESET.req */
 int gprs_llgmm_reset(struct gprs_llc_llme *llme);
-int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi);
+int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
+			    struct gprs_llc_llme *llme);
 
 /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
 int gprs_llgmm_assign(struct gprs_llc_llme *llme,
-		      uint32_t old_tlli, uint32_t new_tlli,
-		      enum gprs_ciph_algo alg, const uint8_t *kc);
+		      uint32_t old_tlli, uint32_t new_tlli);
 int gprs_llgmm_unassign(struct gprs_llc_llme *llme);
 
 int gprs_llc_init(const char *cipher_plugin_path);
@@ -240,6 +244,7 @@
 }
 
 /* LLC low level functions */
+void gprs_llme_set_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
 
 /* parse a GPRS LLC header, also check for invalid frames */
 int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 0e574d8..f8ce2b1 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -355,9 +355,6 @@
 
 char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
 
-/* Force re-attachment based on msgb meta data */
-int sgsn_force_reattach_oldmsg(struct msgb *oldmsg);
-
 /*
  * ctrl interface related work
  */
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index 5db69dd..2cb2a2b 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -26,7 +26,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <errno.h>
-
+#include <stdbool.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -130,13 +130,13 @@
 
 /* Send a message through the underlying layer */
 static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
-			     struct sgsn_mm_ctx *mm)
+			     struct sgsn_mm_ctx *mm, bool encryptable)
 {
 	if (mm)
 		rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
 
 	/* caller needs to provide TLLI, BVCI and NSEI */
-	return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
+	return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm, encryptable);
 }
 
 /* copy identifiers from old message to new message, this
@@ -194,7 +194,7 @@
 	}
 	gh->data[0] = cause;
 
-	return gsm48_gmm_sendmsg(msg, 0, mmctx);
+	return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
 }
 
 static int gsm48_tx_gmm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
@@ -232,7 +232,7 @@
 
 	msgb_tv_put(msg, GSM48_IE_GMM_CAUSE, cause);
 
-	return gsm48_gmm_sendmsg(msg, 0, mmctx);
+	return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
 }
 
 static int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx,
@@ -328,7 +328,7 @@
 	/* Optional: MS-identity (combined attach) */
 	/* Optional: GMM cause (partial attach result for combined attach) */
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 
 /* Chapter 9.4.5: Attach reject */
@@ -345,7 +345,7 @@
 	gh->msg_type = GSM48_MT_GMM_ATTACH_REJ;
 	gh->data[0] = gmm_cause;
 
-	return gsm48_gmm_sendmsg(msg, 0, NULL);
+	return gsm48_gmm_sendmsg(msg, 0, NULL, false);
 }
 static int gsm48_tx_gmm_att_rej_oldmsg(const struct msgb *old_msg,
 					uint8_t gmm_cause)
@@ -377,7 +377,7 @@
 	gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
 	gh->data[0] = force_stby;
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 
 static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
@@ -413,12 +413,12 @@
 	/* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */
 	gh->data[0] = id_type & 0xf;
 
-	return gsm48_gmm_sendmsg(msg, 1, mm);
+	return gsm48_gmm_sendmsg(msg, 1, mm, false);
 }
 
-/* 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)
+/* 3GPP TS 24.008 Section 9.4.9: Authentication and Ciphering Request */
+static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rnd,
+				      uint8_t key_seq, bool force_standby)
 {
 	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REQ");
 	struct gsm48_hdr *gh;
@@ -426,7 +426,7 @@
 	uint8_t *m_rand, *m_cksn;
 
 	LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s)\n",
-		osmo_hexdump(rand, 16));
+		osmo_hexdump(rnd, 16));
 
 	mmctx2msgid(msg, mm);
 
@@ -435,24 +435,29 @@
 	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->ciph_alg = mm->ciph_algo & 0xf;
+	/* § 10.5.5.10: */
 	acreq->imeisv_req = 0x1;
-	acreq->force_stby = 0x0;
-	acreq->ac_ref_nr = 0x0;	/* FIXME: increment this? */
+	/* § 10.5.5.7: */
+	acreq->force_stby = force_standby;
+	/* 3GPP TS 24.008 § 10.5.5.19 */
+	acreq->ac_ref_nr = rand();
+	/* FIXME: store ref_nr and check that received response matches it */
 
 	/* Only if authentication is requested we need to set RAND + CKSN */
-	if (rand) {
+	if (rnd) {
 		m_rand = msgb_put(msg, 16+1);
 		m_rand[0] = GSM48_IE_GMM_AUTH_RAND;
-		memcpy(m_rand+1, rand, 16);
-
+		memcpy(m_rand + 1, rnd, 16);
+		/* § 10.5.1.2: */
 		m_cksn = msgb_put(msg, 1);
 		m_cksn[0] = (GSM48_IE_GMM_CIPH_CKSN << 4) | (key_seq & 0x07);
 	}
+	/* FIXME: add AUTN for 3g auth according to 3GPP TS 24.008 § 10.5.3.1.1 */
 
 	/* FIXME: make sure we don't send any other messages to the MS */
 
-	return gsm48_gmm_sendmsg(msg, 1, mm);
+	return gsm48_gmm_sendmsg(msg, 1, mm, false);
 }
 
 /* Section 9.4.11: Authentication and Ciphering Reject */
@@ -469,7 +474,7 @@
 	gh->proto_discr = GSM48_PDISC_MM_GPRS;
 	gh->msg_type = GSM48_MT_GMM_AUTH_CIPH_REJ;
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, false);
 }
 
 /* Section 9.4.10: Authentication and Ciphering Response */
@@ -638,8 +643,7 @@
 
 		mmctx_timer_start(ctx, 3360, sgsn->cfg.timers.T3360);
 		return gsm48_tx_gmm_auth_ciph_req(ctx, at->vec.rand,
-						  at->key_seq,
-						  GPRS_ALGO_GEA0);
+						  at->key_seq, false);
 	}
 
 	if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && ctx->is_authenticated &&
@@ -962,8 +966,10 @@
 		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);
+		if (ctx->is_authenticated) {
+			gprs_llme_set_key(ctx, ctx->gb.llme);
+		}
+		gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new);
 	}
 
 	ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
@@ -1069,7 +1075,7 @@
 		    gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3314));
 
 	/* Option: MS ID, ... */
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 
 /* Chapter 9.4.17: Routing area update reject */
@@ -1089,7 +1095,7 @@
 	gh->data[1] = 0; /* ? */
 
 	/* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
-	return gsm48_gmm_sendmsg(msg, 0, NULL);
+	return gsm48_gmm_sendmsg(msg, 0, NULL, false);
 }
 
 static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
@@ -1262,8 +1268,7 @@
 
 		/* 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);
+				  mmctx->gb.tlli_new);
 	}
 
 	/* Look at PDP Context Status IE and see if MS's view of
@@ -1340,7 +1345,7 @@
 		}
 
 		/* Force the MS to re-attach */
-		rc = sgsn_force_reattach_oldmsg(msg);
+		rc = gsm0408_gprs_force_reattach_oldmsg(msg, llme);
 
 		/* TLLI unassignment */
 		gprs_llgmm_unassign(llme);
@@ -1398,9 +1403,9 @@
 		if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
 			/* Unassign the old TLLI */
 			mmctx->gb.tlli = mmctx->gb.tlli_new;
+			gprs_llme_set_key(mmctx, mmctx->gb.llme);
 			gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
-					  mmctx->gb.tlli_new,
-					  GPRS_ALGO_GEA0, NULL);
+					  mmctx->gb.tlli_new);
 		}
 		mmctx->mm_state = GMM_REGISTERED_NORMAL;
 		rc = 0;
@@ -1421,8 +1426,8 @@
 		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);
+			gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
+					  mmctx->gb.tlli_new);
 		}
 		mmctx->mm_state = GMM_REGISTERED_NORMAL;
 		rc = 0;
@@ -1519,8 +1524,7 @@
 		}
 		at = &mm->auth_triplet;
 
-		gsm48_tx_gmm_auth_ciph_req(mm, at->vec.rand, at->key_seq,
-					   GPRS_ALGO_GEA0);
+		gsm48_tx_gmm_auth_ciph_req(mm, at->vec.rand, at->key_seq, false);
 		osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3360, 0);
 		break;
 	case 3370:	/* waiting for IDENTITY RESPONSE */
@@ -1623,7 +1627,7 @@
 
 	/* Optional: Packet Flow Identifier */
 
-	return gsm48_gmm_sendmsg(msg, 0, pdp->mm);
+	return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);
 }
 
 /* Section 9.5.3: Activate PDP Context reject */
@@ -1646,7 +1650,7 @@
 	if (pco_len && pco_v)
 		msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 
 /* Section 9.5.8: Deactivate PDP Context Request */
@@ -1667,7 +1671,7 @@
 
 	msgb_v_put(msg, sm_cause);
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause)
 {
@@ -1691,7 +1695,7 @@
 	gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
 	gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;
 
-	return gsm48_gmm_sendmsg(msg, 0, mm);
+	return gsm48_gmm_sendmsg(msg, 0, mm, true);
 }
 int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)
 {
@@ -2079,7 +2083,7 @@
 		if (gh->msg_type == GSM48_MT_GSM_STATUS)
 			return 0;
 
-		return sgsn_force_reattach_oldmsg(msg);
+		return gsm0408_gprs_force_reattach_oldmsg(msg, llme);
 	}
 
 	switch (gh->msg_type) {
@@ -2113,10 +2117,11 @@
 	return rc;
 }
 
-int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg)
+int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
+				       struct gprs_llc_llme *llme)
 {
 	int rc;
-	gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM);
+	gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme);
 
 	rc = gsm48_tx_gmm_detach_req_oldmsg(
 		msg, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 64d22b3..807b1b5 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -21,6 +21,7 @@
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/linuxlist.h>
@@ -236,6 +237,7 @@
 	llme->old_tlli = 0xffffffff;
 	llme->state = GPRS_LLMS_UNASSIGNED;
 	llme->age_timestamp = GPRS_LLME_RESET_AGE;
+	llme->cksn = GSM_KEY_SEQ_INVAL;
 
 	for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
 		lle_init(llme, i);
@@ -343,9 +345,12 @@
 	return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
 }
 
-/* Transmit a UI frame over the given SAPI */
+/* Transmit a UI frame over the given SAPI:
+   'encryptable' indicates whether particular message can be encrypted according
+   to 3GPP TS 24.008 § 4.7.1.2
+ */
 int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
-		   void *mmctx)
+		   struct sgsn_mm_ctx *mmctx, bool encryptable)
 {
 	struct gprs_llc_lle *lle;
 	uint8_t *fcs, *llch;
@@ -365,6 +370,8 @@
 		msgb_free(msg);
 		return -EFBIG;
 	}
+
+	gprs_llme_set_key(mmctx, lle->llme);
 
 	/* Update LLE's (BVCI, NSEI) tuple */
 	lle->llme->bvci = msgb_bvci(msg);
@@ -404,8 +411,7 @@
 	fcs[2] = (fcs_calc >> 16) & 0xff;
 
 	/* encrypt information field + FCS, if needed! */
-	if (lle->llme->algo != GPRS_ALGO_GEA0) {
-		uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
+	if (lle->llme->algo != GPRS_ALGO_GEA0 && encryptable) {
 		uint16_t crypt_len = (fcs + 3) - (llch + 3);
 		uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
 		uint32_t iv;
@@ -413,7 +419,7 @@
 		uint8_t *kc = lle->llme->kc;
 
 		/* Compute the 'Input' Paraemeter */
-		iv = gprs_cipher_gen_input_ui(iov_ui, sapi, nu, oc);
+		iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi, nu, oc);
 
 		/* Compute the keystream that we need to XOR with the data */
 		rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
@@ -424,12 +430,16 @@
 			return rc;
 		}
 
+		/* Mark frame as encrypted and update FCS */
+		llch[2] |= 0x02;
+		fcs_calc = gprs_llc_fcs(llch, fcs - llch);
+		fcs[0] = fcs_calc & 0xff;
+		fcs[1] = (fcs_calc >> 8) & 0xff;
+		fcs[2] = (fcs_calc >> 16) & 0xff;
+
 		/* XOR the cipher output with the information field + FCS */
 		for (i = 0; i < crypt_len; i++)
 			*(llch + 3 + i) ^= cipher_out[i];
-
-		/* Mark frame as encrypted */
-		ctrl[1] |= 0x02;
 	}
 
 	/* Identifiers passed down: (BVCI, NSEI) */
@@ -595,7 +605,8 @@
 		case GPRS_SAPI_SNDCP9:
 		case GPRS_SAPI_SNDCP11:
 			/* Ask an upper layer for help. */
-			return sgsn_force_reattach_oldmsg(msg);
+			return gsm0408_gprs_force_reattach_oldmsg(msg,
+								  lle->llme);
 		default:
 			break;
 		}
@@ -607,7 +618,6 @@
 
 	/* decrypt information field + FCS, if needed! */
 	if (llhp.is_encrypted) {
-		uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
 		uint16_t crypt_len = llhp.data_len + 3;
 		uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
 		uint32_t iv;
@@ -620,7 +630,7 @@
 			return 0;
 		}
 
-		iv = gprs_cipher_gen_input_ui(iov_ui, lle->sapi, llhp.seq_tx,
+		iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, lle->sapi, llhp.seq_tx,
 						lle->oc_ui_recv);
 		rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
 				     kc, iv, GPRS_CIPH_MS2SGSN);
@@ -633,11 +643,15 @@
 		/* XOR the cipher output with the information field + FCS */
 		for (i = 0; i < crypt_len; i++)
 			*(llhp.data + i) ^= cipher_out[i];
+
+		llhp.fcs = *(llhp.data + crypt_len - 3);
+		llhp.fcs |= *(llhp.data + crypt_len - 2) << 8;
+		llhp.fcs |= *(llhp.data + crypt_len - 1) << 16;
 	} else {
-		if (lle->llme->algo != GPRS_ALGO_GEA0) {
+		if (lle->llme->algo != GPRS_ALGO_GEA0 &&
+		    lle->llme->cksn != GSM_KEY_SEQ_INVAL) {
 			LOGP(DLLC, LOGL_NOTICE, "unencrypted frame for LLC "
-				"that is supposed to be encrypted. Dropping.\n");
-			return 0;
+				"that could be expected to be encrypted.\n");
 		}
 	}
 
@@ -687,17 +701,26 @@
 	return rc;
 }
 
+/* Propagate crypto parameter MM -> LLME */
+void gprs_llme_set_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
+{
+	if (mm->ciph_algo != GPRS_ALGO_GEA0) {
+		llme->algo = mm->ciph_algo;
+		if (llme->cksn != mm->auth_triplet.key_seq &&
+		    mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
+			memcpy(llme->kc, mm->auth_triplet.vec.kc,
+			       gprs_cipher_key_length(mm->ciph_algo));
+			llme->cksn = mm->auth_triplet.key_seq;
+		}
+	} else
+		llme->cksn = GSM_KEY_SEQ_INVAL;
+}
+
 /* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
 int gprs_llgmm_assign(struct gprs_llc_llme *llme,
-		      uint32_t old_tlli, uint32_t new_tlli,
-		      enum gprs_ciph_algo alg, const uint8_t *kc)
+		      uint32_t old_tlli, uint32_t new_tlli)
 {
 	unsigned int i;
-
-	/* Update the crypto parameters */
-	llme->algo = alg;
-	if (alg != GPRS_ALGO_GEA0)
-		memcpy(llme->kc, kc, sizeof(llme->kc));
 
 	if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
 		/* TLLI Assignment 8.3.1 */
@@ -748,21 +771,19 @@
 /* TLLI unassignment */
 int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
 {
-	return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0,
-				 NULL);
+	return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff);
 }
 
 /* Chapter 7.2.1.2 LLGMM-RESET.req */
 int gprs_llgmm_reset(struct gprs_llc_llme *llme)
 {
 	struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
-	int random = rand();
 	struct gprs_llc_lle *lle = &llme->lle[1];
-
+	llme->iov_ui = rand();
 	/* First XID component must be RESET */
 	msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
 	/* randomly select new IOV-UI */
-	msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
+	msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui);
 
 	/* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */
 	lle->vu_recv = 0;
@@ -774,15 +795,16 @@
 	return gprs_llc_tx_xid(lle, msg, 1);
 }
 
-int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi)
+int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
+			    struct gprs_llc_llme *llme)
 {
 	struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
-	int random = rand();
+	llme->iov_ui = rand();
 
 	/* First XID component must be RESET */
 	msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
 	/* randomly select new IOV-UI */
-	msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
+	msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &llme->iov_ui);
 
 	/* FIXME: Start T200, wait for XID response */
 
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 98439de..c2f2d5b 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -169,6 +169,7 @@
 	ctx->gb.tlli = tlli;
 	ctx->mm_state = GMM_DEREGISTERED;
 	ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
+	ctx->ciph_algo = sgsn->cfg.cipher;
 	ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
 	INIT_LLIST_HEAD(&ctx->pdp_list);
 
@@ -244,7 +245,7 @@
 
 	if (llme) {
 		/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
-		gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
+		gprs_llgmm_assign(llme, tlli, 0xffffffff);
 	}
 }
 
@@ -602,11 +603,6 @@
 	}
 
 	return num;
-}
-
-int sgsn_force_reattach_oldmsg(struct msgb *oldmsg)
-{
-	return gsm0408_gprs_force_reattach_oldmsg(oldmsg);
 }
 
 void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
index 46d779b..75f95c9 100644
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ b/openbsc/src/gprs/gprs_sndcp.c
@@ -22,6 +22,7 @@
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/linuxlist.h>
@@ -417,7 +418,7 @@
 	/* set the MORE bit of the SNDCP header accordingly */
 	sch->more = more;
 
-	rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext);
+	rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext, true);
 	/* abort in case of error, do not advance frag_nr / next_byte */
 	if (rc < 0) {
 		msgb_free(fs->msg);
@@ -498,7 +499,7 @@
 	sch->type = 1;
 	sch->nsapi = nsapi;
 
-	return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext);
+	return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext, true);
 }
 
 /* Section 5.1.2.17 LL-UNITDATA.ind */
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index c852840..544870b 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <errno.h>
+#include <time.h>
 #include <signal.h>
 #include <sys/fcntl.h>
 #include <sys/stat.h>
@@ -305,7 +306,7 @@
 	struct ctrl_handle *ctrl;
 	struct gsm_network dummy_network;
 	int rc;
-
+	srand(time(NULL));
 	tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
 	tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
 

-- 
To view, visit https://gerrit.osmocom.org/460
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8900b906693496e4e6b35be5a86937c58039ed9e
Gerrit-PatchSet: 1
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: Max <msuraev at sysmocom.de>



More information about the gerrit-log mailing list