diff options
-rw-r--r-- | src/osmo-bts-sysmo/l1_if.c | 52 | ||||
-rw-r--r-- | src/osmo-bts-sysmo/oml.c | 41 |
2 files changed, 88 insertions, 5 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 1c46ecfa..02d930e9 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -301,6 +301,37 @@ get_lapdm_chan_by_hl2(struct gsm_bts_trx *trx, uint32_t hLayer2) return &lchan->lapdm_ch; } +enum lchan_ciph_state { + LCHAN_CIPH_NONE, + LCHAN_CIPH_RX_REQ, + LCHAN_CIPH_RX_CONF, + LCHAN_CIPH_TXRX_REQ, + LCHAN_CIPH_TXRX_CONF, +}; + +/* check if the message is a GSM48_MT_RR_CIPH_M_CMD, and if yes, enable + * uni-directional de-cryption on the uplink. We need this ugly layering + * violation as we have no way of passing down L3 metadata (RSL CIPHERING CMD) + * to this point in L1 */ +static int check_for_ciph_cmd(struct femtol1_hdl *fl1h, + struct msgb *msg, struct gsm_lchan *lchan) +{ + /* First byte (Address Field) of LAPDm header) */ + if (msg->data[0] != 0x03) + return 0; + /* First byte (protocol discriminator) of RR */ + if ((msg->data[3] & 0xF) != GSM48_PDISC_RR) + return 0; + /* 2nd byte (msg type) of RR */ + if ((msg->data[4] & 0x3F) != GSM48_MT_RR_CIPH_M_CMD) + return 0; + + lchan->ciph_state = LCHAN_CIPH_RX_REQ; + l1if_enable_ciphering(fl1h, lchan, 0); + + return 1; +} + static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, @@ -316,7 +347,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param; - struct lapdm_channel *lc; struct lapdm_entity *le; struct gsm_lchan *lchan; struct gsm_time g_time; @@ -424,13 +454,15 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, break; case GsmL1_Sapi_Sdcch: /* resolve the L2 entity using rts_ind->hLayer2 */ - lc = get_lapdm_chan_by_hl2(trx, rts_ind->hLayer2); - le = &lc->lapdm_dcch; + lchan = l1if_hLayer2_to_lchan(trx, rts_ind->hLayer2); + le = &lchan->lapdm_ch.lapdm_dcch; rc = lapdm_phsap_dequeue_prim(le, &pp); if (rc < 0) memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); else { memcpy(msu_param->u8Buffer, pp.oph.msg->data, GSM_MACBLOCK_LEN); + /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ + check_for_ciph_cmd(fl1, pp.oph.msg, lchan); msgb_free(pp.oph.msg); } break; @@ -458,13 +490,15 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, case GsmL1_Sapi_FacchF: case GsmL1_Sapi_FacchH: /* resolve the L2 entity using rts_ind->hLayer2 */ - lc = get_lapdm_chan_by_hl2(trx, rts_ind->hLayer2); - le = &lc->lapdm_dcch; + lchan = l1if_hLayer2_to_lchan(trx, rts_ind->hLayer2); + le = &lchan->lapdm_ch.lapdm_dcch; rc = lapdm_phsap_dequeue_prim(le, &pp); if (rc < 0) goto empty_frame; else { memcpy(msu_param->u8Buffer, pp.oph.msg->data, GSM_MACBLOCK_LEN); + /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ + check_for_ciph_cmd(fl1, pp.oph.msg, lchan); msgb_free(pp.oph.msg); } break; @@ -585,6 +619,14 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i case GsmL1_Sapi_Sdcch: case GsmL1_Sapi_FacchF: case GsmL1_Sapi_FacchH: + /* if this is the first valid message after enabling Rx + * decryption, we have to enable Tx encryption */ + if (lchan->ciph_state == LCHAN_CIPH_RX_REQ || + lchan->ciph_state == LCHAN_CIPH_RX_CONF) { + l1if_enable_ciphering(fl1, lchan, 1); + lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + } + /* SDCCH, SACCH and FACCH all go to LAPDm */ le = le_by_l1_sapi(&lchan->lapdm_ch, data_ind->sapi); /* allocate and fill LAPDm primitive */ diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 3c268497..00c088cd 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -18,6 +18,7 @@ */ #include <stdint.h> +#include <errno.h> #include <osmocom/core/talloc.h> #include <osmocom/core/utils.h> @@ -775,6 +776,46 @@ static int tx_confreq_logchpar(struct gsm_lchan *lchan, uint8_t direction) return l1if_req_compl(fl1h, msg, 0, chmod_modif_compl_cb, lchan); } +const enum GsmL1_CipherId_t rsl2l1_ciph[] = { + [0] = GsmL1_CipherId_A50, + [1] = GsmL1_CipherId_A50, + [2] = GsmL1_CipherId_A51, + [3] = GsmL1_CipherId_A52, + [4] = GsmL1_CipherId_A53, +}; + +int l1if_enable_ciphering(struct femtol1_hdl *fl1h, + struct gsm_lchan *lchan, + int dir_downlink) +{ + struct msgb *msg = l1p_msgb_alloc(); + struct GsmL1_MphConfigReq_t *cfgr; + + LOGP(DL1C, LOGL_DEBUG, "%s enable_ciphering(dir_downlink=%u)\n", + gsm_lchan_name(lchan), dir_downlink); + + cfgr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConfigReq, fl1h); + + cfgr->cfgParamId = GsmL1_ConfigParamId_SetCipheringParams; + cfgr->cfgParams.setCipheringParams.u8Tn = lchan->ts->nr; + cfgr->cfgParams.setCipheringParams.subCh = lchan_to_GsmL1_SubCh_t(lchan); + + if (dir_downlink) + cfgr->cfgParams.setCipheringParams.dir = GsmL1_Dir_TxDownlink; + else + cfgr->cfgParams.setCipheringParams.dir = GsmL1_Dir_RxUplink; + + if (lchan->encr.alg_id >= ARRAY_SIZE(rsl2l1_ciph)) + return -EINVAL; + cfgr->cfgParams.setCipheringParams.cipherId = rsl2l1_ciph[lchan->encr.alg_id]; + + memcpy(cfgr->cfgParams.setCipheringParams.u8Kc, + lchan->encr.key, lchan->encr.key_len); + + return l1if_req_compl(fl1h, msg, 0, chmod_modif_compl_cb, lchan); +} + + int bts_model_rsl_mode_modify(struct gsm_lchan *lchan) { /* channel mode, encryption and/or multirate have changed */ |