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

trxcon/scheduler: implement A5/X ciphering support

This change implements the A5/X ciphering support transparently
for the logical channel handlers. In other words, a DL burst is
deciphered before being passed to a handler, and an UL burst is
ciphered before being sent to transceiver.

The implementation mostly relays on the libosmocore's A5 API.

Change-Id: Ib53418d8c0f394fdece09cf5cc240887cb0bb5af
---
M src/host/trxcon/l1ctl.c
M src/host/trxcon/sched_trx.c
M src/host/trxcon/sched_trx.h
3 files changed, 125 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/12/6812/1

diff --git a/src/host/trxcon/l1ctl.c b/src/host/trxcon/l1ctl.c
index a11e792..070ee56 100644
--- a/src/host/trxcon/l1ctl.c
+++ b/src/host/trxcon/l1ctl.c
@@ -731,6 +731,49 @@
        return 0;
 }
 
+static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
+{
+       struct l1ctl_crypto_req *req;
+       struct l1ctl_info_ul *ul;
+       struct trx_ts *ts;
+       uint8_t tn;
+       int rc = 0;
+
+       ul = (struct l1ctl_info_ul *) msg->l1h;
+       req = (struct l1ctl_crypto_req *) ul->payload;
+
+       LOGP(DL1C, LOGL_NOTICE, "L1CTL_CRYPTO_REQ (algo=A5/%u, key_len=%u)\n",
+               req->algo, req->key_len);
+
+       /* Determine TS index */
+       tn = ul->chan_nr & 0x7;
+       if (tn > 7) {
+               LOGP(DL1C, LOGL_ERROR, "Incorrect TS index %u\n", tn);
+               rc = -EINVAL;
+               goto exit;
+       }
+
+       /* Make sure that required TS is allocated and configured */
+       ts = l1l->trx->ts_list[tn];
+       if (ts == NULL || ts->mf_layout == NULL) {
+               LOGP(DL1C, LOGL_ERROR, "TS %u is not configured\n", tn);
+               rc = -EINVAL;
+               goto exit;
+       }
+
+       /* Poke scheduler */
+       rc = sched_trx_start_ciphering(ts, req->algo, req->key, req->key_len);
+       if (rc) {
+               LOGP(DL1C, LOGL_ERROR, "Couldn't configure ciphering\n");
+               rc = -EINVAL;
+               goto exit;
+       }
+
+exit:
+       msgb_free(msg);
+       return rc;
+}
+
 int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg)
 {
        struct l1ctl_hdr *l1h;
@@ -763,6 +806,8 @@
                return l1ctl_rx_param_req(l1l, msg);
        case L1CTL_TCH_MODE_REQ:
                return l1ctl_rx_tch_mode_req(l1l, msg);
+       case L1CTL_CRYPTO_REQ:
+               return l1ctl_rx_crypto_req(l1l, msg);
        default:
                LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
                msgb_free(msg);
diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c
index fba9ee4..120098b 100644
--- a/src/host/trxcon/sched_trx.c
+++ b/src/host/trxcon/sched_trx.c
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <talloc.h>
 
+#include <osmocom/gsm/a5.h>
 #include <osmocom/core/bits.h>
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/logging.h>
@@ -292,6 +293,37 @@
        return 0;
 }
 
