aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_llc.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-06-30 23:07:59 +0200
committerHarald Welte <laforge@gnumonks.org>2010-07-02 22:55:39 +0200
commitd07b4f99cef6906702c555cfcb923d0d76473916 (patch)
tree6fceb9bd114c0597685aa1a6ed63a9d72d936cef /openbsc/src/gprs/gprs_llc.c
parent496aee463faf8bb0d1fe5062fcee5b52bd5eec52 (diff)
[SGSN] Use libosmocore GPRS encryption plugins from LLC layer
This adds the bits that call into libosmocore (and its plugins) to implement GPRS (LLC) encryption.
Diffstat (limited to 'openbsc/src/gprs/gprs_llc.c')
-rw-r--r--openbsc/src/gprs/gprs_llc.c96
1 files changed, 88 insertions, 8 deletions
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 7e16d1b96..4c870d3fd 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -313,6 +313,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
uint8_t addr, ctrl[2];
uint32_t fcs_calc;
uint16_t nu = 0;
+ uint32_t oc;
/* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
@@ -334,9 +335,14 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
lle->llme->bvci = msgb_bvci(msg);
lle->llme->nsei = msgb_nsei(msg);
- /* Increment V(U) */
+ /* Obtain current values for N(u) and OC */
nu = lle->vu_send;
+ oc = lle->oc_ui_send;
+ /* Increment V(U) */
lle->vu_send = (lle->vu_send + 1) % 512;
+ /* Increment Overflow Counter, if needed */
+ if ((lle->vu_send + 1) / 512)
+ lle->oc_ui_send += 512;
/* Address Field */
addr = sapi & 0xf;
@@ -362,6 +368,34 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
fcs[1] = (fcs_calc >> 8) & 0xff;
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 */
+ uint16_t crypt_len = (fcs + 3) - (llch + 3);
+ uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
+ uint32_t iv;
+ int rc, i;
+ uint64_t kc = *(uint64_t *)&lle->llme->kc;
+
+ /* Compute the 'Input' Paraemeter */
+ iv = gprs_cipher_gen_input_ui(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,
+ kc, iv, GPRS_CIPH_SGSN2MS);
+ if (rc < 0) {
+ LOGP(DLLC, LOGL_ERROR, "Error crypting UI frame: %d\n", rc);
+ return rc;
+ }
+
+ /* 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) */
/* Send BSSGP-DL-UNITDATA.req */
@@ -431,6 +465,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
}
/* Increment the sequence number that we expect in the next frame */
lle->vu_recv = (gph->seq_tx + 1) % 512;
+ /* Increment Overflow Counter */
+ if ((gph->seq_tx + 1) / 512)
+ lle->oc_ui_recv += 512;
break;
}
@@ -591,8 +628,10 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
}
}
- /* calculate what FCS we expect */
- ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length);
+ if (!ghp->is_encrypted) {
+ /* calculate what FCS we expect */
+ ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length);
+ }
/* FIXME: parse sack frame */
if (ghp->cmd == GPRS_LLC_SACK) {
@@ -622,11 +661,6 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
return rc;
}
- if (llhp.fcs != llhp.fcs_calc) {
- LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n");
- return -EIO;
- }
-
switch (gprs_tlli_type(msgb_tlli(msg))) {
case TLLI_LOCAL:
case TLLI_FOREIGN:
@@ -658,6 +692,48 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
}
}
+ /* 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;
+ uint64_t kc = *(uint64_t *)&lle->llme->kc;
+ int rc, i;
+
+ if (lle->llme->algo == GPRS_ALGO_GEA0) {
+ LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that "
+ "has no KC/Algo! Dropping.\n");
+ return 0;
+ }
+
+ iv = gprs_cipher_gen_input_ui(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);
+ if (rc < 0) {
+ LOGP(DLLC, LOGL_ERROR, "Error decrypting frame: %d\n",
+ rc);
+ return rc;
+ }
+
+ /* XOR the cipher output with the information field + FCS */
+ for (i = 0; i < crypt_len; i++)
+ *(llhp.data + i) ^= cipher_out[i];
+ } else {
+ if (lle->llme->algo != GPRS_ALGO_GEA0) {
+ LOGP(DLLC, LOGL_NOTICE, "unencrypted frame for LLC "
+ "that is supposed to be encrypted. Dropping.\n");
+ return 0;
+ }
+ }
+
+ /* We have to do the FCS check _after_ decryption */
+ if (llhp.fcs != llhp.fcs_calc) {
+ LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n");
+ return -EIO;
+ }
+
/* Update LLE's (BVCI, NSEI) tuple */
lle->llme->bvci = msgb_bvci(msg);
lle->llme->nsei = msgb_nsei(msg);
@@ -704,6 +780,10 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
{
unsigned int i;
+ /* Update the crypto parameters */
+ memcpy(llme->kc, kc, sizeof(llme->kc));
+ llme->algo = alg;
+
if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
/* TLLI Assignment 8.3.1 */
/* New TLLI shall be assigned and used when (re)transmitting LLC frames */