aboutsummaryrefslogtreecommitdiffstats
path: root/src/libvlr/vlr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libvlr/vlr.c')
-rw-r--r--src/libvlr/vlr.c204
1 files changed, 73 insertions, 131 deletions
diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c
index c6d8805d6..508246989 100644
--- a/src/libvlr/vlr.c
+++ b/src/libvlr/vlr.c
@@ -33,6 +33,7 @@
#include <osmocom/msc/vlr_sgs.h>
#include <osmocom/msc/vlr.h>
#include <osmocom/msc/debug.h>
+#include <osmocom/msc/gsup_client_mux.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -110,6 +111,18 @@ const char *vlr_subscr_name(const struct vlr_subscr *vsub)
return buf;
}
+const char *vlr_subscr_short_name(const struct vlr_subscr *vsub, unsigned int maxlen)
+{
+ /* cast away the const so we can shorten the string within the static buffer */
+ char *name = (char*)vlr_subscr_name(vsub);
+ size_t len = strlen(name);
+ if (maxlen < 2)
+ return "-";
+ if (len > maxlen)
+ strcpy(name + maxlen - 2, "..");
+ return name;
+}
+
const char *vlr_subscr_msisdn_or_name(const struct vlr_subscr *vsub)
{
if (!vsub || !vsub->msisdn[0])
@@ -174,31 +187,6 @@ struct vlr_subscr *_vlr_subscr_find_by_msisdn(struct vlr_instance *vlr,
return NULL;
}
-/* Transmit GSUP message to HLR */
-static int vlr_tx_gsup_message(const struct vlr_instance *vlr,
- const struct osmo_gsup_message *gsup_msg)
-{
- struct msgb *msg = osmo_gsup_client_msgb_alloc();
-
- int rc = osmo_gsup_encode(msg, gsup_msg);
- if (rc < 0) {
- LOGP(DVLR, LOGL_ERROR, "GSUP encoding failure: %s\n", strerror(-rc));
- return rc;
- }
-
- if (!vlr->gsup_client) {
- LOGP(DVLR, LOGL_NOTICE, "GSUP link is down, cannot "
- "send GSUP: %s\n", msgb_hexdump(msg));
- msgb_free(msg);
- return -ENOTSUP;
- }
-
- LOGP(DVLR, LOGL_DEBUG, "GSUP tx: %s\n",
- osmo_hexdump_nospc(msg->data, msg->len));
-
- return osmo_gsup_client_send(vlr->gsup_client, msg);
-}
-
/* Transmit GSUP message for subscriber to HLR, using IMSI from subscriber */
static int vlr_subscr_tx_gsup_message(const struct vlr_subscr *vsub,
struct osmo_gsup_message *gsup_msg)
@@ -208,40 +196,39 @@ static int vlr_subscr_tx_gsup_message(const struct vlr_subscr *vsub,
if (strlen(gsup_msg->imsi) == 0)
OSMO_STRLCPY_ARRAY(gsup_msg->imsi, vsub->imsi);
- return vlr_tx_gsup_message(vlr, gsup_msg);
-}
-
-/* Transmit GSUP error in response to original message */
-static int vlr_tx_gsup_error_reply(const struct vlr_instance *vlr,
- struct osmo_gsup_message *gsup_orig,
- enum gsm48_gmm_cause cause)
-{
- struct osmo_gsup_message gsup_reply = {0};
-
- OSMO_STRLCPY_ARRAY(gsup_reply.imsi, gsup_orig->imsi);
- gsup_reply.cause = cause;
- gsup_reply.message_type =
- OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
+ gsup_msg->message_class = OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT;
- return vlr_tx_gsup_message(vlr, &gsup_reply);
+ return gsup_client_mux_tx(vlr->gcm, gsup_msg);
}
static int vlr_subscr_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line)
{
struct vlr_subscr *vsub = e->use_count->talloc_object;
char buf[128];
+ int32_t total;
+ int level;
if (!e->use)
return -EINVAL;
- LOGPSRC(DREF, LOGL_DEBUG, file, line, "VLR subscr %s %s %s: now used by %s\n",
+ total = osmo_use_count_total(&vsub->use_count);
+
+ if (total == 0
+ || (total == 1 && old_use_count == 0 && e->count == 1))
+ level = LOGL_INFO;
+ else
+ level = LOGL_DEBUG;
+
+ LOGPSRC(DREF, level, file, line, "VLR subscr %s %s %s: now used by %s\n",
vlr_subscr_name(vsub), (e->count - old_use_count) > 0? "+" : "-", e->use,
osmo_use_count_name_buf(buf, sizeof(buf), e->use_count));
if (e->count < 0)
return -ERANGE;
- if (osmo_use_count_total(e->use_count) <= 0)
+ vsub->max_total_use_count = OSMO_MAX(vsub->max_total_use_count, total);
+
+ if (total <= 0)
vlr_subscr_free(vsub);
return 0;
}
@@ -261,6 +248,7 @@ static struct vlr_subscr *_vlr_subscr_alloc(struct vlr_instance *vlr)
.talloc_object = vsub,
.use_cb = vlr_subscr_use_cb,
},
+ .expire_lu = VLR_SUBSCRIBER_NO_EXPIRATION,
};
osmo_use_count_make_static_entries(&vsub->use_count, vsub->use_count_buf, ARRAY_SIZE(vsub->use_count_buf));
@@ -314,7 +302,8 @@ void vlr_subscr_cancel_attach_fsm(struct vlr_subscr *vsub,
void vlr_subscr_free(struct vlr_subscr *vsub)
{
llist_del(&vsub->list);
- DEBUGP(DREF, "freeing VLR subscr %s\n", vlr_subscr_name(vsub));
+ DEBUGP(DVLR, "freeing VLR subscr %s (max total use count was %d)\n", vlr_subscr_name(vsub),
+ vsub->max_total_use_count);
/* Make sure SGs timer Ts5 is removed */
osmo_timer_del(&vsub->sgs.Ts5);
@@ -611,17 +600,14 @@ vlr_subscr_pdp_data_get_by_id(struct vlr_subscr *vsub, unsigned context_id)
***********************************************************************/
static int vlr_rx_gsup_unknown_imsi(struct vlr_instance *vlr,
- struct osmo_gsup_message *gsup_msg)
+ const struct osmo_gsup_message *gsup_msg)
{
if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
- int rc = vlr_tx_gsup_error_reply(vlr, gsup_msg, GMM_CAUSE_IMSI_UNKNOWN);
- if (rc < 0)
- LOGP(DVLR, LOGL_ERROR, "Failed to send error reply for IMSI %s\n", gsup_msg->imsi);
-
LOGP(DVLR, LOGL_NOTICE,
"Unknown IMSI %s, discarding GSUP request "
"of type 0x%02x\n",
gsup_msg->imsi, gsup_msg->message_type);
+ gsup_client_mux_tx_error_reply(vlr->gcm, gsup_msg, GMM_CAUSE_IMSI_UNKNOWN);
} else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
LOGP(DVLR, LOGL_NOTICE,
"Unknown IMSI %s, discarding GSUP error "
@@ -640,7 +626,7 @@ static int vlr_rx_gsup_unknown_imsi(struct vlr_instance *vlr,
}
static int vlr_rx_gsup_purge_no_subscr(struct vlr_instance *vlr,
- struct osmo_gsup_message *gsup_msg)
+ const struct osmo_gsup_message *gsup_msg)
{
if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
LOGGSUPP(LOGL_NOTICE, gsup_msg,
@@ -682,7 +668,9 @@ int vlr_subscr_req_sai(struct vlr_subscr *vsub,
/* Initiate Check_IMEI_VLR Procedure (23.018 Chapter 7.1.2.9) */
int vlr_subscr_tx_req_check_imei(const struct vlr_subscr *vsub)
{
- struct osmo_gsup_message gsup_msg = {0};
+ struct osmo_gsup_message gsup_msg = {
+ .message_class = OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT,
+ };
uint8_t imei_enc[GSM23003_IMEI_NUM_DIGITS+2]; /* +2: IE header */
int len;
@@ -698,17 +686,19 @@ int vlr_subscr_tx_req_check_imei(const struct vlr_subscr *vsub)
/* Send CHECK_IMEI_REQUEST */
gsup_msg.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST;
OSMO_STRLCPY_ARRAY(gsup_msg.imsi, vsub->imsi);
- return vlr_tx_gsup_message(vsub->vlr, &gsup_msg);
+ return gsup_client_mux_tx(vsub->vlr->gcm, &gsup_msg);
}
/* Tell HLR that authentication failure occurred */
int vlr_subscr_tx_auth_fail_rep(const struct vlr_subscr *vsub)
{
- struct osmo_gsup_message gsup_msg = {0};
+ struct osmo_gsup_message gsup_msg = {
+ .message_class = OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT,
+ };
gsup_msg.message_type = OSMO_GSUP_MSGT_AUTH_FAIL_REPORT;
OSMO_STRLCPY_ARRAY(gsup_msg.imsi, vsub->imsi);
- return vlr_tx_gsup_message(vsub->vlr, &gsup_msg);
+ return gsup_client_mux_tx(vsub->vlr->gcm, &gsup_msg);
}
/* Update the subscriber with GSUP-received auth tuples */
@@ -771,21 +761,6 @@ static int vlr_subscr_handle_sai_res(struct vlr_subscr *vsub,
return 0;
}
-static int decode_bcd_number_safe(char *output, int output_len,
- const uint8_t *bcd_lv, int input_len,
- int h_len)
-{
- uint8_t len;
- OSMO_ASSERT(output_len >= 1);
- *output = '\0';
- if (input_len < 1)
- return -EIO;
- len = bcd_lv[0];
- if (input_len < len)
- return -EIO;
- return gsm48_decode_bcd_number(output, output_len, bcd_lv, h_len);
-}
-
static void vlr_subscr_gsup_insert_data(struct vlr_subscr *vsub,
const struct osmo_gsup_message *gsup_msg)
{
@@ -793,9 +768,9 @@ static void vlr_subscr_gsup_insert_data(struct vlr_subscr *vsub,
int rc;
if (gsup_msg->msisdn_enc) {//FIXME: vlr_subscr_set_msisdn()?
- decode_bcd_number_safe(vsub->msisdn, sizeof(vsub->msisdn),
- gsup_msg->msisdn_enc,
- gsup_msg->msisdn_enc_len, 0);
+ gsm48_decode_bcd_number2(vsub->msisdn, sizeof(vsub->msisdn),
+ gsup_msg->msisdn_enc,
+ gsup_msg->msisdn_enc_len, 0);
LOGP(DVLR, LOGL_DEBUG, "IMSI:%s has MSISDN:%s\n",
vsub->imsi, vsub->msisdn);
}
@@ -1033,7 +1008,7 @@ static void gmm_cause_to_fsm_and_mm_cause(enum gsm48_gmm_cause gmm_cause,
/* Handle LOCATION CANCEL request from HLR */
static int vlr_subscr_handle_cancel_req(struct vlr_subscr *vsub,
- struct osmo_gsup_message *gsup_msg)
+ const struct osmo_gsup_message *gsup_msg)
{
enum gsm48_reject_value gsm48_rej;
enum osmo_fsm_term_cause fsm_cause;
@@ -1081,87 +1056,59 @@ static int vlr_subscr_handle_check_imei(struct vlr_subscr *vsub, const struct os
/* Incoming handler for GSUP from HLR.
* Keep this function non-static for direct invocation by unit tests. */
-int vlr_gsupc_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg)
+int vlr_gsup_rx(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *gsup)
{
- struct vlr_instance *vlr = (struct vlr_instance *) gsupc->data;
+ struct vlr_instance *vlr = data;
struct vlr_subscr *vsub;
- struct osmo_gsup_message gsup;
int rc;
- DEBUGP(DVLR, "GSUP rx %u: %s\n", msgb_l2len(msg),
- osmo_hexdump_nospc(msgb_l2(msg), msgb_l2len(msg)));
-
- rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
- if (rc < 0) {
- LOGP(DVLR, LOGL_ERROR,
- "decoding GSUP message fails with error '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, -rc), -rc);
- goto msgb_free_and_return;
- }
-
- if (!gsup.imsi[0]) {
- LOGP(DVLR, LOGL_ERROR, "Missing IMSI in GSUP message\n");
- if (OSMO_GSUP_IS_MSGT_REQUEST(gsup.message_type)) {
- rc = vlr_tx_gsup_error_reply(vlr, &gsup, GMM_CAUSE_INV_MAND_INFO);
- if (rc < 0)
- LOGP(DVLR, LOGL_ERROR, "Failed to send error reply for IMSI %s\n", gsup.imsi);
- }
- rc = -GMM_CAUSE_INV_MAND_INFO;
- goto msgb_free_and_return;
- }
-
- vsub = vlr_subscr_find_by_imsi(vlr, gsup.imsi, __func__);
+ vsub = vlr_subscr_find_by_imsi(vlr, gsup->imsi, __func__);
if (!vsub) {
- switch (gsup.message_type) {
+ switch (gsup->message_type) {
case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
- rc = vlr_rx_gsup_purge_no_subscr(vlr, &gsup);
- goto msgb_free_and_return;
+ return vlr_rx_gsup_purge_no_subscr(vlr, gsup);
default:
- rc = vlr_rx_gsup_unknown_imsi(vlr, &gsup);
- goto msgb_free_and_return;
+ return vlr_rx_gsup_unknown_imsi(vlr, gsup);
}
}
- switch (gsup.message_type) {
+ switch (gsup->message_type) {
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
- rc = vlr_subscr_handle_sai_res(vsub, &gsup);
+ rc = vlr_subscr_handle_sai_res(vsub, gsup);
break;
case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
- rc = vlr_subscr_handle_isd_req(vsub, &gsup);
+ rc = vlr_subscr_handle_isd_req(vsub, gsup);
break;
case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
- rc = vlr_subscr_handle_cancel_req(vsub, &gsup);
+ rc = vlr_subscr_handle_cancel_req(vsub, gsup);
break;
case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
- rc = vlr_subscr_handle_lu_res(vsub, &gsup);
+ rc = vlr_subscr_handle_lu_res(vsub, gsup);
break;
case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
- rc = vlr_subscr_handle_lu_err(vsub, &gsup);
+ rc = vlr_subscr_handle_lu_err(vsub, gsup);
break;
case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST:
LOGVSUBP(LOGL_ERROR, vsub,
"Rx GSUP msg_type=%d not yet implemented\n",
- gsup.message_type);
+ gsup->message_type);
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
break;
case OSMO_GSUP_MSGT_CHECK_IMEI_ERROR:
case OSMO_GSUP_MSGT_CHECK_IMEI_RESULT:
- rc = vlr_subscr_handle_check_imei(vsub, &gsup);
+ rc = vlr_subscr_handle_check_imei(vsub, gsup);
break;
default:
- /* Forward message towards MSC */
- rc = vlr->ops.forward_gsup_msg(vsub, &gsup);
+ LOGP(DLGSUP, LOGL_ERROR, "GSUP Message type not handled by VLR: %d\n", gsup->message_type);
+ rc = -EINVAL;
break;
}
vlr_subscr_put(vsub, __func__);
-
-msgb_free_and_return:
- msgb_free(msg);
return rc;
}
@@ -1304,7 +1251,6 @@ struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops)
OSMO_ASSERT(ops->tx_common_id);
OSMO_ASSERT(ops->subscr_update);
OSMO_ASSERT(ops->subscr_assoc);
- OSMO_ASSERT(ops->forward_gsup_msg);
INIT_LLIST_HEAD(&vlr->subscribers);
INIT_LLIST_HEAD(&vlr->operations);
@@ -1314,7 +1260,7 @@ struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops)
vlr->cfg.assign_tmsi = true;
/* osmo_auth_fsm.c */
- osmo_fsm_register(&vlr_auth_fsm);
+ OSMO_ASSERT(osmo_fsm_register(&vlr_auth_fsm) == 0);
/* osmo_lu_fsm.c */
vlr_lu_fsm_init();
/* vlr_access_request_fsm.c */
@@ -1325,18 +1271,15 @@ struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops)
return vlr;
}
-int vlr_start(struct ipaccess_unit *ipa_dev, struct vlr_instance *vlr,
- const char *gsup_server_addr_str, uint16_t gsup_server_port)
+int vlr_start(struct vlr_instance *vlr, struct gsup_client_mux *gcm)
{
OSMO_ASSERT(vlr);
- vlr->gsup_client = osmo_gsup_client_create2(vlr, ipa_dev,
- gsup_server_addr_str,
- gsup_server_port,
- &vlr_gsupc_read_cb, NULL);
- if (!vlr->gsup_client)
- return -ENOMEM;
- vlr->gsup_client->data = vlr;
+ vlr->gcm = gcm;
+ gcm->rx_cb[OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT] = (struct gsup_client_mux_rx_cb){
+ .func = vlr_gsup_rx,
+ .data = vlr,
+ };
osmo_timer_setup(&vlr->lu_expire_timer, vlr_subscr_expire_lu, vlr);
osmo_timer_schedule(&vlr->lu_expire_timer, VLR_SUBSCRIBER_LU_EXPIRATION_INTERVAL, 0);
@@ -1383,14 +1326,13 @@ int vlr_subscr_rx_auth_resp(struct vlr_subscr *vsub, bool is_r99,
}
/* MSC->VLR: Receive result of Ciphering Mode Command from MS */
-void vlr_subscr_rx_ciph_res(struct vlr_subscr *vsub, struct vlr_ciph_result *res)
+void vlr_subscr_rx_ciph_res(struct vlr_subscr *vsub, enum vlr_ciph_result_cause result)
{
if (vsub->lu_fsm && vsub->lu_fsm->state == VLR_ULA_S_WAIT_CIPH)
- osmo_fsm_inst_dispatch(vsub->lu_fsm, VLR_ULA_E_CIPH_RES, res);
+ osmo_fsm_inst_dispatch(vsub->lu_fsm, VLR_ULA_E_CIPH_RES, &result);
if (vsub->proc_arq_fsm
&& vsub->proc_arq_fsm->state == PR_ARQ_S_WAIT_CIPH)
- osmo_fsm_inst_dispatch(vsub->proc_arq_fsm, PR_ARQ_E_CIPH_RES,
- res);
+ osmo_fsm_inst_dispatch(vsub->proc_arq_fsm, PR_ARQ_E_CIPH_RES, &result);
}
/* Internal evaluation of requested ciphering mode.