Support for ciphering

When the RR CIPH MODE CMD is transmitted to the MS, we need to tell the
L1 to enable decryption on RX.  After the first received frame has been
decrypted successfully, we will enable encryption also on transmit.

This has been tested with A5/1 so far, but A5/2 and A5/3 should work
exactly identical.
This commit is contained in:
Harald Welte 2012-04-08 20:17:43 +02:00
parent 51f9693ba6
commit d9ab45d1aa
2 changed files with 88 additions and 5 deletions

View File

@ -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 */

View File

@ -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 */