+int sched_trx_start_ciphering(struct trx_ts *ts, uint8_t algo,
+       uint8_t *key, uint8_t key_len)
+{
+       struct trx_lchan_state *state;
+       size_t len;
+       int i;
+
+       /* Prevent NULL-pointer deference */
+       if (!ts)
+               return -EINVAL;
+
+       /* Make sure we can store this key */
+       if (key_len > MAX_A5_KEY_LEN)
+               return -ERANGE;
+
+       /* Iterate over all allocated logical channels */
+       len = talloc_array_length(ts->lchans);
+       for (i = 0; i < len; i++) {
+               /* Set key length and algorithm */
+               state = ts->lchans + i;
+               state->a5.key_len = key_len;
+               state->a5.algo = algo;
+
+               /* Copy requested key */
+               if (key_len)
+                       memcpy(state->a5.key, key, key_len);
+       }
+
+       return 0;
+}
+
 struct trx_lchan_state *sched_trx_find_lchan(struct trx_ts *ts,
        enum trx_lchan_type chan)
 {
@@ -396,6 +428,9 @@
        talloc_free(lchan->rx_bursts);
        talloc_free(lchan->tx_bursts);
 
+       /* Reset ciphering state */
+       memset(&lchan->a5, 0x00, sizeof(lchan->a5));
+
        /* Forget the current prim */
        sched_prim_drop(lchan);
 
@@ -456,6 +491,40 @@
        return TRXC_IDLE;
 }
 
+static void sched_trx_a5_burst_dec(struct trx_lchan_state *lchan,
+       uint32_t fn, sbit_t *burst)
+{
+       ubit_t ks[114];
+       int i;
+
+       /* Generate keystream for a DL burst */
+       osmo_a5(lchan->a5.algo, lchan->a5.key, fn, ks, NULL);
+
+       /* Apply keystream over ciphertext */
+       for (i = 0; i < 57; i++) {
+               if (ks[i])
+                       burst[i + 3] *= -1;
+               if (ks[i + 57])
+                       burst[i + 88] *= -1;
+       }
+}
+
+static void sched_trx_a5_burst_enc(struct trx_lchan_state *lchan,
+       uint32_t fn, ubit_t *burst)
+{
+       ubit_t ks[114];
+       int i;
+
+       /* Generate keystream for an UL burst */
+       osmo_a5(lchan->a5.algo, lchan->a5.key, fn, NULL, ks);
+
+       /* Apply keystream over plaintext */
+       for (i = 0; i < 57; i++) {
+               burst[i + 3] ^= ks[i];
+               burst[i + 88] ^= ks[i + 57];
+       }
+}
+
 int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
        uint32_t burst_fn, sbit_t *bits, uint16_t nbits, int8_t rssi, float toa)
 {
@@ -512,9 +581,13 @@
                if (!lchan->active)
                        goto next_frame;
 
-               /* Put burst to handler */
+               /* Reached current fn */
                if (fn == burst_fn) {
-                       /* TODO: decrypt if required */
+                       /* Perform A5/X decryption if required */
+                       if (lchan->a5.algo)
+                               sched_trx_a5_burst_dec(lchan, fn, bits);
+
+                       /* Put burst to handler */
                        handler(trx, ts, lchan, fn, bid, bits, rssi, toa);
                }
 
@@ -538,7 +611,9 @@
 {
        int rc;
 
-       /* TODO: perform A5/X burst encryption if required */
+       /* Perform A5/X burst encryption if required */
+       if (lchan->a5.algo)
+               sched_trx_a5_burst_enc(lchan, fn, bits);
 
        /* Forward burst to transceiver */
        rc = trx_if_tx_burst(trx, ts->index, fn, trx->tx_power, bits);
diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h
index 54dbc85..504054a 100644
--- a/src/host/trxcon/sched_trx.h
+++ b/src/host/trxcon/sched_trx.h
@@ -253,6 +253,8 @@
 int sched_trx_reset_ts(struct trx_instance *trx, int tn);
 int sched_trx_configure_ts(struct trx_instance *trx, int tn,
        enum gsm_phys_chan_config config);
+int sched_trx_start_ciphering(struct trx_ts *ts, uint8_t algo,
+       uint8_t *key, uint8_t key_len);
 
 /* Logical channel management functions */
 enum gsm_phys_chan_config sched_trx_chan_nr2pchan_config(uint8_t chan_nr);

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib53418d8c0f394fdece09cf5cc240887cb0bb5af
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <lafo...@gnumonks.org>

Reply via email to