aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-11-10 09:44:34 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-11-15 20:06:49 +0100
commitfae3c65938328ba47f12d86db035db118d10ee83 (patch)
tree65afb9c67f770312822cc26d37e0ed14ddb024b6 /openbsc
parentf1f57a84c1b24f5eb03838424410856dac17b41c (diff)
bsc: Parse the cipher mode command and pass it to the BSC api.
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/osmo_bsc.h2
-rw-r--r--openbsc/src/bsc/osmo_bsc_bssap.c78
2 files changed, 80 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h
index 01509c04e..c4b241a24 100644
--- a/openbsc/include/openbsc/osmo_bsc.h
+++ b/openbsc/include/openbsc/osmo_bsc.h
@@ -10,6 +10,8 @@ struct sccp_connection;
struct osmo_bsc_sccp_con {
struct llist_head entry;
+ int ciphering_handled;
+
/* SCCP connection realted */
struct sccp_connection *sccp;
struct bsc_msc_connection *msc_con;
diff --git a/openbsc/src/bsc/osmo_bsc_bssap.c b/openbsc/src/bsc/osmo_bsc_bssap.c
index 703d93905..533da77e1 100644
--- a/openbsc/src/bsc/osmo_bsc_bssap.c
+++ b/openbsc/src/bsc/osmo_bsc_bssap.c
@@ -140,6 +140,81 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
return 0;
}
+/*
+ * GSM 08.08 ยง 3.4.7 cipher mode handling. We will have to pick
+ * the cipher to be used for this. In case we are already using
+ * a cipher we will have to send cipher mode reject to the MSC,
+ * otherwise we will have to pick something that we and the MS
+ * is supporting. Currently we are doing it in a rather static
+ * way by picking one ecnryption or no encrytpion.
+ */
+static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
+ struct msgb *msg, unsigned int payload_length)
+{
+ uint16_t len;
+ struct gsm_network *network = NULL;
+ const uint8_t *data;
+ struct tlv_parsed tp;
+ struct msgb *resp;
+ int reject_cause = -1;
+ int include_imeisv = 1;
+
+ if (!conn->conn) {
+ LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
+ goto reject;
+ }
+
+ if (conn->ciphering_handled) {
+ LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n");
+ goto reject;
+ }
+
+ conn->ciphering_handled = 1;
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
+ LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
+ goto reject;
+ }
+
+ /*
+ * check if our global setting is allowed
+ * - Currently we check for A5/0 and A5/1
+ * - Copy the key if that is necessary
+ * - Otherwise reject
+ */
+ len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
+ if (len < 1) {
+ LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n");
+ goto reject;
+ }
+
+ network = conn->conn->bts->network;
+ data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
+
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE))
+ include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1;
+
+ if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) {
+ gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv);
+ } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) {
+ gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv);
+ } else {
+ LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n");
+ goto reject;
+ }
+
+reject:
+ resp = gsm0808_create_cipher_reject(reject_cause);
+ if (!resp) {
+ LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n");
+ return -1;
+ }
+
+ bsc_queue_for_msc(conn, resp);
+ return -1;
+}
+
static int bssmap_rcvmsg_udt(struct gsm_network *net,
struct msgb *msg, unsigned int length)
{
@@ -177,6 +252,9 @@ static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn,
case BSS_MAP_MSG_CLEAR_CMD:
ret = bssmap_handle_clear_command(conn, msg, length);
break;
+ case BSS_MAP_MSG_CIPHER_MODE_CMD:
+ ret = bssmap_handle_cipher_mode(conn, msg, length);
+ break;
default:
LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l4h[0]);
break;