aboutsummaryrefslogtreecommitdiffstats
path: root/src/mslookup_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mslookup_server.c')
-rw-r--r--src/mslookup_server.c97
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;
}