Merge branch 'master' into encryption
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index 6a454bf..8c5547d 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -499,6 +499,7 @@
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
u_int8_t ta);
int rsl_chan_mode_modify_req(struct gsm_lchan *ts);
+int rsl_encryption_cmd(struct msgb *msg);
int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
u_int8_t *ms_ident, u_int8_t chan_needed);
int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_needed,
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 185d760..acca100 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -720,6 +720,7 @@
int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
+int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan);
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
u_int8_t apdu_len, u_int8_t *apdu);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 4bdca2a..1ceb105 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -126,6 +126,9 @@
int waiting_for_imei : 1;
};
+#define MAX_A5_KEY_LEN (128/8)
+#define RSL_ENC_ALG_A5(x) (x+1)
+
struct gsm_lchan {
/* The TS that we're part of */
struct gsm_bts_trx_ts *ts;
@@ -140,6 +143,12 @@
/* Power levels for MS and BTS */
u_int8_t bs_power;
u_int8_t ms_power;
+ /* Encryption information */
+ struct {
+ u_int8_t alg_id;
+ u_int8_t key_len;
+ u_int8_t key[MAX_A5_KEY_LEN];
+ } encr;
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
@@ -365,6 +374,7 @@
char *name_long;
char *name_short;
enum gsm_auth_policy auth_policy;
+ int a5_encryption;
/* layer 4 */
int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg);
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 7be1a6b..800f202 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -317,6 +317,16 @@
memset(out+len, 0x2b, MACBLOCK_SIZE-len);
}
+/* Chapter 9.3.7: Encryption Information */
+static int build_encr_info(u_int8_t *out, struct gsm_lchan *lchan)
+{
+ *out++ = lchan->encr.alg_id & 0xff;
+ if (lchan->encr.key_len)
+ memcpy(out, lchan->encr.key, lchan->encr.key_len);
+ return lchan->encr.key_len + 1;
+}
+
+
static const char *rsl_err_vals[0xff] = {
[RSL_ERR_RADIO_IF_FAIL] = "Radio Interface Failure",
[RSL_ERR_RADIO_LINK_FAIL] = "Radio Link Failure",
@@ -587,10 +597,14 @@
(u_int8_t *) &cm);
msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
(u_int8_t *) &ci);
-#if 0
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
- (u_int8_t *) &encr_info);
-#endif
+
+ if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
+ u_int8_t encr_info[MAX_A5_KEY_LEN+2];
+ rc = build_encr_info(encr_info, lchan);
+ if (rc > 0)
+ msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
+ }
+
msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
@@ -621,10 +635,45 @@
msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
(u_int8_t *) &cm);
-#if 0
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
- (u_int8_t *) &encr_info);
-#endif
+
+ if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
+ u_int8_t encr_info[MAX_A5_KEY_LEN+2];
+ rc = build_encr_info(encr_info, lchan);
+ if (rc > 0)
+ msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
+ }
+
+ msg->trx = lchan->ts->trx;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* Chapter 8.4.6: Send the encryption command with given L3 info */
+int rsl_encryption_cmd(struct msgb *msg)
+{
+ struct abis_rsl_dchan_hdr *dh;
+ struct gsm_lchan *lchan = msg->lchan;
+ u_int8_t chan_nr = lchan2chan_nr(lchan);
+ u_int8_t encr_info[MAX_A5_KEY_LEN+2];
+ u_int8_t l3_len = msg->len;
+ int rc;
+
+ /* First push the L3 IE tag and length */
+ msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
+
+ /* then the link identifier (SAPI0, main sign link) */
+ msgb_tv_push(msg, RSL_IE_LINK_IDENT, 0);
+
+ /* then encryption information */
+ rc = build_encr_info(encr_info, lchan);
+ if (rc <= 0)
+ return rc;
+ msgb_tlv_push(msg, RSL_IE_ENCR_INFO, rc, encr_info);
+
+ /* and finally the DCHAN header */
+ dh = (struct abis_rsl_dchan_hdr *) msgb_push(msg, sizeof(*dh));
+ init_dchan_hdr(dh, RSL_MT_ENCR_CMD);
+ dh->chan_nr = chan_nr;
msg->trx = lchan->ts->trx;
@@ -1082,6 +1131,7 @@
arfcn = lchan->ts->trx->arfcn;
subch = lchan->nr;
+ lchan->encr.alg_id = RSL_ENC_ALG_A5(0); /* no encryption */
lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
lchan->bs_power = 0; /* 0dB reduction, output power = Pn */
lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index dc85670..d6fe09f 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1674,6 +1674,10 @@
case GSM48_MT_RR_APP_INFO:
rc = gsm48_rx_rr_app_info(msg);
break;
+ case GSM48_MT_RR_CIPH_M_COMPL:
+ DEBUGP(DRR, "CIPHERING MODE COMPLETE\n");
+ /* FIXME: check for MI (if any) */
+ break;
default:
fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
gh->msg_type);
@@ -1683,6 +1687,29 @@
return rc;
}
+/* Chapter 9.1.9: Ciphering Mode Command */
+int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan)
+{
+ struct msgb *msg = gsm48_msgb_alloc();
+ struct gsm48_hdr *gh;
+ u_int8_t ciph_mod_set;
+
+ msg->lchan = lchan;
+
+ DEBUGP(DRR, "TX CIPHERING MODE CMD\n");
+
+ if (lchan->encr.alg_id <= RSL_ENC_ALG_A5(0))
+ ciph_mod_set = 0;
+ else
+ ciph_mod_set = (lchan->encr.alg_id-2)<<1 | 1;
+
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_CIPH_M_CMD;
+ gh->data[0] = 0x10 | (ciph_mod_set & 0xf);
+
+ return rsl_encryption_cmd(msg);
+}
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
u_int8_t apdu_len, u_int8_t *apdu)
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 248e68e..f75cfaf 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -85,6 +85,8 @@
net->name_short, VTY_NEWLINE);
vty_out(vty, " Authentication policy: %s%s",
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
+ vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
+ VTY_NEWLINE);
}
DEFUN(show_net, show_net_cmd, "show network",
@@ -264,6 +266,7 @@
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
+ vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -766,6 +769,16 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_net_encryption,
+ cfg_net_encryption_cmd,
+ "encryption a5 (0|1|2)",
+ "Enable or disable encryption (A5) for this network\n")
+{
+ gsmnet->auth_policy = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
/* per-BTS configuration */
DEFUN(cfg_bts,
cfg_bts_cmd,
@@ -1155,6 +1168,7 @@
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
+ install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);