diff options
Diffstat (limited to 'src/libmsc/gsm_04_08.c')
-rw-r--r-- | src/libmsc/gsm_04_08.c | 152 |
1 files changed, 109 insertions, 43 deletions
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c index 21ffaaad8..3f3f90581 100644 --- a/src/libmsc/gsm_04_08.c +++ b/src/libmsc/gsm_04_08.c @@ -31,6 +31,7 @@ #include <netinet/in.h> #include <regex.h> #include <sys/types.h> +#include <openssl/rand.h> #include "bscconfig.h" @@ -69,6 +70,13 @@ #include <osmocom/core/talloc.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/tlv.h> +#include <osmocom/crypt/auth.h> + +#include <openbsc/msc_ifaces.h> + +#ifdef BUILD_IU +#include <openbsc/iu.h> +#endif #include <assert.h> @@ -105,7 +113,7 @@ static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection gh->proto_discr = trans->protocol | (trans->transaction_id << 4); } - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm48_cc_tx_notify_ss(struct gsm_trans *trans, const char *message) @@ -141,7 +149,7 @@ void gsm0408_clear_all_trans(struct gsm_network *net, int protocol) } /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ -int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) +static int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) { struct msgb *msg; @@ -184,12 +192,17 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, len = gsm48_generate_mid_from_imsi(mi, conn->vsub->imsi); mid = msgb_put(msg, len); memcpy(mid, mi, len); + DEBUGP(DMM, "-> %s LOCATION UPDATE ACCEPT\n", + vlr_subscr_name(conn->vsub)); } else { /* Include the TMSI, which means that the MS will send a * TMSI REALLOCATION COMPLETE, and we should wait for * that until T3250 expiration */ mid = msgb_put(msg, GSM48_MID_TMSI_LEN); gsm48_generate_mid_from_tmsi(mid, send_tmsi); + DEBUGP(DMM, "-> %s LOCATION UPDATE ACCEPT (TMSI = 0x%08x)\n", + vlr_subscr_name(conn->vsub), + send_tmsi); } /* TODO: Follow-on proceed */ /* TODO: CTS permission */ @@ -197,7 +210,6 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, /* TODO: Emergency Number List */ /* TODO: Per-MS T3312 */ - DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -257,11 +269,11 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg) uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; enum vlr_lu_type vlr_lu_type = VLR_LU_TYPE_REGULAR; - uint32_t tmsi; char *imsi; struct osmo_location_area_id old_lai, new_lai; struct osmo_fsm_inst *lu_fsm; + bool is_utran; int rc; lu = (struct gsm48_loc_upd_req *) gh->data; @@ -327,16 +339,18 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg) new_lai.lac = conn->lac; DEBUGP(DMM, "LU/new-LAC: %u/%u\n", old_lai.lac, new_lai.lac); + is_utran = (conn->via_ran == RAN_UTRAN_IU); lu_fsm = vlr_loc_update(conn->conn_fsm, SUBSCR_CONN_E_ACCEPTED, SUBSCR_CONN_E_CN_CLOSE, (void*)&conn_from_lu, net->vlr, conn, vlr_lu_type, tmsi, imsi, &old_lai, &new_lai, - conn->network->authentication_required, - conn->network->a5_encryption, + is_utran || conn->network->authentication_required, + is_utran? VLR_CIPH_A5_3 + : conn->network->a5_encryption, classmark_is_r99(&conn->classmark), - conn->via_ran == RAN_UTRAN_IU, + is_utran, net->vlr->cfg.assign_tmsi); if (!lu_fsm) { DEBUGP(DRR, "%s: Can't start LU FSM\n", mi_string); @@ -629,6 +643,7 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms uint8_t mi_len = *(classmark2 + classmark2_len); uint8_t *mi = (classmark2 + classmark2_len + 1); struct osmo_location_area_id lai; + bool is_utran; int rc; lai.plmn.mcc = conn->network->country_code; @@ -685,16 +700,18 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms return rc; } + is_utran = (conn->via_ran == RAN_UTRAN_IU); vlr_proc_acc_req(conn->conn_fsm, SUBSCR_CONN_E_ACCEPTED, SUBSCR_CONN_E_CN_CLOSE, (void*)&conn_from_cm_service_req, net->vlr, conn, VLR_PR_ARQ_T_CM_SERV_REQ, mi-1, &lai, - conn->network->authentication_required, - conn->network->a5_encryption, + is_utran || conn->network->authentication_required, + is_utran? VLR_CIPH_A5_3 + : conn->network->a5_encryption, classmark_is_r99(&conn->classmark), - conn->via_ran == RAN_UTRAN_IU); + is_utran); return 0; } @@ -1038,6 +1055,7 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m char mi_string[GSM48_MI_SIZE]; int rc = 0; struct osmo_location_area_id lai; + bool is_utran; lai.plmn.mcc = conn->network->country_code; lai.plmn.mnc = conn->network->network_code; @@ -1063,18 +1081,20 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m memcpy(conn->classmark.classmark2, classmark2_lv+1, *classmark2_lv); conn->classmark.classmark2_len = *classmark2_lv; + is_utran = (conn->via_ran == RAN_UTRAN_IU); vlr_proc_acc_req(conn->conn_fsm, SUBSCR_CONN_E_ACCEPTED, SUBSCR_CONN_E_CN_CLOSE, (void*)&conn_from_paging_resp, net->vlr, conn, VLR_PR_ARQ_T_PAGING_RESP, mi_lv, &lai, - conn->network->authentication_required, - conn->network->a5_encryption, + is_utran || conn->network->authentication_required, + is_utran? VLR_CIPH_A5_3 + : conn->network->a5_encryption, classmark_is_r99(&conn->classmark), - conn->via_ran == RAN_UTRAN_IU); + is_utran); - return rc; + return 0; } static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -1365,8 +1385,7 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge) /* Which subscriber do we want to track trans1 or trans2? */ log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub); - /* future: msc_call_bridge(trans1, trans2); */ - return -1; + return msc_call_bridge(trans1, trans2); } static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg) @@ -1694,15 +1713,18 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF); + msc_call_assignment(trans); + return mncc_recvmsg(trans->net, trans, MNCC_CALL_CONF_IND, &call_conf); } -static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) +static int gsm48_cc_tx_call_proc_and_assign(struct gsm_trans *trans, void *arg) { struct gsm_mncc *proceeding = arg; struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CC PROC"); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + int rc; gh->msg_type = GSM48_MT_CC_CALL_PROC; @@ -1718,7 +1740,11 @@ static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) if (proceeding->fields & MNCC_F_PROGRESS) gsm48_encode_progress(msg, 0, &proceeding->progress); - return gsm48_conn_sendmsg(msg, trans->conn, trans); + rc = gsm48_conn_sendmsg(msg, trans->conn, trans); + if (rc) + return rc; + + return msc_call_assignment(trans); } static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg) @@ -2555,7 +2581,7 @@ static struct downstate { } downstatelist[] = { /* mobile originating call establishment */ {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */ - MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc}, + MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc_and_assign}, {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */ MNCC_ALERT_REQ, gsm48_cc_tx_alerting}, {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) | SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.2 | 5.2.1.6 | 5.2.1.6 */ @@ -2732,15 +2758,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) trans_free(trans); return 0; } - /* store setup informations until paging was successfull */ + /* store setup information until paging succeeds */ memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc)); /* Request a channel */ trans->paging_request = subscr_request_conn( vsub, - RSL_CHANNEED_TCH_F, setup_trig_pag_evt, - trans); + trans, + "MNCC: establish call"); if (!trans->paging_request) { LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n"); vlr_subscr_put(vsub); @@ -3007,6 +3033,16 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) return -EACCES; } + if (conn->vsub && conn->vsub->cs.attached_via_ran != conn->via_ran) { + LOGP(DMM, LOGL_ERROR, + "%s: Illegal situation: RAN type mismatch:" + " attached via %s, received message via %s\n", + vlr_subscr_name(conn->vsub), + ran_type_name(conn->vsub->cs.attached_via_ran), + ran_type_name(conn->via_ran)); + return -EACCES; + } + #if 0 if (silent_call_reroute(conn, msg)) return silent_call_rx(conn, msg); @@ -3090,7 +3126,13 @@ static int msc_vlr_tx_lu_rej(void *msc_conn_ref, uint8_t cause) static int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref) { struct gsm_subscriber_connection *conn = msc_conn_ref; - return gsm48_tx_mm_serv_ack(conn); + return msc_gsm48_tx_mm_serv_ack(conn); +} + +static int msc_vlr_tx_common_id(void *msc_conn_ref) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return msc_tx_common_id(conn); } /* VLR asks us to transmit a CM Service Reject */ @@ -3124,7 +3166,7 @@ static int msc_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum vlr_proc_arq_result r break; }; - return gsm48_tx_mm_serv_rej(conn, cause); + return msc_gsm48_tx_mm_serv_rej(conn, cause); } /* VLR asks us to start using ciphering */ @@ -3152,9 +3194,47 @@ static int msc_vlr_set_ciph_mode(void *msc_conn_ref, return -EINVAL; } - /* TODO: MSCSPLIT: don't directly push BSC buttons */ - return gsm0808_cipher_mode(conn, ciph, tuple->vec.kc, 8, - retrieve_imeisv); + switch (conn->via_ran) { + case RAN_GERAN_A: + DEBUGP(DMM, "-> CIPHER MODE COMMAND %s\n", + vlr_subscr_name(conn->vsub)); + return msc_gsm0808_tx_cipher_mode(conn, ciph, tuple->vec.kc, 8, + retrieve_imeisv); + case RAN_UTRAN_IU: +#ifdef BUILD_IU + DEBUGP(DMM, "-> SECURITY MODE CONTROL %s\n", + vlr_subscr_name(conn->vsub)); + return iu_tx_sec_mode_cmd(conn->iu.ue_ctx, tuple, 0, 1); +#else + LOGP(DMM, LOGL_ERROR, "Cannot send Security Mode Control over RAN_UTRAN_IU," + " built without Iu support\n"); + return -ENOTSUP; +#endif + + default: + break; + } + LOGP(DMM, LOGL_ERROR, + "%s: cannot start ciphering, unknown RAN type %d\n", + vlr_subscr_name(conn->vsub), conn->via_ran); + return -ENOTSUP; +} + +void msc_rx_sec_mode_compl(struct gsm_subscriber_connection *conn) +{ + struct vlr_ciph_result vlr_res = {}; + + if (!conn || !conn->vsub) { + LOGP(DMM, LOGL_ERROR, + "Rx Security Mode Complete for invalid conn\n"); + return; + } + + DEBUGP(DMM, "<- SECURITY MODE COMPLETE %s\n", + vlr_subscr_name(conn->vsub)); + + vlr_res.cause = VLR_CIPH_COMPL; + vlr_subscr_rx_ciph_res(conn->vsub, &vlr_res); } /* VLR informs us that the subscriber data has somehow been modified */ @@ -3170,6 +3250,7 @@ static void msc_vlr_subscr_assoc(void *msc_conn_ref, struct gsm_subscriber_connection *conn = msc_conn_ref; OSMO_ASSERT(!conn->vsub); conn->vsub = vlr_subscr_get(vsub); + conn->vsub->cs.attached_via_ran = conn->via_ran; } /* operations that we need to implement for libvlr */ @@ -3182,6 +3263,7 @@ static const struct vlr_ops msc_vlr_ops = { .tx_cm_serv_acc = msc_vlr_tx_cm_serv_acc, .tx_cm_serv_rej = msc_vlr_tx_cm_serv_rej, .set_ciph_mode = msc_vlr_set_ciph_mode, + .tx_common_id = msc_vlr_tx_common_id, .subscr_update = msc_vlr_subscr_update, .subscr_assoc = msc_vlr_subscr_assoc, }; @@ -3203,19 +3285,3 @@ int msc_vlr_start(struct gsm_network *net) return vlr_start("MSC", net->vlr, net->gsup_server_addr_str, net->gsup_server_port); } - -/* This is a temporary shim merely to ensure that the unit tests still work. It - * shall be removed as soon as Iu and A interface paging is implemented. */ -int msc_fake_paging_request(struct vlr_subscr *vsub) -{ - LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n"); - OSMO_ASSERT(false); -} - -/* This is a temporary shim merely to ensure that the unit tests still work. It - * shall be removed as soon as Iu and A interface paging is implemented. */ -void msc_fake_paging_request_stop(struct vlr_subscr *vsub) -{ - LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n"); - OSMO_ASSERT(false); -} |