diff options
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r-- | openbsc/src/libmsc/Makefile.am | 4 | ||||
-rw-r--r-- | openbsc/src/libmsc/a_iface.c | 8 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 135 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_11.c | 7 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_80.c | 10 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_subscriber.c | 130 | ||||
-rw-r--r-- | openbsc/src/libmsc/iucs.c | 191 | ||||
-rw-r--r-- | openbsc/src/libmsc/iucs_ranap.c | 106 | ||||
-rw-r--r-- | openbsc/src/libmsc/msc_ifaces.c | 240 | ||||
-rw-r--r-- | openbsc/src/libmsc/msc_vty.c | 181 | ||||
-rw-r--r-- | openbsc/src/libmsc/osmo_msc.c | 72 | ||||
-rw-r--r-- | openbsc/src/libmsc/silent_call.c | 3 | ||||
-rw-r--r-- | openbsc/src/libmsc/subscr_conn.c | 62 | ||||
-rw-r--r-- | openbsc/src/libmsc/transaction.c | 24 | ||||
-rw-r--r-- | openbsc/src/libmsc/vty_interface_layer3.c | 102 |
15 files changed, 1008 insertions, 267 deletions
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 7ab30d029..a320f7d28 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -12,6 +12,7 @@ AM_CFLAGS = \ $(COVERAGE_CFLAGS) \ $(LIBCRYPTO_CFLAGS) \ $(LIBSMPP34_CFLAGS) \ + $(LIBASN1C_CFLAGS) \ $(NULL) noinst_HEADERS = \ @@ -25,11 +26,14 @@ noinst_LIBRARIES = \ libmsc_a_SOURCES = \ a_iface.c \ auth.c \ + msc_vty.c \ db.c \ gsm_04_08.c \ gsm_04_11.c \ gsm_04_80.c \ gsm_subscriber.c \ + iucs.c \ + iucs_ranap.c \ mncc.c \ mncc_builtin.c \ mncc_sock.c \ diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c index 1f471f97b..caf9d4b06 100644 --- a/openbsc/src/libmsc/a_iface.c +++ b/openbsc/src/libmsc/a_iface.c @@ -35,6 +35,14 @@ int a_tx(struct msgb *msg) return -1; } +int a_page(const char *imsi, uint32_t tmsi, uint16_t lac) +{ + LOGP(DMSC, LOGL_ERROR, "Paging to be sent to BSC, but A-interface" + " not implemented: IMSI %s TMSI 0x%08x LAC %u\n", + imsi, tmsi, lac); + return -1; +} + int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher, const uint8_t *key, int len, int include_imeisv) { diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index f8d47e4da..67eb5c135 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/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,10 @@ #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> +#include <openbsc/iu.h> #include <assert.h> @@ -113,7 +118,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) @@ -149,7 +154,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; @@ -192,12 +197,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 */ @@ -205,7 +215,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); } @@ -265,11 +274,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; @@ -332,19 +341,21 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg) &old_lai.plmn.mnc, &old_lai.lac); new_lai.plmn.mcc = conn->network->country_code; new_lai.plmn.mnc = conn->network->network_code; - new_lai.lac = conn->bts->location_area_code; + 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); @@ -643,11 +654,12 @@ 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; lai.plmn.mnc = conn->network->network_code; - lai.lac = conn->bts->location_area_code; + lai.lac = conn->lac; DEBUGP(DMM, "<- CM SERVICE REQUEST "); if (msg->data_len < sizeof(struct gsm48_service_request*)) { @@ -708,16 +720,18 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms send_siemens_mrpci(msg->lchan, classmark2-1); #endif + 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; } @@ -1062,6 +1076,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; @@ -1087,18 +1102,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) @@ -1553,8 +1570,7 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge) /* through-connect channel */ return tch_map(trans1->conn->lchan, trans2->conn->lchan); #else - /* not implemented yet! */ - return -1; + return msc_call_bridge(trans1, trans2); #endif } @@ -1969,15 +1985,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; @@ -1993,7 +2012,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) @@ -3073,7 +3096,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 */ @@ -3304,15 +3327,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_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); @@ -3323,7 +3346,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) return 0; } - /* Assign lchan */ + /* Assign conn */ trans->conn = msc_subscr_conn_get(conn); vlr_subscr_put(vsub); } else { @@ -3577,6 +3600,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); @@ -3660,7 +3693,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 */ @@ -3694,7 +3733,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 */ @@ -3722,9 +3761,41 @@ 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: + 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); + + 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 */ @@ -3740,6 +3811,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 */ @@ -3752,6 +3824,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, }; diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 3255a3b6f..bdf2ad7cc 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -55,7 +55,7 @@ #include <openbsc/paging.h> #include <openbsc/bsc_rll.h> #include <openbsc/chan_alloc.h> -#include <openbsc/bsc_api.h> +#include <openbsc/msc_ifaces.h> #include <openbsc/osmo_msc.h> #include <openbsc/vlr.h> @@ -128,7 +128,7 @@ static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *m { DEBUGP(DLSMS, "GSM4.11 TX %s\n", osmo_hexdump(msg->data, msg->len)); msg->l3h = msg->data; - return gsm0808_submit_dtap(conn, msg, UM_SAPI_SMS, 1); + return msc_tx_dtap(conn, msg); } /* Prefix msg with a 04.08/04.11 CP header */ @@ -1016,8 +1016,7 @@ int gsm411_send_sms_subscr(struct vlr_subscr *vsub, /* if not, we have to start paging */ LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n", vlr_subscr_name(vsub)); - res = subscr_request_conn(vsub, RSL_CHANNEED_SDCCH, paging_cb_send_sms, - sms); + res = subscr_request_conn(vsub, paging_cb_send_sms, sms, "send SMS"); if (!res) { send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY); sms_free(sms); diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index 479d6fbd2..bec1d26f4 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -32,7 +32,7 @@ #include <openbsc/gsm_data.h> #include <openbsc/gsm_04_08.h> #include <openbsc/gsm_04_80.h> -#include <openbsc/bsc_api.h> +#include <openbsc/msc_ifaces.h> #include <osmocom/gsm/gsm0480.h> #include <osmocom/gsm/gsm_utils.h> @@ -106,7 +106,7 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, @@ -135,7 +135,7 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, const char *text) @@ -143,7 +143,7 @@ int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, cons struct msgb *msg = gsm0480_create_ussd_notify(level, text); if (!msg) return -1; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int msc_send_ussd_release_complete(struct gsm_subscriber_connection *conn) @@ -151,5 +151,5 @@ int msc_send_ussd_release_complete(struct gsm_subscriber_connection *conn) struct msgb *msg = gsm0480_create_ussd_release_complete(); if (!msg) return -1; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index f425058f0..f92101863 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -40,33 +40,16 @@ #include <openbsc/db.h> #include <openbsc/chan_alloc.h> #include <openbsc/vlr.h> +#include <openbsc/iu.h> +#include <openbsc/osmo_msc.h> +#include <openbsc/msc_ifaces.h> void *tall_sub_req_ctx; int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, gsm_cbfn *cb, void *cb_data); -static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers, - struct vlr_subscr *vsub) -{ - struct bsc_subscr *sub; - /* TODO MSC split -- creating a BSC subscriber directly from MSC data - * structures in RAM. At some point the MSC will send a message to the - * BSC instead. */ - sub = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, vsub->imsi); - sub->tmsi = vsub->tmsi; - sub->lac = vsub->lac; - return sub; -} - -#if 0 -TODO implement paging response in libmsc! -Excluding this to be able to link without libbsc: - -/* - * We got the channel assigned and can now hand this channel - * over to one of our callbacks. - */ +/* A connection is established and the paging callbacks may run now. */ int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param) { @@ -74,38 +57,42 @@ int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, struct gsm_subscriber_connection *conn = data; struct vlr_subscr *vsub = param; struct paging_signal_data sig_data; - struct bsc_subscr *bsub; - struct gsm_network *net; - OSMO_ASSERT(vsub && vsub->cs.is_paging); - net = vsub->vlr->user_ctx; + OSMO_ASSERT(vsub); + OSMO_ASSERT(hooknum == GSM_HOOK_RR_PAGING); + OSMO_ASSERT(!(conn && (conn->vsub != vsub))); + OSMO_ASSERT(!((event == GSM_PAGING_SUCCEEDED) && !conn)); + + LOGP(DPAG, LOGL_DEBUG, "Paging %s for %s (event=%d)\n", + event == GSM_PAGING_SUCCEEDED ? "success" : "failure", + vlr_subscr_name(vsub), event); - /* - * Stop paging on all other BTS. E.g. if this is - * the first timeout on a BTS then the others will - * timeout soon as well. Let's just stop everything - * and forget we wanted to page. - */ + if (!vsub->cs.is_paging) { + LOGP(DPAG, LOGL_ERROR, + "Paging Response received for subscriber" + " that is not paging.\n"); + return -EINVAL; + } - bsub = vlr_subscr_to_bsc_sub(conn->network->bsc_subscribers, vsub); - paging_request_stop(&net->bts_list, NULL, bsub, NULL, NULL); - bsc_subscr_put(bsub); + if (event == GSM_PAGING_SUCCEEDED) + msc_stop_paging(vsub); /* Inform parts of the system we don't know */ - sig_data.vsub = vsub; - sig_data.bts = conn ? conn->bts : NULL; - sig_data.conn = conn; + sig_data.vsub = vsub; + sig_data.conn = conn; sig_data.paging_result = event; - osmo_signal_dispatch( - SS_PAGING, - event == GSM_PAGING_SUCCEEDED ? - S_PAGING_SUCCEEDED : S_PAGING_EXPIRED, - &sig_data - ); + osmo_signal_dispatch(SS_PAGING, + event == GSM_PAGING_SUCCEEDED ? + S_PAGING_SUCCEEDED : S_PAGING_EXPIRED, + &sig_data); llist_for_each_entry_safe(request, tmp, &vsub->cs.requests, entry) { llist_del(&request->entry); - request->cbfn(hooknum, event, msg, data, request->param); + if (request->cbfn) { + LOGP(DPAG, LOGL_DEBUG, "Calling paging cbfn.\n"); + request->cbfn(hooknum, event, msg, data, request->param); + } else + LOGP(DPAG, LOGL_DEBUG, "Paging without action.\n"); talloc_free(request); } @@ -115,29 +102,48 @@ int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, return 0; } -struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub, - int channel_type, - gsm_cbfn *cbfn, void *param) +int msc_paging_request(struct vlr_subscr *vsub) +{ + /* The subscriber was last seen in subscr->lac. Find out which + * BSCs/RNCs are responsible and send them a paging request via open + * SCCP connections (if any). */ + /* TODO Implementing only RNC paging, since this is code on the iu branch. + * Need to add BSC paging at some point. */ + switch (vsub->cs.attached_via_ran) { + case RAN_GERAN_A: + return a_page(vsub->imsi, vsub->tmsi, vsub->lac); + case RAN_UTRAN_IU: + return iu_page_cs(vsub->imsi, + vsub->tmsi == GSM_RESERVED_TMSI? + NULL : &vsub->tmsi, + vsub->lac); + default: + break; + } + + LOGP(DPAG, LOGL_ERROR, "%s: Cannot page, subscriber not attached\n", + vlr_subscr_name(vsub)); + return -EINVAL; +} + +/*! \brief Start a paging request for vsub, call cbfn(param) when done. + * \param vsub subscriber to page. + * \param cbfn function to call when the conn is established. + * \param param caller defined param to pass to cbfn(). + * \param label human readable label of the request kind used for logging. + */ +struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub, + gsm_cbfn *cbfn, void *param, + const char *label) { int rc; struct subscr_request *request; - struct bsc_subscr *bsub; - struct gsm_network *net = vsub->vlr->user_ctx; /* Start paging.. we know it is async so we can do it before */ if (!vsub->cs.is_paging) { - LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n", + LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet, start paging.\n", vlr_subscr_name(vsub)); -#if 0 - TODO implement paging response in libmsc! - Excluding this to be able to link without libbsc: - - bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub); - rc = paging_request(net, bsub, channel_type, NULL, NULL); - bsc_subscr_put(bsub); -#else - rc = -ENOTSUP; -#endif + rc = msc_paging_request(vsub); if (rc <= 0) { LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n", vlr_subscr_name(vsub), rc); @@ -146,6 +152,9 @@ struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub, /* reduced on the first paging callback */ vlr_subscr_get(vsub); vsub->cs.is_paging = true; + } else { + LOGP(DMM, LOGL_DEBUG, "Subscriber %s already paged.\n", + vlr_subscr_name(vsub)); } /* TODO: Stop paging in case of memory allocation failure */ @@ -177,4 +186,3 @@ struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub) return NULL; } -#endif diff --git a/openbsc/src/libmsc/iucs.c b/openbsc/src/libmsc/iucs.c new file mode 100644 index 000000000..aeda1406a --- /dev/null +++ b/openbsc/src/libmsc/iucs.c @@ -0,0 +1,191 @@ +/* Code to manage MSC subscriber connections over IuCS interface */ + +/* + * (C) 2016,2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> + * + * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <inttypes.h> + +#include <osmocom/core/logging.h> +#include <openbsc/debug.h> + +#include <openbsc/gsm_data.h> +#include <openbsc/iu.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/osmo_msc.h> +#include <openbsc/vlr.h> + +/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */ +static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network, + struct ue_conn_ctx *ue, + uint16_t lac) +{ + struct gsm_subscriber_connection *conn; + + DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, link_id %p, conn_id %" PRIx32 "\n", + lac, ue->link, ue->conn_id); + + conn = talloc_zero(network, struct gsm_subscriber_connection); + if (!conn) + return NULL; + + conn->network = network; + conn->via_ran = RAN_UTRAN_IU; + conn->iu.ue_ctx = ue; + conn->iu.ue_ctx->rab_assign_addr_enc = network->iu.rab_assign_addr_enc; + conn->lac = lac; + + llist_add_tail(&conn->entry, &network->subscr_conns); + return conn; +} + +static int same_ue_conn(struct ue_conn_ctx *a, struct ue_conn_ctx *b) +{ + if (a == b) + return 1; + return (a->link == b->link) + && (a->conn_id == b->conn_id); +} + +static inline void log_subscribers(struct gsm_network *network) +{ + if (!log_check_level(DIUCS, LOGL_DEBUG)) + return; + + struct gsm_subscriber_connection *conn; + int i = 0; + llist_for_each_entry(conn, &network->subscr_conns, entry) { + DEBUGP(DIUCS, "%3d: %s", i, vlr_subscr_name(conn->vsub)); + switch (conn->via_ran) { + case RAN_UTRAN_IU: + DEBUGPC(DIUCS, " Iu"); + if (conn->iu.ue_ctx) { + DEBUGPC(DIUCS, " link %p, conn_id %d", + conn->iu.ue_ctx->link, + conn->iu.ue_ctx->conn_id + ); + } + break; + case RAN_GERAN_A: + DEBUGPC(DIUCS, " A"); + /* TODO log A-interface connection details */ + break; + case RAN_UNKNOWN: + DEBUGPC(DIUCS, " ?"); + break; + default: + DEBUGPC(DIUCS, " invalid"); + break; + } + DEBUGPC(DIUCS, "\n"); + i++; + } + DEBUGP(DIUCS, "subscribers registered: %d\n", i); +} + +/* Return an existing IuCS subscriber connection record for the given link and + * connection IDs, or return NULL if not found. */ +struct gsm_subscriber_connection *subscr_conn_lookup_iu( + struct gsm_network *network, + struct ue_conn_ctx *ue) +{ + struct gsm_subscriber_connection *conn; + + DEBUGP(DIUCS, "Looking for IuCS subscriber: link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + log_subscribers(network); + + llist_for_each_entry(conn, &network->subscr_conns, entry) { + if (conn->via_ran != RAN_UTRAN_IU) + continue; + if (!same_ue_conn(conn->iu.ue_ctx, ue)) + continue; + DEBUGP(DIUCS, "Found IuCS subscriber for link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + return conn; + } + DEBUGP(DIUCS, "No IuCS subscriber found for link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + return NULL; +} + +/* Receive MM/CC/... message from IuCS (SCCP user SAP). + * msg->dst must reference a struct ue_conn_ctx, which identifies the peer that + * sent the msg. + * + * For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */ +int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg, + uint16_t *lac) +{ + int rc; + struct ue_conn_ctx *ue_ctx; + struct gsm_subscriber_connection *conn; + + ue_ctx = (struct ue_conn_ctx*)msg->dst; + + /* TODO: are there message types that could allow us to skip this + * search? */ + conn = subscr_conn_lookup_iu(network, ue_ctx); + + if (conn && lac && (conn->lac != *lac)) { + LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC" + " within the same connection, discarding connection:" + " %s from LAC %d to %d\n", + vlr_subscr_name(conn->vsub), conn->lac, *lac); + /* Deallocate conn with previous LAC */ + msc_subscr_conn_close(conn, GSM_CAUSE_INV_MAND_INFO); + /* At this point we could be tolerant and allocate a new + * connection, but changing the LAC within the same connection + * is shifty. Rather cancel everything. */ + return -1; + } + + if (conn) { + /* Make sure we don't receive RR over IuCS; otherwise all + * messages handled by gsm0408_dispatch() are of interest (CC, + * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */ + struct gsm48_hdr *gh = msgb_l3(msg); + uint8_t pdisc = gh->proto_discr & 0x0f; + OSMO_ASSERT(pdisc != GSM48_PDISC_RR); + + msc_dtap(conn, ue_ctx->conn_id, msg); + rc = 0; + } else { + /* allocate a new connection */ + + if (!lac) { + LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber" + " but no LAC available. Expecting an InitialUE" + " message containing a LAI IE." + " Dropping connection.\n"); + return -1; + } + + conn = subscr_conn_allocate_iu(network, ue_ctx, *lac); + if (!conn) + abort(); + + /* ownership of conn hereby goes to the MSC: */ + rc = msc_compl_l3(conn, msg, 0); + } + + return rc; +} diff --git a/openbsc/src/libmsc/iucs_ranap.c b/openbsc/src/libmsc/iucs_ranap.c new file mode 100644 index 000000000..b69d52bc7 --- /dev/null +++ b/openbsc/src/libmsc/iucs_ranap.c @@ -0,0 +1,106 @@ +/* Implementation of RANAP messages to/from an MSC via an Iu-CS interface. + * This keeps direct RANAP dependencies out of libmsc. */ + +/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#include <osmocom/core/logging.h> + +#include <osmocom/ranap/ranap_ies_defs.h> + +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/iu.h> +#include <openbsc/iucs.h> +#include <openbsc/vlr.h> +#include <openbsc/iucs_ranap.h> +#include <openbsc/osmo_msc.h> + +/* To continue authorization after a Security Mode Complete */ +int gsm0408_authorize(struct gsm_subscriber_connection *conn); + +static int iucs_rx_rab_assign(struct gsm_subscriber_connection *conn, + RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) +{ + uint8_t rab_id; + RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem; + + rab_id = item->rAB_ID.buf[0]; + + LOGP(DIUCS, LOGL_NOTICE, + "Received RAB assignment event for %s rab_id=%hhd\n", + vlr_subscr_name(conn->vsub), rab_id); + + return 0; +} + +int iucs_rx_sec_mode_compl(struct gsm_subscriber_connection *conn, + RANAP_SecurityModeCompleteIEs_t *ies) +{ + OSMO_ASSERT(conn->via_ran == RAN_UTRAN_IU); + + /* TODO evalute ies */ + + if (conn->iu.integrity_protection) + LOGP(DIUCS, LOGL_NOTICE, "Integrity Protection" + " was already enabled for %s\n", + vlr_subscr_name(conn->vsub)); + + conn->iu.integrity_protection = INTEGRITY_PROTECTION_IK; + + msc_rx_sec_mode_compl(conn); + return 0; +} + +int iucs_rx_ranap_event(struct gsm_network *network, + struct ue_conn_ctx *ue_ctx, int type, void *data) +{ + struct gsm_subscriber_connection *conn; + + conn = subscr_conn_lookup_iu(network, ue_ctx); + + if (!conn) { + LOGP(DRANAP, LOGL_ERROR, "Cannot find subscriber for IU event %u\n", type); + return -1; + } + + switch (type) { + case IU_EVENT_IU_RELEASE: + case IU_EVENT_LINK_INVALIDATED: + LOGP(DIUCS, LOGL_INFO, "IuCS release for %s\n", + vlr_subscr_name(conn->vsub)); + msc_subscr_conn_close(conn, 0); + return 0; + + case IU_EVENT_SECURITY_MODE_COMPLETE: + LOGP(DIUCS, LOGL_INFO, "IuCS security mode complete for %s\n", + vlr_subscr_name(conn->vsub)); + return iucs_rx_sec_mode_compl(conn, + (RANAP_SecurityModeCompleteIEs_t*)data); + case IU_EVENT_RAB_ASSIGN: + return iucs_rx_rab_assign(conn, + (RANAP_RAB_SetupOrModifiedItemIEs_t*)data); + default: + LOGP(DIUCS, LOGL_NOTICE, "Unknown message received:" + " RANAP event: %i\n", type); + return -1; + } +} diff --git a/openbsc/src/libmsc/msc_ifaces.c b/openbsc/src/libmsc/msc_ifaces.c index 500c99c2e..1a7d878a2 100644 --- a/openbsc/src/libmsc/msc_ifaces.c +++ b/openbsc/src/libmsc/msc_ifaces.c @@ -23,9 +23,25 @@ #include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <openbsc/msc_ifaces.h> +#include <openbsc/iu.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/transaction.h> +#include <openbsc/mgcp.h> +#include <openbsc/mgcpgw_client.h> +#include <openbsc/vlr.h> + +#include "../../bscconfig.h" + +extern struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, + uint32_t rtp_ip, + uint16_t rtp_port, + bool use_x213_nsap); static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg) { + DEBUGP(DMSC, "msc_tx %u bytes to %s via %s\n", + msg->len, vlr_subscr_name(conn->vsub), + ran_type_name(conn->via_ran)); switch (conn->via_ran) { case RAN_GERAN_A: msg->dst = conn; @@ -60,7 +76,8 @@ int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn) gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_CM_SERV_ACC; - DEBUGP(DMM, "-> CM SERVICE ACCEPT\n"); + DEBUGP(DMM, "-> CM SERVICE ACCEPT %s\n", + vlr_subscr_name(conn->vsub)); return msc_tx_dtap(conn, msg); } @@ -70,6 +87,7 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, enum gsm48_reject_value value) { struct msgb *msg; + conn->received_cm_service_request = false; msg = gsm48_create_mm_serv_rej(value); if (!msg) { @@ -81,3 +99,223 @@ int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, return msc_tx_dtap(conn, msg); } + +int msc_tx_common_id(struct gsm_subscriber_connection *conn) +{ + /* Common ID is only sent over IuCS */ + if (conn->via_ran != RAN_UTRAN_IU) { + LOGP(DMM, LOGL_INFO, + "%s: Asked to transmit Common ID, but skipping" + " because this is not on UTRAN\n", + vlr_subscr_name(conn->vsub)); + return 0; + } + +#ifdef BUILD_IU + DEBUGP(DIUCS, "%s: tx CommonID %s\n", + vlr_subscr_name(conn->vsub), conn->vsub->imsi); + return iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi); +#else + LOGP(DMM, LOGL_ERROR, + "Cannot send CommonID: RAN_UTRAN_IU but IuCS support not built\n"); + return -ENOTSUP; +#endif +} + +#ifdef BUILD_IU +static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id, + uint32_t rtp_ip, uint16_t rtp_port) +{ + struct msgb *msg; + bool use_x213_nsap; + uint32_t conn_id = uectx->conn_id; + + use_x213_nsap = (uectx->rab_assign_addr_enc == NSAP_ADDR_ENC_X213); + + LOGP(DIUCS, LOGL_DEBUG, "Assigning RAB: conn_id=%u, rab_id=%d," + " rtp=%x:%u, use_x213_nsap=%d\n", conn_id, rab_id, rtp_ip, + rtp_port, use_x213_nsap); + + msg = ranap_new_msg_rab_assign_voice(rab_id, rtp_ip, rtp_port, + use_x213_nsap); + msg->l2h = msg->data; + + if (iu_rab_act(uectx, msg)) + LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:" + " conn_id=%d rab_id=%d rtp=%x:%u\n", + conn_id, rab_id, rtp_ip, rtp_port); +} + +static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv) +{ + struct gsm_trans *trans = priv; + struct gsm_subscriber_connection *conn = trans->conn; + struct ue_conn_ctx *uectx = conn->iu.ue_ctx; + uint32_t rtp_ip; + int rc; + + if (r->head.response_code != 200) { + LOGP(DMGCP, LOGL_ERROR, + "MGCPGW response yields error: %d %s\n", + r->head.response_code, r->head.comment); + goto rab_act_cs_error; + } + + rc = mgcp_response_parse_params(r); + if (rc) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot parse MGCP response, for %s\n", + vlr_subscr_name(trans->vsub)); + goto rab_act_cs_error; + } + + conn->iu.mgcp_rtp_port_cn = r->audio_port; + + rtp_ip = mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client); + iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip, + conn->iu.mgcp_rtp_port_ue); + /* use_x213_nsap == 0 for ip.access nano3G */ + +rab_act_cs_error: + /* FIXME abort call, invalidate conn, ... */ + return; +} + +static int conn_iu_rab_act_cs(struct gsm_trans *trans) +{ + struct gsm_subscriber_connection *conn = trans->conn; + struct mgcpgw_client *mgcp = conn->network->mgcpgw.client; + struct msgb *msg; + + /* HACK. where to scope the RAB Id? At the conn / subscriber / + * ue_conn_ctx? */ + static uint8_t next_rab_id = 1; + conn->iu.rab_id = next_rab_id ++; + + conn->iu.mgcp_rtp_endpoint = + mgcpgw_client_next_endpoint(conn->network->mgcpgw.client); + /* HACK: the addresses should be known from CRCX response + * and config. */ + conn->iu.mgcp_rtp_port_ue = 4000 + 2 * conn->iu.mgcp_rtp_endpoint; + + /* Establish the RTP stream first as looping back to the originator. + * The MDCX will patch through to the counterpart. TODO: play a ring + * tone instead. */ + msg = mgcp_msg_crcx(mgcp, conn->iu.mgcp_rtp_endpoint, trans->callref, + MGCP_CONN_LOOPBACK); + return mgcpgw_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans); +} +#endif + +int msc_call_assignment(struct gsm_trans *trans) +{ + struct gsm_subscriber_connection *conn = trans->conn; + + switch (conn->via_ran) { + case RAN_GERAN_A: + LOGP(DMSC, LOGL_ERROR, + "msc_call_assignment(): A-interface BSSMAP Assignment" + " Request not yet implemented\n"); + return -ENOTSUP; + + case RAN_UTRAN_IU: +#ifdef BUILD_IU + return conn_iu_rab_act_cs(trans); +#else + LOGP(DMSC, LOGL_ERROR, + "msc_call_assignment(): IuCS RAB Activation not supported" + " in this build\n"); + return -ENOTSUP; +#endif + + default: + LOGP(DMSC, LOGL_ERROR, + "msc_tx(): conn->via_ran invalid (%d)\n", + conn->via_ran); + return -EINVAL; + } +} + +static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv); + +static void mgcp_bridge(struct gsm_trans *from, struct gsm_trans *to, + enum bridge_state state, + enum mgcp_connection_mode mode) +{ + struct gsm_subscriber_connection *conn1 = from->conn; + struct gsm_subscriber_connection *conn2 = to->conn; + struct mgcpgw_client *mgcp = conn1->network->mgcpgw.client; + const char *ip; + struct msgb *msg; + + OSMO_ASSERT(mgcp); + + from->bridge.peer = to; + from->bridge.state = state; + + /* Loop back to the same MGCP GW */ + ip = mgcpgw_client_remote_addr_str(mgcp); + + msg = mgcp_msg_mdcx(mgcp, + conn1->iu.mgcp_rtp_endpoint, + ip, conn2->iu.mgcp_rtp_port_cn, + mode); + if (mgcpgw_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from)) + LOGP(DMGCP, LOGL_ERROR, + "Failed to send MDCX message for %s\n", + vlr_subscr_name(from->vsub)); +} + +static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv) +{ + struct gsm_trans *trans = priv; + struct gsm_trans *peer = trans->bridge.peer; + + switch (trans->bridge.state) { + case BRIDGE_STATE_LOOPBACK_PENDING: + trans->bridge.state = BRIDGE_STATE_LOOPBACK_ESTABLISHED; + + switch (peer->bridge.state) { + case BRIDGE_STATE_LOOPBACK_PENDING: + /* Wait until the other is done as well. */ + return; + case BRIDGE_STATE_LOOPBACK_ESTABLISHED: + /* Now that both are in loopback, switch both to + * forwarding. */ + mgcp_bridge(trans, peer, BRIDGE_STATE_BRIDGE_PENDING, + MGCP_CONN_RECV_SEND); + mgcp_bridge(peer, trans, BRIDGE_STATE_BRIDGE_PENDING, + MGCP_CONN_RECV_SEND); + break; + default: + LOGP(DMGCP, LOGL_ERROR, + "Unexpected bridge state: %d for %s\n", + trans->bridge.state, vlr_subscr_name(trans->vsub)); + break; + } + break; + + case BRIDGE_STATE_BRIDGE_PENDING: + trans->bridge.state = BRIDGE_STATE_BRIDGE_ESTABLISHED; + break; + + default: + LOGP(DMGCP, LOGL_ERROR, + "Unexpected bridge state: %d for %s\n", + trans->bridge.state, vlr_subscr_name(trans->vsub)); + break; + } +} + +int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2) +{ + /* First setup as loopback and configure the counterparts' endpoints, + * so that when transmission starts the originating addresses are + * already known to be valid. The mgcp callback will continue. */ + mgcp_bridge(trans1, trans2, BRIDGE_STATE_LOOPBACK_PENDING, + MGCP_CONN_LOOPBACK); + mgcp_bridge(trans2, trans1, BRIDGE_STATE_LOOPBACK_PENDING, + MGCP_CONN_LOOPBACK); + + return 0; +} diff --git a/openbsc/src/libmsc/msc_vty.c b/openbsc/src/libmsc/msc_vty.c new file mode 100644 index 000000000..b6fff56af --- /dev/null +++ b/openbsc/src/libmsc/msc_vty.c @@ -0,0 +1,181 @@ +/* MSC interface to quagga VTY */ +/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de> + * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c) + * (C) 2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2009-2011 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +/* NOTE: I would have liked to call this the MSC_NODE instead of the MSC_NODE, + * but MSC_NODE already exists to configure a remote MSC for osmo-bsc. */ + +#include <inttypes.h> + +#include <osmocom/vty/command.h> + +#include <openbsc/vty.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/vlr.h> +#include <openbsc/iu.h> + +static struct cmd_node msc_node = { + MSC_NODE, + "%s(config-msc)# ", + 1, +}; + +DEFUN(cfg_msc, cfg_msc_cmd, + "msc", "Configure MSC options") +{ + vty->node = MSC_NODE; + return CMD_SUCCESS; +} + +/* Note: limit on the parameter length is set by internal vty code limitations */ +DEFUN(cfg_msc_subscr_random, cfg_msc_subscr_random_cmd, + "subscriber-create-on-demand random <1-9999999999> <2-9999999999>", + "Set random parameters for a new record when a subscriber is first seen.\n" + "Set random parameters for a new record when a subscriber is first seen.\n" + "Minimum for subscriber extension\n""Maximum for subscriber extension\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + uint64_t mi = atoi(argv[0]), ma = atoi(argv[1]); + gsmnet->auto_create_subscr = true; + gsmnet->auto_assign_exten = true; + if (mi >= ma) { + vty_out(vty, "Incorrect range: %s >= %s, expected MIN < MAX%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + gsmnet->ext_min = mi; + gsmnet->ext_max = ma; + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_subscr_create, cfg_msc_subscr_create_cmd, + "subscriber-create-on-demand [no-extension]", + "Make a new record when a subscriber is first seen.\n" + "Do not automatically assign extension to created subscribers\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->auto_create_subscr = true; + gsmnet->auto_assign_exten = argc ? false : true; + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_no_subscr_create, cfg_msc_no_subscr_create_cmd, + "no subscriber-create-on-demand", + NO_STR "Make a new record when a subscriber is first seen.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->auto_create_subscr = false; + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_assign_tmsi, cfg_msc_assign_tmsi_cmd, + "assign-tmsi", + "Assign TMSI during Location Updating.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->vlr->cfg.assign_tmsi = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_no_assign_tmsi, cfg_msc_no_assign_tmsi_cmd, + "no assign-tmsi", + NO_STR "Assign TMSI during Location Updating.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->vlr->cfg.assign_tmsi = false; + return CMD_SUCCESS; +} + +static int config_write_msc(struct vty *vty) +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + + vty_out(vty, "msc%s", VTY_NEWLINE); + if (!gsmnet->auto_create_subscr) + vty_out(vty, " no subscriber-create-on-demand%s", VTY_NEWLINE); + else + vty_out(vty, " subscriber-create-on-demand%s%s", + gsmnet->auto_assign_exten ? "" : " no-extension", + VTY_NEWLINE); + + if (gsmnet->ext_min != GSM_MIN_EXTEN || gsmnet->ext_max != GSM_MAX_EXTEN) + vty_out(vty, " subscriber-create-on-demand random %"PRIu64" %" + PRIu64"%s", gsmnet->ext_min, gsmnet->ext_max, + VTY_NEWLINE); + vty_out(vty, " %sassign-tmsi%s", + gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE); + + mgcpgw_client_config_write(vty, " "); + iu_vty_config_write(vty, " "); + + return CMD_SUCCESS; +} + +static int config_write_net(struct vty *vty) +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + + vty_out(vty, "network%s", VTY_NEWLINE); + vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE); + vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE); + 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, " location updating reject cause %u%s", + gsmnet->reject_cause, VTY_NEWLINE); + vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); + vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), + VTY_NEWLINE); + vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); + if (gsmnet->tz.override != 0) { + if (gsmnet->tz.dst) + vty_out(vty, " timezone %d %d %d%s", + gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst, + VTY_NEWLINE); + else + vty_out(vty, " timezone %d %d%s", + gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE); + } + if (gsmnet->t3212 == 0) + vty_out(vty, " no periodic location update%s", VTY_NEWLINE); + else + vty_out(vty, " periodic location update %u%s", + gsmnet->t3212 * 6, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +void msc_vty_init(struct gsm_network *msc_network) +{ + common_cs_vty_init(msc_network, config_write_net); + + install_element(CONFIG_NODE, &cfg_msc_cmd); + install_node(&msc_node, config_write_msc); + vty_install_default(MSC_NODE); + install_element(MSC_NODE, &cfg_msc_subscr_create_cmd); + install_element(MSC_NODE, &cfg_msc_subscr_random_cmd); + install_element(MSC_NODE, &cfg_msc_no_subscr_create_cmd); + install_element(MSC_NODE, &cfg_msc_assign_tmsi_cmd); + install_element(MSC_NODE, &cfg_msc_no_assign_tmsi_cmd); + mgcpgw_client_vty_init(MSC_NODE, &msc_network->mgcpgw.conf); + iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc); +} diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c index ab53b0be7..bfe5343cf 100644 --- a/openbsc/src/libmsc/osmo_msc.c +++ b/openbsc/src/libmsc/osmo_msc.c @@ -28,6 +28,7 @@ #include <openbsc/db.h> #include <openbsc/vlr.h> #include <openbsc/osmo_msc.h> +#include <openbsc/iu.h> #include <openbsc/gsm_04_11.h> @@ -40,24 +41,6 @@ static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) gsm411_sapi_n_reject(conn); } -static bool keep_conn(struct gsm_subscriber_connection *conn) -{ - /* TODO: what about a silent call? */ - - if (!conn->conn_fsm) { - DEBUGP(DMM, "No conn_fsm, release conn\n"); - return false; - } - - switch (conn->conn_fsm->state) { - case SUBSCR_CONN_S_NEW: - case SUBSCR_CONN_S_ACCEPTED: - return true; - default: - return false; - } -} - static void subscr_conn_bump(struct gsm_subscriber_connection *conn) { if (!conn) @@ -65,39 +48,32 @@ static void subscr_conn_bump(struct gsm_subscriber_connection *conn) if (!conn->conn_fsm) return; if (!(conn->conn_fsm->state == SUBSCR_CONN_S_ACCEPTED - || conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING)) + || conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING)) { + DEBUGP(DMM, "%s: bump: conn still being established (%s)\n", + vlr_subscr_name(conn->vsub), + osmo_fsm_inst_state_name(conn->conn_fsm)); return; + } osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL); } /* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or * MSC_CONN_REJECT */ -enum msc_compl_l3_rc msc_compl_l3(struct gsm_subscriber_connection *conn, - struct msgb *msg, uint16_t chosen_channel) +int msc_compl_l3(struct gsm_subscriber_connection *conn, + struct msgb *msg, uint16_t chosen_channel) { - /* Ownership of the gsm_subscriber_connection is still a bit mucky - * between libbsc and libmsc. In libmsc, we use ref counting, but not - * in libbsc. This will become simpler with the MSCSPLIT. */ - - /* reserve for the duration of this function */ msc_subscr_conn_get(conn); - gsm0408_dispatch(conn, msg); - if (!keep_conn(conn)) { - DEBUGP(DMM, "compl_l3: Discarding conn\n"); - /* keep the use_count reserved, libbsc will discard. If we - * released the ref count and discarded here, libbsc would - * double-free. And we will not change bsc_api semantics. */ - return MSC_CONN_REJECT; - } - DEBUGP(DMM, "compl_l3: Keeping conn\n"); - /* Bump whether the conn wants to be closed */ subscr_conn_bump(conn); /* If this should be kept, the conn->conn_fsm has placed a use_count */ msc_subscr_conn_put(conn); + + /* Always return acceptance, because even if the conn was not accepted, + * we assumed ownership of it and the caller shall not interfere with + * that. We may even already have discarded the conn. */ return MSC_CONN_ACCEPT; #if 0 @@ -119,7 +95,7 @@ enum msc_compl_l3_rc msc_compl_l3(struct gsm_subscriber_connection *conn, } /* Receive a DTAP message from BSC */ -static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) +void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { msc_subscr_conn_get(conn); gsm0408_dispatch(conn, msg); @@ -158,8 +134,8 @@ static void msc_classmark_chg(struct gsm_subscriber_connection *conn, } /* Receive a CIPHERING MODE COMPLETE from BSC */ -static void msc_ciph_m_compl(struct gsm_subscriber_connection *conn, - struct msgb *msg, uint8_t alg_id) +void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn, + struct msgb *msg, uint8_t alg_id) { struct gsm48_hdr *gh = msgb_l3(msg); unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); @@ -277,7 +253,7 @@ static struct bsc_api msc_handler = { .assign_compl = msc_assign_compl, .assign_fail = msc_assign_fail, .classmark_chg = msc_classmark_chg, - .cipher_mode_compl = msc_ciph_m_compl, + .cipher_mode_compl = msc_cipher_mode_compl, .conn_cleanup = msc_subscr_con_cleanup, }; @@ -285,6 +261,10 @@ struct bsc_api *msc_bsc_api() { return &msc_handler; } +/* Signal the connection's FSM to gracefully terminate the connection by a + * SUBSCR_CONN_E_CN_CLOSE event. + * \param cause a GSM_CAUSE_* constant, e.g. GSM_CAUSE_AUTH_FAILED. + */ void msc_subscr_conn_close(struct gsm_subscriber_connection *conn, uint32_t cause) { @@ -335,8 +315,12 @@ void _msc_subscr_conn_put(struct gsm_subscriber_connection *conn, "%s: MSC conn use - 1 == %u\n", vlr_subscr_name(conn->vsub), conn->use_count); - if (conn->use_count == 0) { - gsm0808_clear(conn); - bsc_subscr_con_free(conn); - } + if (conn->use_count == 0) + msc_subscr_con_free(conn); +} + +void msc_stop_paging(struct vlr_subscr *vsub) +{ + DEBUGP(DPAG, "Paging can stop for %s\n", vlr_subscr_name(vsub)); + /* tell BSCs and RNCs to stop paging? How? */ } diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c index 76816c29d..256b5b453 100644 --- a/openbsc/src/libmsc/silent_call.c +++ b/openbsc/src/libmsc/silent_call.c @@ -131,7 +131,8 @@ int gsm_silent_call_start(struct vlr_subscr *vsub, void *data, int type) /* FIXME the VTY command allows selecting a silent call channel type. * This doesn't apply to the situation after MSCSPLIT with an * A-interface. */ - req = subscr_request_conn(vsub, type, paging_cb_silent, data); + req = subscr_request_conn(vsub, paging_cb_silent, data, + "establish silent call"); return req != NULL; } diff --git a/openbsc/src/libmsc/subscr_conn.c b/openbsc/src/libmsc/subscr_conn.c index 9be53cf4a..9d5dd5d2c 100644 --- a/openbsc/src/libmsc/subscr_conn.c +++ b/openbsc/src/libmsc/subscr_conn.c @@ -30,6 +30,7 @@ #include <openbsc/debug.h> #include <openbsc/transaction.h> #include <openbsc/signal.h> +#include <openbsc/iu.h> #define SUBSCR_CONN_TIMEOUT 5 /* seconds */ @@ -52,8 +53,8 @@ const struct value_string subscr_conn_from_names[] = { { 0, NULL } }; -static void paging_resp(struct gsm_subscriber_connection *conn, - enum gsm_paging_event pe) +static void paging_event(struct gsm_subscriber_connection *conn, + enum gsm_paging_event pe) { subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->vsub); } @@ -85,11 +86,17 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data) case SUBSCR_CONN_E_MO_CLOSE: case SUBSCR_CONN_E_CN_CLOSE: + if (data) + LOGPFSM(fi, "Close event, cause %u\n", + *(uint32_t*)data); + /* will release further below, see + * 'if (fi->state != SUBSCR_CONN_S_ACCEPTED)' */ break; default: - LOGPFSM(fi, "Unexpected event: %d %s\n", - event, osmo_fsm_event_name(fi->fsm, event)); + LOGPFSML(fi, LOGL_ERROR, + "Unexpected event: %d %s\n", event, + osmo_fsm_event_name(fi->fsm, event)); break; } @@ -102,21 +109,24 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data) /* signal paging success or failure in case this was a paging */ if (from == SUBSCR_CONN_FROM_PAGING_RESP) - paging_resp(conn, - success ? GSM_PAGING_SUCCEEDED - : GSM_PAGING_EXPIRED); + paging_event(conn, + success ? GSM_PAGING_SUCCEEDED + : GSM_PAGING_EXPIRED); + + /* FIXME rate counters */ + /*rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_COMPLETED]);*/ /* On failure, discard the conn */ if (!success) { /* TODO: on MO_CLOSE or CN_CLOSE, first go to RELEASING and - * await BSC confirmation? */ + * await BSC/RNC confirmation? */ osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0); return; } if (from == SUBSCR_CONN_FROM_CM_SERVICE_REQ) { conn->received_cm_service_request = true; - LOGPFSM(fi, "received_cm_service_request = true\n"); + LOGPFSML(fi, LOGL_DEBUG, "received_cm_service_request = true\n"); } osmo_fsm_inst_dispatch(fi, SUBSCR_CONN_E_BUMP, data); @@ -125,19 +135,37 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_trans *trans; - if (conn->silent_call) + if (conn->silent_call) { + LOGPFSML(fi, LOGL_DEBUG, "bump: silent call still active\n"); return; + } - if (conn->received_cm_service_request) + if (conn->received_cm_service_request) { + LOGPFSML(fi, LOGL_DEBUG, "bump: still awaiting first request after a CM Service Request\n"); return; + } - if (conn->vsub && !llist_empty(&conn->vsub->cs.requests)) + if (conn->vsub && !llist_empty(&conn->vsub->cs.requests)) { + struct subscr_request *sr; + if (!log_check_level(fi->fsm->log_subsys, LOGL_DEBUG)) { + llist_for_each_entry(sr, &conn->vsub->cs.requests, entry) { + LOGPFSML(fi, LOGL_DEBUG, "bump: still active: %s\n", + sr->label); + } + } return; + } - if (trans_has_conn(conn)) + if ((trans = trans_has_conn(conn))) { + LOGPFSML(fi, LOGL_DEBUG, + "bump: connection still has active transaction: %s\n", + gsm48_pdisc_name(trans->protocol)); return; + } + LOGPFSML(fi, LOGL_DEBUG, "bump: releasing conn\n"); osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0); } @@ -204,6 +232,12 @@ static void subscr_conn_fsm_cleanup(struct osmo_fsm_inst *fi, /* If we're closing in a middle of a trans, we need to clean up */ trans_conn_closed(conn); + if (conn->via_ran == RAN_UTRAN_IU) + iu_tx_release(conn->iu.ue_ctx, NULL); + /* FIXME: keep the conn until the Iu Release Outcome is + * received from the UE, or a timeout expires. For now, the log + * says "unknown UE" for each release outcome. */ + msc_subscr_conn_put(conn); } @@ -275,7 +309,7 @@ static struct osmo_fsm subscr_conn_fsm = { .num_states = ARRAY_SIZE(subscr_conn_fsm_states), .allstate_event_mask = 0, .allstate_action = NULL, - .log_subsys = DVLR, + .log_subsys = DMM, .event_names = subscr_conn_fsm_event_names, .cleanup = subscr_conn_fsm_cleanup, .timer_cb = subscr_conn_fsm_timeout, diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index 41fb5a914..73c509c2c 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -180,23 +180,35 @@ int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub, * \param[in] conn Connection to check * \returns 1 in case there is a transaction, 0 otherwise */ -int trans_has_conn(const struct gsm_subscriber_connection *conn) +struct gsm_trans *trans_has_conn(const struct gsm_subscriber_connection *conn) { struct gsm_trans *trans; llist_for_each_entry(trans, &conn->network->trans_list, entry) if (trans->conn == conn) - return 1; + return trans; - return 0; + return NULL; } +/* + * Free all transactions that are associated with the released + * connection. The transaction code will inform the CC or SMS + * facilities that will send the release indications. + */ void trans_conn_closed(struct gsm_subscriber_connection *conn) { - struct gsm_trans *trans, *t2; + struct gsm_trans *trans; - llist_for_each_entry_safe(trans, t2, &conn->network->trans_list, entry) { - if (trans->conn == conn) + /* As part of the CC REL_IND the remote leg might be released and this + * will trigger the call to trans_free. This is something the llist + * macro can not handle and we will need to re-iterate the list. + */ +restart: + llist_for_each_entry(trans, &conn->network->trans_list, entry) { + if (trans->conn == conn) { trans_free(trans); + goto restart; + } } } diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index df2d1e4ad..c783cf101 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -21,9 +21,8 @@ #include <stdlib.h> #include <limits.h> #include <unistd.h> -#include <stdbool.h> -#include <inttypes.h> #include <time.h> +#include <inttypes.h> #include <osmocom/vty/command.h> #include <osmocom/vty/buffer.h> @@ -902,7 +901,6 @@ DEFUN(logging_fltr_imsi, "Filter log messages by IMSI\n" "IMSI to be used as filter\n") { struct vlr_subscr *vlr_subscr; - struct bsc_subscr *bsc_subscr; struct gsm_network *gsmnet = gsmnet_from_vty(vty); struct log_target *tgt = osmo_log_vty2tgt(vty); const char *imsi = argv[0]; @@ -911,16 +909,14 @@ DEFUN(logging_fltr_imsi, return CMD_WARNING; vlr_subscr = vlr_subscr_find_by_imsi(gsmnet->vlr, imsi); - bsc_subscr = bsc_subscr_find_by_imsi(gsmnet->bsc_subscribers, imsi); - if (!vlr_subscr && !bsc_subscr) { + if (!vlr_subscr) { vty_out(vty, "%%no subscriber with IMSI(%s)%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } log_set_filter_vlr_subscr(tgt, vlr_subscr); - log_set_filter_bsc_subscr(tgt, bsc_subscr); return CMD_SUCCESS; } @@ -968,92 +964,6 @@ static int config_write_hlr(struct vty *vty) return CMD_SUCCESS; } -static struct cmd_node nitb_node = { - NITB_NODE, - "%s(config-nitb)# ", - 1, -}; - -DEFUN(cfg_nitb, cfg_nitb_cmd, - "nitb", "Configure NITB options") -{ - vty->node = NITB_NODE; - return CMD_SUCCESS; -} - -/* Note: limit on the parameter length is set by internal vty code limitations */ -DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd, - "subscriber-create-on-demand random <1-9999999999> <2-9999999999>", - "Set random parameters for a new record when a subscriber is first seen.\n" - "Set random parameters for a new record when a subscriber is first seen.\n" - "Minimum for subscriber extension\n""Maximum for subscriber extension\n") -{ - vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s" - "%% This is now up to osmo-hlr.%s", - VTY_NEWLINE, VTY_NEWLINE); - return CMD_WARNING; -} - -DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd, - "subscriber-create-on-demand [no-extension]", - "Make a new record when a subscriber is first seen.\n" - "Do not automatically assign extension to created subscribers\n") -{ - vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s" - "%% This is now up to osmo-hlr.%s", - VTY_NEWLINE, VTY_NEWLINE); - return CMD_WARNING; -} - -DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd, - "no subscriber-create-on-demand", - NO_STR "Make a new record when a subscriber is first seen.\n") -{ - vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s" - "%% This is now up to osmo-hlr.%s", - VTY_NEWLINE, VTY_NEWLINE); - return CMD_WARNING; -} - -DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd, - "assign-tmsi", - "Assign TMSI during Location Updating.\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->vlr->cfg.assign_tmsi = true; - return CMD_SUCCESS; -} - -DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd, - "no assign-tmsi", - NO_STR "Assign TMSI during Location Updating.\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->vlr->cfg.assign_tmsi = false; - return CMD_SUCCESS; -} - -static int config_write_nitb(struct vty *vty) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - - vty_out(vty, "nitb%s", VTY_NEWLINE); - if (!gsmnet->auto_create_subscr) - vty_out(vty, " no subscriber-create-on-demand%s", VTY_NEWLINE); - else - vty_out(vty, " subscriber-create-on-demand%s%s", - gsmnet->auto_assign_exten ? "" : " no-extension", - VTY_NEWLINE); - - if (gsmnet->ext_min != GSM_MIN_EXTEN || gsmnet->ext_max != GSM_MAX_EXTEN) - vty_out(vty, " subscriber-create-on-demand random %"PRIu64" %" - PRIu64"%s", gsmnet->ext_min, gsmnet->ext_max, - VTY_NEWLINE); - vty_out(vty, " %sassign-tmsi%s", - gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE); - return CMD_SUCCESS; -} - int bsc_vty_init_extra(void) { osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL); @@ -1105,13 +1015,5 @@ int bsc_vty_init_extra(void) install_element(HLR_NODE, &cfg_hlr_remote_ip_cmd); install_element(HLR_NODE, &cfg_hlr_remote_port_cmd); - install_element(CONFIG_NODE, &cfg_nitb_cmd); - install_node(&nitb_node, config_write_nitb); - install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd); - install_element(NITB_NODE, &cfg_nitb_subscr_random_cmd); - install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd); - install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd); - install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd); - return 0; } |