diff options
Diffstat (limited to 'src/mslookup_server.c')
-rw-r--r-- | src/mslookup_server.c | 97 |
1 files changed, 90 insertions, 7 deletions
diff --git a/src/mslookup_server.c b/src/mslookup_server.c index 9c4dc58..885adf8 100644 --- a/src/mslookup_server.c +++ b/src/mslookup_server.c @@ -27,6 +27,7 @@ #include <osmocom/hlr/db.h> #include <osmocom/hlr/timestamp.h> #include <osmocom/hlr/mslookup_server.h> +#include <osmocom/hlr/proxy.h> static const struct osmo_mslookup_result not_found = { .rc = OSMO_MSLOOKUP_RC_NOT_FOUND, @@ -294,13 +295,84 @@ static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *qu return true; } -static bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query, - uint32_t *lu_age_p, - struct osmo_ipa_name *local_msc_name) + +/* Determine whether the subscriber with the given ID has routed a Location Updating via this HLR as first hop. Return + * true if it is attached at a local VLR, and we are serving as proxy for a remote home HLR. + */ +static bool subscriber_has_done_lu_here_proxy(const struct osmo_mslookup_query *query, + uint32_t *lu_age, + struct osmo_ipa_name *local_msc_name, + struct proxy_subscr *ret_proxy_subscr) +{ + struct proxy_subscr proxy_subscr; + uint32_t age; + int rc; + + /* See the local HLR record. If the subscriber is "at home" in this HLR and is also currently located here, we + * will find a valid location updating and no vlr_via_proxy entry. */ + switch (query->id.type) { + case OSMO_MSLOOKUP_ID_IMSI: + rc = proxy_subscr_get_by_imsi(&proxy_subscr, g_hlr->gs->proxy, query->id.imsi); + break; + case OSMO_MSLOOKUP_ID_MSISDN: + rc = proxy_subscr_get_by_msisdn(&proxy_subscr, g_hlr->gs->proxy, query->id.msisdn); + break; + default: + LOGP(DDGSM, LOGL_ERROR, "%s: unknown ID type\n", + osmo_mslookup_result_name_c(OTC_SELECT, query, NULL)); + return false; + } + + if (rc) { + LOGP(DDGSM, LOGL_DEBUG, "%s: does not exist in GSUP proxy\n", + osmo_mslookup_result_name_c(OTC_SELECT, query, NULL)); + return false; + } + + /* We only need to care about CS LU, since only CS services need D-GSM routing. */ + if (!timestamp_age(&proxy_subscr.cs.last_lu, &age) + || age > g_hlr->mslookup.server.local_attach_max_age) { + LOGP(DDGSM, LOGL_ERROR, + "%s: last attach was at local VLR (proxying for remote HLR), but too long ago: %us > %us\n", + osmo_mslookup_result_name_c(OTC_SELECT, query, NULL), + age, g_hlr->mslookup.server.local_attach_max_age); + return false; + } + + if (proxy_subscr.cs.vlr_via_proxy.len) { + LOGP(DDGSM, LOGL_DEBUG, "%s: last attach is not at local VLR, but at VLR '%s' via proxy '%s'\n", + osmo_mslookup_result_name_c(OTC_SELECT, query, NULL), + osmo_ipa_name_to_str(&proxy_subscr.cs.vlr_name), + osmo_ipa_name_to_str(&proxy_subscr.cs.vlr_via_proxy)); + return false; + } + + *lu_age = age; + *local_msc_name = proxy_subscr.cs.vlr_name; + LOGP(DDGSM, LOGL_DEBUG, "%s: attached %u seconds ago at local VLR %s; proxying for remote HLR " + OSMO_SOCKADDR_STR_FMT "\n", + osmo_mslookup_result_name_c(OTC_SELECT, query, NULL), + age, osmo_ipa_name_to_str(local_msc_name), + OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr.remote_hlr_addr)); + + if (ret_proxy_subscr) + *ret_proxy_subscr = proxy_subscr; + return true; +} + +bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query, + uint32_t *lu_age_p, struct osmo_ipa_name *local_msc_name, + char *ret_imsi, size_t ret_imsi_len) { bool attached_here; uint32_t lu_age = 0; struct osmo_ipa_name msc_name = {}; + bool attached_here_proxy; + uint32_t proxy_lu_age = 0; + struct osmo_ipa_name proxy_msc_name = {}; + struct proxy_subscr proxy_subscr; + struct hlr_subscriber db_subscr; + /* First ask the local HLR db, but if the local proxy record indicates a more recent LU, use that instead. * For all usual cases, only one of these will reflect a LU, even if a subscriber had more than one home HLR: @@ -310,9 +382,20 @@ static bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query, * the local HLR database, there might occur a situation where both reflect a LU. So, to be safe against all * situations, compare the two entries. */ - attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name, NULL); - - /* Future: If proxy has a younger lu, replace. */ + attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name, &db_subscr); + attached_here_proxy = subscriber_has_done_lu_here_proxy(query, &proxy_lu_age, &proxy_msc_name, &proxy_subscr); + + /* If proxy has a younger lu, replace. */ + if (attached_here_proxy && (!attached_here || (proxy_lu_age < lu_age))) { + attached_here = true; + lu_age = proxy_lu_age; + msc_name = proxy_msc_name; + if (ret_imsi) + osmo_strlcpy(ret_imsi, proxy_subscr.imsi, ret_imsi_len); + } else if (attached_here) { + if (ret_imsi) + osmo_strlcpy(ret_imsi, db_subscr.imsi, ret_imsi_len); + } if (attached_here && !msc_name.len) { LOGP(DMSLOOKUP, LOGL_ERROR, "%s: attached here, but no VLR name known\n", @@ -349,7 +432,7 @@ void mslookup_server_rx(const struct osmo_mslookup_query *query, /* All other service types: answer when the subscriber has done a LU that is either listed in the local HLR or * in the GSUP proxy database: i.e. if the subscriber has done a Location Updating at an VLR belonging to this * HLR. Respond with whichever services are configured in the osmo-hlr.cfg. */ - if (!subscriber_has_done_lu_here(query, &age, &msc_name)) { + if (!subscriber_has_done_lu_here(query, &age, &msc_name, NULL, 0)) { *result = not_found; return; } |