diff options
-rw-r--r-- | include/osmocom/bsc/gsm_data.h | 4 | ||||
-rw-r--r-- | src/osmo-bsc/handover_fsm.c | 28 | ||||
-rw-r--r-- | src/osmo-bsc/osmo_bsc_bssap.c | 2 |
3 files changed, 26 insertions, 8 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 7657a5f6a..a1aa2df67 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -250,6 +250,8 @@ struct handover_in_req { struct gsm0808_channel_type ct; struct gsm0808_speech_codec_list scl; struct gsm0808_encrypt_info ei; + /* The same information as in 'ei' but as the handy bitmask as on the wire. */ + uint8_t ei_as_bitmask; bool kc128_present; uint8_t kc128[16]; struct gsm_classmark classmark; @@ -1435,4 +1437,6 @@ extern const struct gsm_interf_meas_params interf_meas_params_def; enum rsl_cmod_spd chan_mode_to_rsl_cmod_spd(enum gsm48_chan_mode chan_mode); +int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask); + #endif /* _GSM_DATA_H */ diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c index 37e74176d..487135b89 100644 --- a/src/osmo-bsc/handover_fsm.c +++ b/src/osmo-bsc/handover_fsm.c @@ -490,6 +490,7 @@ static bool parse_ho_request(struct gsm_subscriber_connection *conn, const struc LOG_HO(conn, LOGL_ERROR, "Failed to parse Encryption Information IE\n"); return false; } + req->ei_as_bitmask = *e->val; if ((e = TLVP_GET(tp, GSM0808_IE_KC_128))) { if (e->len != 16) { @@ -630,6 +631,7 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn, int match_idx; struct osmo_fsm_inst *fi; struct channel_mode_and_rate ch_mode_rate = {}; + int chosen_a5_n; handover_fsm_alloc(conn); @@ -717,16 +719,28 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn, .msc_assigned_cic = req->msc_assigned_cic, }; - if (req->chosen_encr_alg) { - info.encr.alg_id = req->chosen_encr_alg; - if (info.encr.alg_id > 1 && !req->ei.key_len) { - ho_fail(HO_RESULT_ERROR, "Chosen Encryption Algorithm (Serving) reflects A5/%u" - " but there is no key (Encryption Information)", info.encr.alg_id - 1); + /* Figure out the encryption algorithm */ + chosen_a5_n = select_best_cipher(req->ei_as_bitmask, bsc_gsmnet->a5_encryption_mask); + if (chosen_a5_n < 0) { + ho_fail(HO_RESULT_FAIL_RR_HO_FAIL, + "There is no A5 encryption mode that both BSC and MSC permit: MSC 0x%x & BSC 0x%x = 0\n", + req->ei_as_bitmask, bsc_gsmnet->a5_encryption_mask); + return; + } + if (chosen_a5_n > 0 && !req->ei.key_len) { + /* There is no key. Is A5/0 permitted? */ + if ((req->ei_as_bitmask & bsc_gsmnet->a5_encryption_mask & 0x1) == 0x1) { + chosen_a5_n = 0; + } else { + ho_fail(HO_RESULT_ERROR, + "Encryption is required, but there is no key (Encryption Information)"); return; } } - if (req->ei.key_len) { + /* Put encryption info in the chan activation info */ + info.encr.alg_id = ALG_A5_NR_TO_RSL(chosen_a5_n); + if (chosen_a5_n > 0) { if (req->ei.key_len > sizeof(info.encr.key)) { ho_fail(HO_RESULT_ERROR, "Encryption Information IE key length is too large: %u\n", req->ei.key_len); @@ -965,7 +979,7 @@ void handover_end(struct gsm_subscriber_connection *conn, enum handover_result r result = bsc_tx_bssmap_ho_complete(conn, ho->new_lchan); } /* Not 'else': above checks may still result in HO_RESULT_ERROR. */ - if (result == HO_RESULT_ERROR) { + if (result != HO_RESULT_OK) { /* Return a BSSMAP Handover Failure, as described in 3GPP TS 48.008 3.1.5.2.2 * "Handover Resource Allocation Failure" */ bsc_tx_bssmap_ho_failure(conn); diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index cf8254c01..9d7b89fa3 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -394,7 +394,7 @@ int bsc_paging_start(struct bsc_paging_params *params) } /* select the best cipher permitted by the intersection of both masks */ -static int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask) +int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask) { /* A5/7 ... A5/3: We assume higher is better, * but: A5/1 is better than A5/2, which is better than A5/0 */ |