<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16209">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">implement D-GSM in osmo-hlr<br><br>Implement the mslookup server to service remote mslookup requests:<br>- VTY mslookup/server config with service names,<br>- the mslookup_mdns_server listening for mslookup requests,<br>- determine whether a subscriber is on a local MSC.<br><br>Use the mslookup client to proxy GSUP to remote HLRs:<br>- VTY mslookup/client config,<br>- remote_hlr.c to connect GSUP clients to remote GSUP servers,<br>- proxy.c as local GSUP proxy state, so far in-memory.<br>  This is kept an opaque API without a mutable struct, so that it can be easily<br>  moved to a persistent database implementation.<br><br>dgsm.c orchestrates mslookup server, client, and MUXes GSUP messages to the<br>right proxy peers.<br><br>Change-Id: Ife4a61d71926d08f310a1aeed9d9f1974f64178b<br>---<br>M include/osmocom/hlr/Makefile.am<br>A include/osmocom/hlr/dgsm.h<br>M include/osmocom/hlr/gsup_server.h<br>M include/osmocom/hlr/hlr.h<br>M include/osmocom/hlr/hlr_vty.h<br>M include/osmocom/hlr/logging.h<br>A include/osmocom/hlr/mslookup_server.h<br>A include/osmocom/hlr/mslookup_server_mdns.h<br>A include/osmocom/hlr/proxy.h<br>A include/osmocom/hlr/remote_hlr.h<br>M src/Makefile.am<br>A src/dgsm.c<br>A src/dgsm_vty.c<br>M src/gsup_server.c<br>M src/hlr.c<br>M src/hlr_vty.c<br>M src/hlr_vty_subscr.c<br>M src/logging.c<br>A src/mslookup_server.c<br>A src/mslookup_server_mdns.c<br>A src/proxy.c<br>A src/remote_hlr.c<br>M tests/test_nodes.vty<br>23 files changed, 2,697 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-hlr refs/changes/09/16209/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/hlr/Makefile.am b/include/osmocom/hlr/Makefile.am</span><br><span>index 532fa5d..38011f6 100644</span><br><span>--- a/include/osmocom/hlr/Makefile.am</span><br><span>+++ b/include/osmocom/hlr/Makefile.am</span><br><span>@@ -2,6 +2,7 @@</span><br><span>  auc.h \</span><br><span>      ctrl.h \</span><br><span>     db.h \</span><br><span style="color: hsl(120, 100%, 40%);">+        dgsm.h \</span><br><span>     gsup_router.h \</span><br><span>      gsup_server.h \</span><br><span>      hlr.h \</span><br><span>@@ -10,5 +11,9 @@</span><br><span>  hlr_vty_subscr.h \</span><br><span>   logging.h \</span><br><span>  lu_fsm.h \</span><br><span style="color: hsl(120, 100%, 40%);">+    mslookup_server.h \</span><br><span style="color: hsl(120, 100%, 40%);">+   mslookup_server_mdns.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      proxy.h \</span><br><span>    rand.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      remote_hlr.h \</span><br><span>       $(NULL)</span><br><span>diff --git a/include/osmocom/hlr/dgsm.h b/include/osmocom/hlr/dgsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..d89ace7</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/dgsm.h</span><br><span>@@ -0,0 +1,78 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/gsup_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_DGSM(imsi, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct vty;</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+struct hlr_subscriber;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern void *dgsm_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      char service[OSMO_MSLOOKUP_SERVICE_MAXLEN+1];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr_str host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr_str host_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_msc_config {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gt name;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head service_hosts;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* "Sketch pad" where the VTY can store config items without yet applying. The changes will be applied by e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+ * dgsm_mdns_server_config_apply() and dgsm_mdns_client_config_apply(). */</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_config {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Whether to listen for incoming MS Lookup requests */</span><br><span style="color: hsl(120, 100%, 40%);">+               bool enable;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      bool enable;</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_sockaddr_str bind_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+           } mdns;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             struct llist_head msc_configs;</span><br><span style="color: hsl(120, 100%, 40%);">+        } server;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Whether to ask remote HLRs via MS Lookup if an IMSI is not known locally. */</span><br><span style="color: hsl(120, 100%, 40%);">+               bool enable;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct timeval timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Whether to use mDNS for IMSI MS Lookup */</span><br><span style="color: hsl(120, 100%, 40%);">+                  bool enable;</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_sockaddr_str query_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+          } mdns;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_sockaddr_str gateway_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+       } client;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *dgsm_config_service_get(const struct osmo_gt *msc_name, const char *service);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *dgsm_config_msc_service_get(struct dgsm_msc_config *msc, const char *service, bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+int dgsm_config_msc_service_set(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+int dgsm_config_msc_service_del(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct osmo_gt dgsm_config_msc_wildcard;</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_msc_config *dgsm_config_msc_get(const struct osmo_gt *msc_name, bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_init(void *ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_start(void *ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_config_apply(const struct dgsm_config *c);</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_stop();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool dgsm_check_forward_gsup_msg(struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_vty_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool hlr_subscr_lu_age(const struct hlr_subscriber *subscr, uint32_t *age_p);</span><br><span>diff --git a/include/osmocom/hlr/gsup_server.h b/include/osmocom/hlr/gsup_server.h</span><br><span>index c3efea2..7002da0 100644</span><br><span>--- a/include/osmocom/hlr/gsup_server.h</span><br><span>+++ b/include/osmocom/hlr/gsup_server.h</span><br><span>@@ -27,6 +27,9 @@</span><br><span>         struct ipa_server_link *link;</span><br><span>        osmo_gsup_read_cb_t read_cb;</span><br><span>         struct llist_head routes;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Proxy requests from this server's clients to remote GSUP servers. */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy *proxy;</span><br><span> };</span><br><span> </span><br><span> </span><br><span>diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h</span><br><span>index 2214a8b..f9d7450 100644</span><br><span>--- a/include/osmocom/hlr/hlr.h</span><br><span>+++ b/include/osmocom/hlr/hlr.h</span><br><span>@@ -27,6 +27,8 @@</span><br><span> #include <osmocom/gsm/ipa.h></span><br><span> #include <osmocom/core/tdef.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define HLR_DEFAULT_DB_FILE_PATH "hlr.db"</span><br><span> </span><br><span> struct hlr_euse;</span><br><span>@@ -68,6 +70,22 @@</span><br><span>         /* Bitmask of DB_SUBSCR_FLAG_* */</span><br><span>    uint8_t subscr_create_on_demand_flags;</span><br><span>       unsigned int subscr_create_on_demand_rand_msisdn_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              bool allow_startup;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct dgsm_config vty;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct osmo_mslookup_server_mdns *mdns;</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint32_t max_age;</span><br><span style="color: hsl(120, 100%, 40%);">+             } server;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      unsigned int result_timeout_milliseconds;</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_mslookup_client *client;</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct osmo_mslookup_client_method *mdns;</span><br><span style="color: hsl(120, 100%, 40%);">+             } client;</span><br><span style="color: hsl(120, 100%, 40%);">+     } mslookup;</span><br><span> };</span><br><span> </span><br><span> extern struct hlr *g_hlr;</span><br><span>diff --git a/include/osmocom/hlr/hlr_vty.h b/include/osmocom/hlr/hlr_vty.h</span><br><span>index acd6510..1b9b59e 100644</span><br><span>--- a/include/osmocom/hlr/hlr_vty.h</span><br><span>+++ b/include/osmocom/hlr/hlr_vty.h</span><br><span>@@ -31,6 +31,10 @@</span><br><span>     HLR_NODE = _LAST_OSMOVTY_NODE + 1,</span><br><span>   GSUP_NODE,</span><br><span>   EUSE_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+    MSLOOKUP_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+        MSLOOKUP_SERVER_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+ MSLOOKUP_SERVER_MSC_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+     MSLOOKUP_CLIENT_NODE,</span><br><span> };</span><br><span> </span><br><span> int hlr_vty_is_config_node(struct vty *vty, int node);</span><br><span>diff --git a/include/osmocom/hlr/logging.h b/include/osmocom/hlr/logging.h</span><br><span>index 4e0a25c..a8081af 100644</span><br><span>--- a/include/osmocom/hlr/logging.h</span><br><span>+++ b/include/osmocom/hlr/logging.h</span><br><span>@@ -10,6 +10,7 @@</span><br><span>       DSS,</span><br><span>         DMSLOOKUP,</span><br><span>   DLU,</span><br><span style="color: hsl(120, 100%, 40%);">+  DDGSM,</span><br><span> };</span><br><span> </span><br><span> extern const struct log_info hlr_log_info;</span><br><span>diff --git a/include/osmocom/hlr/mslookup_server.h b/include/osmocom/hlr/mslookup_server.h</span><br><span>new file mode 100644</span><br><span>index 0000000..68a8695</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/mslookup_server.h</span><br><span>@@ -0,0 +1,8 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_query;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct osmo_mslookup_result *result);</span><br><span>diff --git a/include/osmocom/hlr/mslookup_server_mdns.h b/include/osmocom/hlr/mslookup_server_mdns.h</span><br><span>new file mode 100644</span><br><span>index 0000000..8d4d4fc</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/mslookup_server_mdns.h</span><br><span>@@ -0,0 +1,14 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mdns_sock.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_server_mdns {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_mslookup_server *mslookup;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sockaddr_str bind_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_mdns_sock *sock;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server);</span><br><span>diff --git a/include/osmocom/hlr/proxy.h b/include/osmocom/hlr/proxy.h</span><br><span>new file mode 100644</span><br><span>index 0000000..1aaee81</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/proxy.h</span><br><span>@@ -0,0 +1,86 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <time.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_req;</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+typedef time_t timestamp_t;</span><br><span style="color: hsl(120, 100%, 40%);">+void timestamp_update(timestamp_t *timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+bool timestamp_age(const timestamp_t *timestamp, uint32_t *age);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy_pending_gsup_req {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_req *req;</span><br><span style="color: hsl(120, 100%, 40%);">+    timestamp_t received_at;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head subscr_list;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head pending_gsup_reqs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* When messages arrive back from a remote HLR that this is the proxy for, reach the VLR to forward the response</span><br><span style="color: hsl(120, 100%, 40%);">+       * to via this osmo_gsup_server. */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_server *gsup_server_to_vlr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* How long to keep proxy entries without a refresh, in seconds. */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t fresh_time;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* How often to garbage collect the proxy cache, period in seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+    * To change this and take effect immediately, rather use proxy_set_gc_period(). */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t gc_period;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list gc_timer;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy_subscr_domain_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gt vlr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_t last_lu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The name from which an Update Location Request was received. Copied to vlr_name as soon as the LU is</span><br><span style="color: hsl(120, 100%, 40%);">+        * completed successfully. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_gt vlr_name_preliminary;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Set if this is a middle proxy, i.e. a proxy behind another proxy.</span><br><span style="color: hsl(120, 100%, 40%);">+   * That is mostly to know whether the MS is attached at a local MSC/SGSN or further away.</span><br><span style="color: hsl(120, 100%, 40%);">+      * It could be a boolean, but store the full name for logging. Set only at successful LU acceptance. */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_gt vlr_via_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy_subscr {</span><br><span style="color: hsl(120, 100%, 40%);">+    char imsi[GSM23003_IMSI_MAX_DIGITS+1];</span><br><span style="color: hsl(120, 100%, 40%);">+        char msisdn[GSM23003_MSISDN_MAX_DIGITS+1];</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_sockaddr_str remote_hlr_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct proxy_subscr_domain_state cs, ps;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_init(struct osmo_gsup_server *gsup_server_to_vlr);</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_del(struct proxy *proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* The API to access / modify proxy entries keeps the implementation opaque, to make sure that we can easily move proxy</span><br><span style="color: hsl(120, 100%, 40%);">+ * storage to SQLite db. */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscrs_get_by_remote_hlr(struct proxy *proxy, const struct osmo_sockaddr_str *remote_hlr_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  bool (*yield)(struct proxy *proxy, const struct proxy_subscr *subscr, void *data),</span><br><span style="color: hsl(120, 100%, 40%);">+                                    void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_del(struct proxy *proxy, const char *imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_forward_to_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            struct remote_hlr *remote_hlr, struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_forward_to_vlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                          const struct osmo_gsup_message *gsup, struct remote_hlr *from_remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   struct remote_hlr *remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_remote_hlr_up(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct remote_hlr *remote_hlr);</span><br><span>diff --git a/include/osmocom/hlr/remote_hlr.h b/include/osmocom/hlr/remote_hlr.h</span><br><span>new file mode 100644</span><br><span>index 0000000..bfa3d95</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/remote_hlr.h</span><br><span>@@ -0,0 +1,29 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_client;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_message;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_req;</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_REMOTE_HLR(remote_hlr, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DDGSM, level, "(Proxy HLR-" OSMO_SOCKADDR_STR_FMT ") " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+             OSMO_SOCKADDR_STR_FMT_ARGS((remote_hlr) ? &(remote_hlr)->addr : NULL), ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_REMOTE_HLR_MSG(remote_hlr, gsup_msg, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_REMOTE_HLR(remote_hlr, level, "%s: " fmt, osmo_gsup_message_type_name((gsup_msg)->message_type), ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* GSUP client link for proxying to a remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gsup_client *gsupc;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create);</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_destroy(struct remote_hlr *remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req);</span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index 3a83616..5113aa4 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -9,6 +9,7 @@</span><br><span>  $(LIBOSMOGSM_CFLAGS) \</span><br><span>       $(LIBOSMOVTY_CFLAGS) \</span><br><span>       $(LIBOSMOCTRL_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOMSLOOKUP_CFLAGS) \</span><br><span>  $(LIBOSMOABIS_CFLAGS) \</span><br><span>      $(SQLITE3_CFLAGS) \</span><br><span>  $(NULL)</span><br><span>@@ -52,15 +53,23 @@</span><br><span>        hlr_vty_subscr.c \</span><br><span>   gsup_send.c \</span><br><span>        hlr_ussd.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  proxy.c \</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      dgsm_vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  remote_hlr.c \</span><br><span style="color: hsl(120, 100%, 40%);">+        mslookup_server.c \</span><br><span style="color: hsl(120, 100%, 40%);">+   mslookup_server_mdns.c \</span><br><span>     lu_fsm.c \</span><br><span>   $(NULL)</span><br><span> </span><br><span> osmo_hlr_LDADD = \</span><br><span>    $(top_builddir)/src/gsupclient/libosmo-gsup-client.la \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(top_builddir)/src/mslookup/libosmo-mslookup.la \</span><br><span>   $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOVTY_LIBS) \</span><br><span>         $(LIBOSMOCTRL_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOMSLOOKUP_LIBS) \</span><br><span>    $(LIBOSMOABIS_LIBS) \</span><br><span>        $(SQLITE3_LIBS) \</span><br><span>    $(NULL)</span><br><span>diff --git a/src/dgsm.c b/src/dgsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..9856188</span><br><span>--- /dev/null</span><br><span>+++ b/src/dgsm.c</span><br><span>@@ -0,0 +1,402 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup_client_mdns.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/gsup_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_router.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/remote_hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server_mdns.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *dgsm_ctx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_gt dgsm_config_msc_wildcard = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_msc_config *dgsm_config_msc_get(const struct osmo_gt *msc_name, bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_msc_config *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(msc, &c->server.msc_configs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (osmo_gt_cmp(&msc->name, msc_name))</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             return msc;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!create)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msc = talloc_zero(dgsm_ctx, struct dgsm_msc_config);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(msc);</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&msc->service_hosts);</span><br><span style="color: hsl(120, 100%, 40%);">+  msc->name = *msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&msc->entry, &c->server.msc_configs);</span><br><span style="color: hsl(120, 100%, 40%);">+    return msc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *dgsm_config_msc_service_get(struct dgsm_msc_config *msc, const char *service, bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct dgsm_service_host *e;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(e, &msc->service_hosts, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!strcmp(e->service, service))</span><br><span style="color: hsl(120, 100%, 40%);">+                  return e;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!create)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        e = talloc_zero(msc, struct dgsm_service_host);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(e);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_STRLCPY_ARRAY(e->service, service);</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add_tail(&e->entry, &msc->service_hosts);</span><br><span style="color: hsl(120, 100%, 40%);">+ return e;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *dgsm_config_service_get(const struct osmo_gt *msc_name, const char *service)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct dgsm_msc_config *msc = dgsm_config_msc_get(msc_name, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return dgsm_config_msc_service_get(msc, service, false);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int dgsm_config_msc_service_set(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct dgsm_service_host *e;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!service || !service[0]</span><br><span style="color: hsl(120, 100%, 40%);">+       || strlen(service) > OSMO_MSLOOKUP_SERVICE_MAXLEN)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!addr || !osmo_sockaddr_str_is_nonzero(addr))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     e = dgsm_config_msc_service_get(msc, service, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (addr->af) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+         e->host_v4 = *addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->host_v6 = *addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int dgsm_config_msc_service_del(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct dgsm_service_host *e, *n;</span><br><span style="color: hsl(120, 100%, 40%);">+      int deleted = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msc)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOENT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry_safe(e, n, &msc->service_hosts, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (service && strcmp(service, e->service))</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (addr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!osmo_sockaddr_str_cmp(addr, &e->host_v4)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               e->host_v4 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* Removed one addr. If the other is still there, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (osmo_sockaddr_str_is_nonzero(&e->host_v6))</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (!osmo_sockaddr_str_cmp(addr, &e->host_v6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                e->host_v6 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* Removed one addr. If the other is still there, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (osmo_sockaddr_str_is_nonzero(&e->host_v4))</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else</span><br><span style="color: hsl(120, 100%, 40%);">+                                /* No addr match, keep the entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Addr matched and none is left. Delete. */</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_del(&e->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(e);</span><br><span style="color: hsl(120, 100%, 40%);">+               deleted++;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return deleted;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void resolve_hlr_result_cb(struct osmo_mslookup_client *client,</span><br><span style="color: hsl(120, 100%, 40%);">+                            uint32_t request_handle,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct proxy *proxy = g_hlr->gs->proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct proxy_subscr *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct osmo_sockaddr_str *use_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct remote_hlr *remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* A remote HLR is answering back, indicating that it is the home HLR for a given IMSI.</span><br><span style="color: hsl(120, 100%, 40%);">+        * There should be a mostly empty proxy entry for that IMSI.</span><br><span style="color: hsl(120, 100%, 40%);">+   * Add the remote address data in the proxy. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (query->id.type != OSMO_MSLOOKUP_ID_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DDGSM, LOGL_ERROR, "Expected IMSI ID type in mslookup query+result: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to resolve remote HLR: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_subscr_del(proxy, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_sockaddr_str_is_nonzero(&result->host_v4))</span><br><span style="color: hsl(120, 100%, 40%);">+            use_addr = &result->host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+   else if (osmo_sockaddr_str_is_nonzero(&result->host_v6))</span><br><span style="color: hsl(120, 100%, 40%);">+               use_addr = &result->host_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+   else {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_DGSM(query->id.imsi, LOGL_ERROR, "Invalid address for remote HLR: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_subscr_del(proxy, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   remote_hlr = remote_hlr_get(use_addr, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!remote_hlr) {</span><br><span style="color: hsl(120, 100%, 40%);">+            proxy_subscr_del(proxy, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   proxy_subscr = proxy_subscr_get_by_imsi(proxy, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!proxy_subscr) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_DGSM(query->id.imsi, LOGL_ERROR, "No proxy entry for mslookup result: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* The remote HLR already exists and is connected. Messages for this IMSI were spooled because we did not know</span><br><span style="color: hsl(120, 100%, 40%);">+         * which remote HLR was responsible. Now we know, send this IMSI's messages now. */</span><br><span style="color: hsl(120, 100%, 40%);">+       LOG_DGSM(query->id.imsi, LOGL_DEBUG, "Resolved remote HLR, sending spooled GSUP messages: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_mslookup_result_name_c(OTC_SELECT, query, result));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   proxy_subscr_remote_hlr_resolved(proxy, proxy_subscr, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_REMOTE_HLR(remote_hlr, LOGL_DEBUG, "Waiting for link-up\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_subscr_remote_hlr_up(proxy, proxy_subscr, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Return true when the message has been handled by D-GSM. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool dgsm_check_forward_gsup_msg(struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct proxy_subscr *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct proxy_subscr proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct proxy *proxy = g_hlr->gs->proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_mslookup_query query;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mslookup_query_handling handling;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t request_handle;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* If the IMSI is known in the local HLR, then we won't proxy. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Are we already forwarding this IMSI to a remote HLR? */</span><br><span style="color: hsl(120, 100%, 40%);">+    proxy_subscr = proxy_subscr_get_by_imsi(proxy, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (proxy_subscr)</span><br><span style="color: hsl(120, 100%, 40%);">+             goto yes_we_are_proxying;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* The IMSI is not known locally, so we want to proxy to a remote HLR, but no proxy entry exists yet. We need to</span><br><span style="color: hsl(120, 100%, 40%);">+       * look up the subscriber in remote HLRs via D-GSM mslookup, forward GSUP and reply once a result is back from</span><br><span style="color: hsl(120, 100%, 40%);">+         * there.  Defer message and kick off MS lookup. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add a proxy entry without a remote address to indicate that we are busy querying for a remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+      proxy_subscr_new = (struct proxy_subscr){};</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_STRLCPY_ARRAY(proxy_subscr_new.imsi, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy_subscr = &proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (proxy_subscr_update(proxy, proxy_subscr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Failed to create proxy entry\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Is a fixed gateway proxy configured? */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.vty.client.gateway_proxy)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct remote_hlr *gateway_proxy = remote_hlr_get(&g_hlr->mslookup.vty.client.gateway_proxy, true);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!gateway_proxy) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_DGSM(req->gsup.imsi, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                "Failed to set up fixed gateway proxy " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.vty.client.gateway_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+                       return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           proxy_subscr_remote_hlr_resolved(proxy, proxy_subscr, gateway_proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Update info */</span><br><span style="color: hsl(120, 100%, 40%);">+             proxy_subscr = proxy_subscr_get_by_imsi(proxy, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!proxy_subscr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Proxy entry disappeared\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto yes_we_are_proxying;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Kick off an mslookup for the remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!g_hlr->mslookup.client.client) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_GSUP_REQ(req, LOGL_DEBUG, "mslookup client not running, cannot query remote home HLR\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   query = (struct osmo_mslookup_query){</span><br><span style="color: hsl(120, 100%, 40%);">+         .id = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .type = OSMO_MSLOOKUP_ID_IMSI,</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_STRLCPY_ARRAY(query.id.imsi, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_STRLCPY_ARRAY(query.service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);</span><br><span style="color: hsl(120, 100%, 40%);">+    handling = (struct osmo_mslookup_query_handling){</span><br><span style="color: hsl(120, 100%, 40%);">+             .min_delay_milliseconds = g_hlr->mslookup.client.result_timeout_milliseconds,</span><br><span style="color: hsl(120, 100%, 40%);">+              .result_cb = resolve_hlr_result_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+    request_handle = osmo_mslookup_client_request(g_hlr->mslookup.client.client, &query, &handling);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!request_handle) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Error dispatching mslookup query for home HLR: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+          proxy_subscr_del(proxy, req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+yes_we_are_proxying:</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(proxy_subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* If the remote HLR is already known, directly forward the GSUP message; otherwise, spool the GSUP message</span><br><span style="color: hsl(120, 100%, 40%);">+    * until the remote HLR will respond / until timeout aborts. */</span><br><span style="color: hsl(120, 100%, 40%);">+       proxy_subscr_forward_to_remote_hlr(proxy, proxy_subscr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_init(void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");</span><br><span style="color: hsl(120, 100%, 40%);">+      INIT_LLIST_HEAD(&c->server.msc_configs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     g_hlr->mslookup.server.max_age = 60 * 60;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        g_hlr->mslookup.client.result_timeout_milliseconds = 2000;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       g_hlr->gsup_unit_name.unit_name = "HLR";</span><br><span style="color: hsl(120, 100%, 40%);">+ g_hlr->gsup_unit_name.serno = "unnamed-HLR";</span><br><span style="color: hsl(120, 100%, 40%);">+     g_hlr->gsup_unit_name.swversion = PACKAGE_NAME "-" PACKAGE_VERSION;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_sockaddr_str_from_str(&c->server.mdns.bind_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                             OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_sockaddr_str_from_str(&c->client.mdns.query_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                            OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_start(void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      g_hlr->mslookup.client.client = osmo_mslookup_client_new(dgsm_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(g_hlr->mslookup.client.client);</span><br><span style="color: hsl(120, 100%, 40%);">+        g_hlr->mslookup.allow_startup = true;</span><br><span style="color: hsl(120, 100%, 40%);">+      dgsm_config_apply(&g_hlr->mslookup.vty);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_stop()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct dgsm_config disabled = {};</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm_config_apply(&disabled);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void dgsm_mdns_server_config_apply(const struct dgsm_config *c)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check whether to start/stop/restart mDNS server */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool should_run;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool should_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!g_hlr->mslookup.allow_startup)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     should_run = c->server.enable && c->server.mdns.enable;</span><br><span style="color: hsl(120, 100%, 40%);">+ should_stop = g_hlr->mslookup.server.mdns</span><br><span style="color: hsl(120, 100%, 40%);">+          && (!should_run</span><br><span style="color: hsl(120, 100%, 40%);">+                   || osmo_sockaddr_str_cmp(&c->server.mdns.bind_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             &g_hlr->mslookup.server.mdns->bind_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (should_stop) {</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_mslookup_server_mdns_stop(g_hlr->mslookup.server.mdns);</span><br><span style="color: hsl(120, 100%, 40%);">+               g_hlr->mslookup.server.mdns = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DDGSM, LOGL_NOTICE, "Stopped mslookup mDNS server\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (should_run && !g_hlr->mslookup.server.mdns) {</span><br><span style="color: hsl(120, 100%, 40%);">+          g_hlr->mslookup.server.mdns =</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_mslookup_server_mdns_start(g_hlr, &c->server.mdns.bind_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!g_hlr->mslookup.server.mdns)</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DDGSM, LOGL_ERROR, "Failed to start mslookup mDNS server on " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns->bind_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DDGSM, LOGL_NOTICE, "Started mslookup mDNS server, receiving mDNS requests at multicast "</span><br><span style="color: hsl(120, 100%, 40%);">+                           OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns->bind_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void dgsm_mdns_client_config_apply(const struct dgsm_config *c)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!g_hlr->mslookup.allow_startup)</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check whether to start/stop/restart mDNS client */</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct osmo_sockaddr_str *current_bind_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+    current_bind_addr = osmo_mslookup_client_method_mdns_get_bind_addr(g_hlr->mslookup.client.mdns);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bool should_run = c->client.enable && c->client.mdns.enable;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool should_stop = g_hlr->mslookup.client.mdns &&</span><br><span style="color: hsl(120, 100%, 40%);">+          (!should_run</span><br><span style="color: hsl(120, 100%, 40%);">+           || osmo_sockaddr_str_cmp(&c->client.mdns.query_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    current_bind_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (should_stop) {</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_mslookup_client_method_del(g_hlr->mslookup.client.client, g_hlr->mslookup.client.mdns);</span><br><span style="color: hsl(120, 100%, 40%);">+            g_hlr->mslookup.client.mdns = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DDGSM, LOGL_NOTICE, "Stopped mslookup mDNS client\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (should_run && !g_hlr->mslookup.client.mdns) {</span><br><span style="color: hsl(120, 100%, 40%);">+          g_hlr->mslookup.client.mdns =</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_mslookup_client_add_mdns(g_hlr->mslookup.client.client,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     c->client.mdns.query_addr.ip,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      c->client.mdns.query_addr.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    -1);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!g_hlr->mslookup.client.mdns)</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DDGSM, LOGL_ERROR, "Failed to start mslookup mDNS client with target "</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         OSMO_SOCKADDR_STR_FMT_ARGS(&c->client.mdns.query_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DDGSM, LOGL_NOTICE, "Started mslookup mDNS client, sending mDNS requests to multicast " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       OSMO_SOCKADDR_STR_FMT_ARGS(&c->client.mdns.query_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (c->client.enable && osmo_sockaddr_str_is_nonzero(&c->client.gateway_proxy))</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGP(DDGSM, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "mslookup client: all GSUP requests for unknown IMSIs will be forwarded to"</span><br><span style="color: hsl(120, 100%, 40%);">+                         " gateway-proxy " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             OSMO_SOCKADDR_STR_FMT_ARGS(&c->client.gateway_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_config_apply(const struct dgsm_config *c)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       dgsm_mdns_server_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm_mdns_client_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/dgsm_vty.c b/src/dgsm_vty.c</span><br><span>new file mode 100644</span><br><span>index 0000000..83c31a2</span><br><span>--- /dev/null</span><br><span>+++ b/src/dgsm_vty.c</span><br><span>@@ -0,0 +1,515 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/command.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup_client_mdns.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr_vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct cmd_node mslookup_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+        MSLOOKUP_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+        "%s(config-mslookup)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+    1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "mslookup",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure Distributed GSM mslookup")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->node = MSLOOKUP_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int mslookup_server_mdns_bind(struct vty *vty, int argc, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *ip_str = argc > 0? argv[0] : c->server.mdns.bind_addr.ip;</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *port_str = argc > 1? argv[1] : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t port_nr = port_str ? atoi(port_str) : c->server.mdns.bind_addr.port;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_sockaddr_str_from_str(&addr, ip_str, port_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+        || !osmo_sockaddr_str_is_nonzero(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup server: Invalid mDNS bind address: %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip_str, port_nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   c->server.mdns.bind_addr = addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   c->server.mdns.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+      c->server.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+   dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int mslookup_client_mdns_to(struct vty *vty, int argc, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *ip_str = argc > 0? argv[0] : c->client.mdns.query_addr.ip;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *port_str = argc > 1? argv[1] : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t port_nr = port_str ? atoi(port_str) : c->client.mdns.query_addr.port;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_sockaddr_str_from_str(&addr, ip_str, port_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+        || !osmo_sockaddr_str_is_nonzero(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup client: Invalid mDNS target address: %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ip_str, port_nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   c->client.mdns.query_addr = addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->client.mdns.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+      c->client.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+   dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define MDNS_IP46_STR "multicast IPv4 address like " OSMO_MSLOOKUP_MDNS_IP4 \</span><br><span style="color: hsl(120, 100%, 40%);">+                     " or IPv6 address like " OSMO_MSLOOKUP_MDNS_IP6 "\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define MDNS_PORT_STR "mDNS UDP Port number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define IP46_STR "IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define PORT_STR "Service-specific port number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_mdns,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_mdns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "mdns [IP] [<1-65535>]",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Convenience shortcut: enable and configure both server and client for mDNS mslookup\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      MDNS_IP46_STR MDNS_PORT_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc1 = mslookup_server_mdns_bind(vty, argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc2 = mslookup_client_mdns_to(vty, argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc1 != CMD_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+               return rc1;</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc2;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_no_mdns,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_no_mdns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no mdns",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable both server and client for mDNS mslookup\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->server.mdns.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     c->client.mdns.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct cmd_node mslookup_server_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+    MSLOOKUP_SERVER_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s(config-mslookup-server)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+     1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "server",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Enable and configure Distributed GSM mslookup server")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  vty->node = MSLOOKUP_SERVER_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->server.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+   dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_no_server,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_no_server_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no server",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable Distributed GSM mslookup server")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->server.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+  dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_mdns_bind,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_mdns_bind_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "mdns [IP] [<1-65535>]",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure where the mDNS server listens for mslookup requests\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      MDNS_IP46_STR MDNS_PORT_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return mslookup_server_mdns_bind(vty, argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_no_mdns,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_no_mdns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no mdns",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable server for mDNS mslookup (do not answer remote requests)\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->server.mdns.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct cmd_node mslookup_server_msc_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+        MSLOOKUP_SERVER_MSC_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+     "%s(config-mslookup-server-msc)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+ 1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_msc,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "msc .UNIT_NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure services for individual local MSCs\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "IPA Unit Name of the local MSC to configure\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gt msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct dgsm_msc_config *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_gt_set_str(&msc_name, argv_concat(argv, argc, 0));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msc = dgsm_config_msc_get(&msc_name, true);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error creating MSC %s%s", osmo_gt_name(&msc_name), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     vty->node = MSLOOKUP_SERVER_MSC_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+      vty->index = msc;</span><br><span style="color: hsl(120, 100%, 40%);">+  return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SERVICE_NAME_STR \</span><br><span style="color: hsl(120, 100%, 40%);">+  "mslookup service name, e.g. " OSMO_MSLOOKUP_SERVICE_SIP " or " OSMO_MSLOOKUP_SERVICE_SMPP "\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct dgsm_msc_config *msc_from_node(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (vty->node) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case MSLOOKUP_SERVER_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* On the mslookup.server node, set services on the wildcard msc, without a particular name. */</span><br><span style="color: hsl(120, 100%, 40%);">+               return dgsm_config_msc_get(&dgsm_config_msc_wildcard, true);</span><br><span style="color: hsl(120, 100%, 40%);">+      case MSLOOKUP_SERVER_MSC_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+                return vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_msc_service,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_msc_service_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "service NAME at IP <1-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure addresses of local services, as sent in replies to remote mslookup requests.\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      SERVICE_NAME_STR "at\n" IP46_STR PORT_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  /* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all</span><br><span style="color: hsl(120, 100%, 40%);">+  * MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_msc_config *msc = msc_from_node(vty);</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *service = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *ip_str = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *port_str = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: no MSC object on this node%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_sockaddr_str_from_str(&addr, ip_str, atoi(port_str))</span><br><span style="color: hsl(120, 100%, 40%);">+         || !osmo_sockaddr_str_is_nonzero(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup server: Invalid address for service %s: %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 service, ip_str, port_str, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (dgsm_config_msc_service_set(msc, service, &addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% mslookup server: Error setting service %s to %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     service, ip_str, port_str, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NO_SERVICE_AND_NAME_STR NO_STR "Remove one or more service address entries\n" SERVICE_NAME_STR</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_msc_no_service,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_msc_no_service_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no service NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_SERVICE_AND_NAME_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all</span><br><span style="color: hsl(120, 100%, 40%);">+  * MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_msc_config *msc = msc_from_node(vty);</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *service = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: no MSC object on this node%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (dgsm_config_msc_service_del(msc, service, NULL) < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%% mslookup server: cannot remove service '%s'%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    service, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_server_msc_no_service_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_server_msc_no_service_addr_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no service NAME at IP <1-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_SERVICE_AND_NAME_STR "at\n" IP46_STR PORT_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  /* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all</span><br><span style="color: hsl(120, 100%, 40%);">+  * MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_msc_config *msc = msc_from_node(vty);</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *service = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *ip_str = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *port_str = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: no MSC object on this node%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_sockaddr_str_from_str(&addr, ip_str, atoi(port_str))</span><br><span style="color: hsl(120, 100%, 40%);">+         || !osmo_sockaddr_str_is_nonzero(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup server: Invalid address for 'no service' %s: %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    service, ip_str, port_str, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (dgsm_config_msc_service_del(msc, service, &addr) < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup server: cannot remove service '%s' to %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                   service, ip_str, port_str, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct cmd_node mslookup_client_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+    MSLOOKUP_CLIENT_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s(config-mslookup-client)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+     1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "client",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Enable and configure Distributed GSM mslookup client")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  vty->node = MSLOOKUP_CLIENT_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->client.enable = true;</span><br><span style="color: hsl(120, 100%, 40%);">+   dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_no_client,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_no_client_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no client",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable Distributed GSM mslookup client")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->client.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+  dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client_timeout,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_timeout_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "timeout <1-100000>",</span><br><span style="color: hsl(120, 100%, 40%);">+      "How long should the mslookup client wait for remote responses before evaluating received results\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "timeout in milliseconds\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t val = atol(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ c->client.timeout.tv_sec = val / 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+     c->client.timeout.tv_usec = (val % 1000) * 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define EXIT_HINT() \</span><br><span style="color: hsl(120, 100%, 40%);">+       if (vty->type != VTY_FILE) \</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% 'exit' this node to apply changes%s", VTY_NEWLINE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client_mdns,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_mdns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "mdns [IP] [<1-65535>]",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Enable mDNS client, and configure multicast address to send mDNS mslookup requests to\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      MDNS_IP46_STR MDNS_PORT_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return mslookup_client_mdns_to(vty, argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client_no_mdns,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_no_mdns_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no mdns",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable mDNS client, do not query remote services by mDNS\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->client.mdns.enable = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     dgsm_config_apply(c);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void config_write_msc_services(struct vty *vty, const char *indent, struct dgsm_msc_config *msc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_service_host *e;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(e, &msc->service_hosts, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (osmo_sockaddr_str_is_nonzero(&e->host_v4))</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, "%sservice %s at %s %u%s", indent, e->service, e->host_v4.ip, e->host_v4.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (osmo_sockaddr_str_is_nonzero(&e->host_v6))</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, "%sservice %s at %s %u%s", indent, e->service, e->host_v6.ip, e->host_v6.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int config_write_mslookup(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!c->server.enable && !c->client.enable</span><br><span style="color: hsl(120, 100%, 40%);">+          && llist_empty(&c->server.msc_configs))</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "mslookup%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (c->server.enable || !llist_empty(&c->server.msc_configs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct dgsm_msc_config *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, " server%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (c->server.mdns.enable</span><br><span style="color: hsl(120, 100%, 40%);">+              && osmo_sockaddr_str_is_nonzero(&c->server.mdns.bind_addr))</span><br><span style="color: hsl(120, 100%, 40%);">+                        vty_out(vty, "  mdns bind %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                         c->server.mdns.bind_addr.ip,</span><br><span style="color: hsl(120, 100%, 40%);">+                               c->server.mdns.bind_addr.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                             VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               msc = dgsm_config_msc_get(&dgsm_config_msc_wildcard, false);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (msc)</span><br><span style="color: hsl(120, 100%, 40%);">+                      config_write_msc_services(vty, " ", msc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         llist_for_each_entry(msc, &c->server.msc_configs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!osmo_gt_cmp(&dgsm_config_msc_wildcard, &msc->name))</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     vty_out(vty, " msc %s%s", osmo_gt_name(&msc->name), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                    config_write_msc_services(vty, "  ", msc);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* If the server is disabled, still output the above to not lose the service config. */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!c->server.enable)</span><br><span style="color: hsl(120, 100%, 40%);">+                     vty_out(vty, " no server%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (c->client.enable) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, " client%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (osmo_sockaddr_str_is_nonzero(&c->client.gateway_proxy))</span><br><span style="color: hsl(120, 100%, 40%);">+                    vty_out(vty, "  gateway-proxy %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             c->client.gateway_proxy.ip,</span><br><span style="color: hsl(120, 100%, 40%);">+                                c->client.gateway_proxy.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                              VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (c->client.mdns.enable</span><br><span style="color: hsl(120, 100%, 40%);">+              && osmo_sockaddr_str_is_nonzero(&c->client.mdns.query_addr))</span><br><span style="color: hsl(120, 100%, 40%);">+                       vty_out(vty, "  mdns to %s %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                           c->client.mdns.query_addr.ip,</span><br><span style="color: hsl(120, 100%, 40%);">+                              c->client.mdns.query_addr.port,</span><br><span style="color: hsl(120, 100%, 40%);">+                            VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client_gateway_proxy,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_gateway_proxy_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "gateway-proxy IP [<1-65535>]",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure a fixed IP address to send all GSUP requests for unknown IMSIs to, without invoking a lookup for IMSI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "IP address of the remote HLR\n" "GSUP port number (omit for default " OSMO_STRINGIFY_VAL(OSMO_GSUP_PORT) ")\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *ip_str = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *port_str = argc > 1 ? argv[1] : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_sockaddr_str addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (osmo_sockaddr_str_from_str(&addr, ip_str, port_str ? atoi(port_str) : OSMO_GSUP_PORT)</span><br><span style="color: hsl(120, 100%, 40%);">+     || !osmo_sockaddr_str_is_nonzero(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% mslookup client: Invalid address for gateway-proxy: %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ip_str, port_str ? : "", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   c->client.gateway_proxy = addr;</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mslookup_client_no_gateway_proxy,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_mslookup_client_no_gateway_proxy_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "no gateway-proxy",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Disable gateway proxy for GSUP with unknown IMSIs\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  c->client.gateway_proxy = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(do_mslookup_show_services,</span><br><span style="color: hsl(120, 100%, 40%);">+      do_mslookup_show_services_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "show mslookup services",</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Distributed GSM / mslookup related information\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "List configured service addresses as sent to remote mslookup requests\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_config *c = &g_hlr->mslookup.vty;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_msc_config *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct dgsm_service_host *local_hlr = mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        vty_out(vty, "Local GSUP HLR address returned in mslookup responses for local IMSIs:");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_sockaddr_str_is_nonzero(&local_hlr->host_v4))</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, " " OSMO_SOCKADDR_STR_FMT,</span><br><span style="color: hsl(120, 100%, 40%);">+                     OSMO_SOCKADDR_STR_FMT_ARGS(&local_hlr->host_v4));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (osmo_sockaddr_str_is_nonzero(&local_hlr->host_v6))</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, " " OSMO_SOCKADDR_STR_FMT,</span><br><span style="color: hsl(120, 100%, 40%);">+                     OSMO_SOCKADDR_STR_FMT_ARGS(&local_hlr->host_v6));</span><br><span style="color: hsl(120, 100%, 40%);">+      vty_out(vty, "%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msc = dgsm_config_msc_get(&dgsm_config_msc_wildcard, false);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (msc)</span><br><span style="color: hsl(120, 100%, 40%);">+              config_write_msc_services(vty, "", msc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(msc, &c->server.msc_configs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!osmo_gt_cmp(&dgsm_config_msc_wildcard, &msc->name))</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "msc %s%s", osmo_gt_name(&msc->name), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             config_write_msc_services(vty, " ", msc);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void dgsm_vty_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(CONFIG_NODE, &cfg_mslookup_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        install_node(&mslookup_node, config_write_mslookup);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(MSLOOKUP_NODE, &cfg_mslookup_no_mdns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MSLOOKUP_NODE, &cfg_mslookup_server_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSLOOKUP_NODE, &cfg_mslookup_no_server_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    install_node(&mslookup_server_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_bind_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_mdns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_service_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    install_node(&mslookup_server_msc_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_service_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_no_service_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MSLOOKUP_NODE, &cfg_mslookup_client_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_node(&mslookup_client_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_timeout_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_mdns_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_gateway_proxy_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_gateway_proxy_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element_ve(&do_mslookup_show_services_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gsup_server.c b/src/gsup_server.c</span><br><span>index 83329a0..151a882 100644</span><br><span>--- a/src/gsup_server.c</span><br><span>+++ b/src/gsup_server.c</span><br><span>@@ -28,8 +28,10 @@</span><br><span> #include <osmocom/gsm/apn.h></span><br><span> #include <osmocom/gsm/gsm23003.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr.h></span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span> #include <osmocom/hlr/gsup_router.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span> </span><br><span> #define LOG_GSUP_CONN(conn, level, fmt, args...) \</span><br><span>        LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \</span><br><span>diff --git a/src/hlr.c b/src/hlr.c</span><br><span>index d1647a0..536a240 100644</span><br><span>--- a/src/hlr.c</span><br><span>+++ b/src/hlr.c</span><br><span>@@ -36,6 +36,7 @@</span><br><span> #include <osmocom/gsm/gsm48_ie.h></span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span> #include <osmocom/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup_client.h></span><br><span> </span><br><span> #include <osmocom/gsupclient/global_title.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span>@@ -47,6 +48,8 @@</span><br><span> #include <osmocom/hlr/rand.h></span><br><span> #include <osmocom/hlr/hlr_vty.h></span><br><span> #include <osmocom/hlr/hlr_ussd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span> #include <osmocom/hlr/lu_fsm.h></span><br><span> </span><br><span> struct hlr *g_hlr;</span><br><span>@@ -489,6 +492,15 @@</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Distributed GSM: check whether to proxy for / lookup a remote HLR.</span><br><span style="color: hsl(120, 100%, 40%);">+  * It would require less database hits to do this only if a local-only operation fails with "unknown IMSI", but</span><br><span style="color: hsl(120, 100%, 40%);">+      * it becomes semantically easier if we do this once-off ahead of time. */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_mslookup_client_active(g_hlr->mslookup.client.client)</span><br><span style="color: hsl(120, 100%, 40%);">+         || osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.vty.client.gateway_proxy)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (dgsm_check_forward_gsup_msg(req))</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  switch (req->gsup.message_type) {</span><br><span>         /* requests sent to us */</span><br><span>    case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:</span><br><span>@@ -692,6 +704,9 @@</span><br><span>            exit(1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set up llists and objects, startup is happening from VTY commands. */</span><br><span style="color: hsl(120, 100%, 40%);">+      dgsm_init(hlr_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        osmo_stats_init(hlr_ctx);</span><br><span>    vty_init(&vty_info);</span><br><span>     ctrl_vty_init(hlr_ctx);</span><br><span>@@ -746,10 +761,13 @@</span><br><span>              LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");</span><br><span>           exit(1);</span><br><span>     }</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_init(g_hlr->gs);</span><br><span> </span><br><span>        g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();</span><br><span>         g_hlr->ctrl = hlr_controlif_setup(g_hlr);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      dgsm_start(hlr_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       osmo_init_ignore_signals();</span><br><span>  signal(SIGINT, &signal_hdlr);</span><br><span>    signal(SIGTERM, &signal_hdlr);</span><br><span>@@ -766,6 +784,7 @@</span><br><span>     while (!quit)</span><br><span>                osmo_select_main_ctx(0);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  dgsm_stop();</span><br><span> </span><br><span>     osmo_gsup_server_destroy(g_hlr->gs);</span><br><span>      db_close(g_hlr->dbc);</span><br><span>diff --git a/src/hlr_vty.c b/src/hlr_vty.c</span><br><span>index 6701cd9..e20d2bb 100644</span><br><span>--- a/src/hlr_vty.c</span><br><span>+++ b/src/hlr_vty.c</span><br><span>@@ -39,6 +39,7 @@</span><br><span> #include <osmocom/hlr/hlr_vty_subscr.h></span><br><span> #include <osmocom/hlr/hlr_ussd.h></span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span> </span><br><span> struct cmd_node hlr_node = {</span><br><span>     HLR_NODE,</span><br><span>@@ -146,6 +147,24 @@</span><br><span>     return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_hlr_gsup_ipa_name,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_hlr_gsup_ipa_name_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "ipa-name NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Set the IPA name of this HLR, for proxying to remote HLRs\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "A globally unique name for this HLR. For example: PLMN + redundancy server number: HLR-901-70-0. "</span><br><span style="color: hsl(120, 100%, 40%);">+      "This name is used for GSUP routing and must be set if multiple HLRs interconnect (e.g. mslookup "</span><br><span style="color: hsl(120, 100%, 40%);">+      "for Distributed GSM).\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (vty->type != VTY_FILE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "It can only be set in the configuraton file.%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   g_hlr->gsup_unit_name.serno = talloc_strdup(g_hlr, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /***********************************************************************</span><br><span>  * USSD Entity</span><br><span>  ***********************************************************************/</span><br><span>@@ -403,6 +422,17 @@</span><br><span>           vty->index = NULL;</span><br><span>                vty->index_sub = NULL;</span><br><span>            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MSLOOKUP_CLIENT_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+    case MSLOOKUP_SERVER_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+            vty->node = CONFIG_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+           vty->index = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         vty->index_sub = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MSLOOKUP_SERVER_MSC_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+                vty->node = CONFIG_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+           vty->index = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         vty->index_sub = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       default:</span><br><span>     case HLR_NODE:</span><br><span>               vty->node = CONFIG_NODE;</span><br><span>@@ -444,6 +474,7 @@</span><br><span>    install_node(&gsup_node, config_write_hlr_gsup);</span><br><span> </span><br><span>     install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);</span><br><span> </span><br><span>      install_element(HLR_NODE, &cfg_database_cmd);</span><br><span> </span><br><span>@@ -462,4 +493,5 @@</span><br><span>  install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);</span><br><span> </span><br><span>      hlr_vty_subscriber_init();</span><br><span style="color: hsl(120, 100%, 40%);">+    dgsm_vty_init();</span><br><span> }</span><br><span>diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c</span><br><span>index adbfcab..b8eba4d 100644</span><br><span>--- a/src/hlr_vty_subscr.c</span><br><span>+++ b/src/hlr_vty_subscr.c</span><br><span>@@ -30,6 +30,7 @@</span><br><span> </span><br><span> #include <osmocom/hlr/hlr.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span> </span><br><span> struct vty;</span><br><span> </span><br><span>diff --git a/src/logging.c b/src/logging.c</span><br><span>index d123fcd..9d3cc62 100644</span><br><span>--- a/src/logging.c</span><br><span>+++ b/src/logging.c</span><br><span>@@ -31,6 +31,12 @@</span><br><span>             .color = "\033[1;33m",</span><br><span>             .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span>       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DDGSM] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "DDGSM",</span><br><span style="color: hsl(120, 100%, 40%);">+            .description = "Distributed GSM: MS lookup and proxy",</span><br><span style="color: hsl(120, 100%, 40%);">+              .color = "\033[1;35m",</span><br><span style="color: hsl(120, 100%, 40%);">+              .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span> </span><br><span> };</span><br><span> </span><br><span>diff --git a/src/mslookup_server.c b/src/mslookup_server.c</span><br><span>new file mode 100644</span><br><span>index 0000000..af25e06</span><br><span>--- /dev/null</span><br><span>+++ b/src/mslookup_server.c</span><br><span>@@ -0,0 +1,302 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_mslookup_result not_found = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .rc = OSMO_MSLOOKUP_RC_NOT_FOUND,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void set_result(struct osmo_mslookup_result *result,</span><br><span style="color: hsl(120, 100%, 40%);">+                    const struct dgsm_service_host *service_host,</span><br><span style="color: hsl(120, 100%, 40%);">+                 uint32_t age)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!osmo_sockaddr_str_is_nonzero(&service_host->host_v4)</span><br><span style="color: hsl(120, 100%, 40%);">+          && !osmo_sockaddr_str_is_nonzero(&service_host->host_v6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                *result = not_found;</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     result->rc = OSMO_MSLOOKUP_RC_RESULT;</span><br><span style="color: hsl(120, 100%, 40%);">+      result->host_v4 = service_host->host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+        result->host_v6 = service_host->host_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+        result->age = age;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct dgsm_service_host *mslookup_server_get_local_gsup_addr()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        static struct dgsm_service_host gsup_bind = {};</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_service_host *host;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Find a HLR/GSUP service set for the server (no VLR unit name) */</span><br><span style="color: hsl(120, 100%, 40%);">+   host = dgsm_config_service_get(&dgsm_config_msc_wildcard, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (host)</span><br><span style="color: hsl(120, 100%, 40%);">+             return host;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Try to use the locally configured GSUP bind address */</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_sockaddr_str_from_str(&gsup_bind.host_v4, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gsup_bind.host_v4.af == AF_INET6) {</span><br><span style="color: hsl(120, 100%, 40%);">+               gsup_bind.host_v6 = gsup_bind.host_v4;</span><br><span style="color: hsl(120, 100%, 40%);">+                gsup_bind.host_v4 = (struct osmo_sockaddr_str){};</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return &gsup_bind;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* A remote entity is asking us whether we are the home HLR of the given subscriber. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct dgsm_service_host *host;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (query->id.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_MSLOOKUP_ID_IMSI:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_MSLOOKUP_ID_MSISDN:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = db_subscr_exists_by_msisdn(g_hlr->dbc, query->id.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDGSM, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);</span><br><span style="color: hsl(120, 100%, 40%);">+               *result = not_found;</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DDGSM, LOGL_DEBUG, "%s: does not exist in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = not_found;</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDGSM, LOGL_DEBUG, "%s: found in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ host = mslookup_server_get_local_gsup_addr();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       set_result(result, host, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DDGSM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Subscriber found, but error in service '" OSMO_MSLOOKUP_SERVICE_HLR_GSUP "' config:"</span><br><span style="color: hsl(120, 100%, 40%);">+                     " v4: " OSMO_SOCKADDR_STR_FMT "  v6: " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v4),</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v6));</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Look in the local HLR record: If the subscriber is "at home" in this HLR and is also currently located at a local</span><br><span style="color: hsl(120, 100%, 40%);">+ * VLR, we will find a valid location updating with vlr_number, and no vlr_via_proxy entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      uint32_t *lu_age,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct osmo_gt *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct hlr_subscriber subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (query->id.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_MSLOOKUP_ID_IMSI:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = db_subscr_get_by_imsi(g_hlr->dbc, query->id.imsi, &subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_MSLOOKUP_ID_MSISDN:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = db_subscr_get_by_msisdn(g_hlr->dbc, query->id.msisdn, &subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDGSM, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DDGSM, LOGL_DEBUG, "%s: does not exist in local HLR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!subscr.vlr_number[0]) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_DEBUG, "%s: not attached (vlr_number unset)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (subscr.vlr_via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* The VLR is behind a proxy, the subscriber is not attached to a local VLR but a remote one. That</span><br><span style="color: hsl(120, 100%, 40%);">+             * remote proxy should instead respond to the service lookup request. */</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDGSM, LOGL_DEBUG, "%s: last attach is not at local VLR, but at VLR '%s' via proxy %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 subscr.vlr_number,</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_gt_name(&subscr.vlr_via_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!timestamp_age(&subscr.last_lu_seen, &age)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_DGSM(subscr.imsi, LOGL_ERROR, "Invalid last_lu_seen timestamp for subscriber\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (age > g_hlr->mslookup.server.max_age) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DDGSM, LOGL_DEBUG, "%s: last attach was here, but too long ago: %us > %us\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 age, g_hlr->mslookup.server.max_age);</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *lu_age = age;</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_gt_set_str(local_msc_name, subscr.vlr_number);</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDGSM, LOGL_DEBUG, "%s: attached %u seconds ago at local VLR %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+         age, osmo_gt_name(local_msc_name));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Determine whether the subscriber with the given ID has routed a Location Updating via this HLR as first hop. Return</span><br><span style="color: hsl(120, 100%, 40%);">+ * true if it is attached at a local VLR, and we are serving as proxy for a remote home HLR.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool subscriber_has_done_lu_here_proxy(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              uint32_t *lu_age,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct osmo_gt *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct proxy_subscr *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* See the local HLR record. If the subscriber is "at home" in this HLR and is also currently located here, we</span><br><span style="color: hsl(120, 100%, 40%);">+       * will find a valid location updating and no vlr_via_proxy entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (query->id.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_MSLOOKUP_ID_IMSI:</span><br><span style="color: hsl(120, 100%, 40%);">+           proxy_subscr = proxy_subscr_get_by_imsi(g_hlr->gs->proxy, query->id.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_MSLOOKUP_ID_MSISDN:</span><br><span style="color: hsl(120, 100%, 40%);">+         proxy_subscr = proxy_subscr_get_by_msisdn(g_hlr->gs->proxy, query->id.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDGSM, LOGL_ERROR, "%s: unknown ID type\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!proxy_subscr) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_DEBUG, "%s: does not exist in GSUP proxy\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We only need to care about CS LU, since only CS services need D-GSM routing. */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!timestamp_age(&proxy_subscr->cs.last_lu, &age)</span><br><span style="color: hsl(120, 100%, 40%);">+            || age > g_hlr->mslookup.server.max_age) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "%s: last attach was at local VLR (proxying for remote HLR), but too long ago: %us > %us\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 age, g_hlr->mslookup.server.max_age);</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (proxy_subscr->cs.vlr_via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_DEBUG, "%s: last attach is not at local VLR, but at VLR '%s' via proxy '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gt_name(&proxy_subscr->cs.vlr_name),</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_gt_name(&proxy_subscr->cs.vlr_via_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *lu_age = age;</span><br><span style="color: hsl(120, 100%, 40%);">+        *local_msc_name = proxy_subscr->cs.vlr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DDGSM, LOGL_DEBUG, "%s: attached %u seconds ago at local VLR %s; proxying for remote HLR "</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+         age, osmo_gt_name(local_msc_name),</span><br><span style="color: hsl(120, 100%, 40%);">+            OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   uint32_t *lu_age_p,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   struct osmo_gt *local_msc_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    bool attached_here;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t lu_age = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_gt msc_name = {};</span><br><span style="color: hsl(120, 100%, 40%);">+ bool attached_here_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t proxy_lu_age = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gt proxy_msc_name = {};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* First ask the local HLR db, but if the local proxy record indicates a more recent LU, use that instead.</span><br><span style="color: hsl(120, 100%, 40%);">+     * For all usual cases, only one of these will reflect a LU, even if a subscriber had more than one home HLR:</span><br><span style="color: hsl(120, 100%, 40%);">+  *   - if the subscriber is known here, we will never proxy.</span><br><span style="color: hsl(120, 100%, 40%);">+   *   - if the subscriber is not known here, this local HLR db will never record a LU.</span><br><span style="color: hsl(120, 100%, 40%);">+  * However, if a subscriber was being proxied to a remote home HLR, and if then the subscriber was also added to</span><br><span style="color: hsl(120, 100%, 40%);">+       * the local HLR database, there might occur a situation where both reflect a LU. So, to be safe against all</span><br><span style="color: hsl(120, 100%, 40%);">+   * situations, compare the two entries.</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+   attached_here = subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   attached_here_proxy = subscriber_has_done_lu_here_proxy(query, &proxy_lu_age, &proxy_msc_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If proxy has a younger lu, replace. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (attached_here_proxy && (!attached_here || (proxy_lu_age < lu_age))) {</span><br><span style="color: hsl(120, 100%, 40%);">+          attached_here = true;</span><br><span style="color: hsl(120, 100%, 40%);">+         lu_age = proxy_lu_age;</span><br><span style="color: hsl(120, 100%, 40%);">+                msc_name = proxy_msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (attached_here && !msc_name.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DDGSM, LOGL_ERROR, "%s: attached here, but no VLR name known\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!attached_here) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Already logged "not attached" for both local-db and proxy attach */</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDGSM, LOGL_INFO, "%s: attached here, at VLR %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gt_name(&msc_name));</span><br><span style="color: hsl(120, 100%, 40%);">+    *lu_age_p = lu_age;</span><br><span style="color: hsl(120, 100%, 40%);">+   *local_msc_name = msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* A remote entity is asking us whether we are providing the given service for the given subscriber. */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mslookup_server_rx(const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct dgsm_service_host *service_host;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_gt msc_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* A request for a home HLR: answer exactly if this is the subscriber's home HLR, i.e. the IMSI is listed in the</span><br><span style="color: hsl(120, 100%, 40%);">+   * HLR database. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (strcmp(query->service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return mslookup_server_rx_hlr_gsup(query, result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* All other service types: answer when the subscriber has done a LU that is either listed in the local HLR or</span><br><span style="color: hsl(120, 100%, 40%);">+         * in the GSUP proxy database: i.e. if the subscriber has done a Location Updating at an VLR belonging to this</span><br><span style="color: hsl(120, 100%, 40%);">+         * HLR. Respond with whichever services are configured in the osmo-hlr.cfg. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!subscriber_has_done_lu_here(query, &age, &msc_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           *result = not_found;</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We've detected a LU here. The VLR where the LU happened is stored in msc_unit_name, and the LU age is stored</span><br><span style="color: hsl(120, 100%, 40%);">+    * in 'age'. Figure out the address configured for that VLR and service name. */</span><br><span style="color: hsl(120, 100%, 40%);">+      service_host = dgsm_config_service_get(&msc_name, query->service);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!service_host) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Find such service set globally (no VLR unit name) */</span><br><span style="color: hsl(120, 100%, 40%);">+               service_host = dgsm_config_service_get(&dgsm_config_msc_wildcard, query->service);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!service_host) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "%s: subscriber found, but no service %s configured, cannot service lookup request\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_quote_str_c(OTC_SELECT, query->service, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+            *result = not_found;</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   set_result(result, service_host, age);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/mslookup_server_mdns.c b/src/mslookup_server_mdns.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b758cb5</span><br><span>--- /dev/null</span><br><span>+++ b/src/mslookup_server_mdns.c</span><br><span>@@ -0,0 +1,100 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mslookup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/mslookup/mdns.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/mslookup_server_mdns.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_mslookup_server_mdns_tx(struct osmo_mslookup_server_mdns *server,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     uint16_t packet_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const struct osmo_mslookup_query *query,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct osmo_mslookup_result *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *errmsg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    void *ctx = talloc_named_const(server, 0, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = osmo_mdns_result_encode(ctx, packet_id, query, result);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             errmsg = "Error encoding mDNS answer packet";</span><br><span style="color: hsl(120, 100%, 40%);">+       else if (osmo_mdns_sock_send(server->sock, msg))</span><br><span style="color: hsl(120, 100%, 40%);">+           errmsg = "Error sending mDNS answer";</span><br><span style="color: hsl(120, 100%, 40%);">+       if (errmsg)</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DDGSM, LOGL_ERROR, "%s: mDNS: %s\n", osmo_mslookup_result_name_c(ctx, query, result), errmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_mslookup_server_mdns_handle_request(uint16_t packet_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   struct osmo_mslookup_server_mdns *server,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     const struct osmo_mslookup_query *query)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_mslookup_result result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_mslookup_server_rx(query, &result);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Error logging already happens in osmo_mslookup_server_rx() */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (result.rc != OSMO_MSLOOKUP_RC_RESULT)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_mslookup_server_mdns_tx(server, packet_id, query, &result);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_mslookup_server_mdns_rx(struct osmo_fd *osmo_fd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_mslookup_server_mdns *server = osmo_fd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_mslookup_query *query;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t packet_id;</span><br><span style="color: hsl(120, 100%, 40%);">+   int n;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t buffer[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+ void *ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Parse the message and print it */</span><br><span style="color: hsl(120, 100%, 40%);">+  n = read(osmo_fd->fd, buffer, sizeof(buffer));</span><br><span style="color: hsl(120, 100%, 40%);">+     if (n < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         return n;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ctx = talloc_named_const(server, 0, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+        query = osmo_mdns_query_decode(ctx, buffer, n, &packet_id);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!query) {</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_mslookup_id_name_buf((char *)buffer, sizeof(buffer), &query->id);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DDGSM, LOGL_DEBUG, "mDNS rx request: %s.%s\n", query->service, buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_mslookup_server_mdns_handle_request(packet_id, server, query);</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+     return n;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_mslookup_server_mdns *server = talloc_zero(ctx, struct osmo_mslookup_server_mdns);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(server);</span><br><span style="color: hsl(120, 100%, 40%);">+  *server = (struct osmo_mslookup_server_mdns){</span><br><span style="color: hsl(120, 100%, 40%);">+         .bind_addr = *bind_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  server->sock = osmo_mdns_sock_init(server,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    bind_addr->ip, bind_addr->port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         osmo_mslookup_server_mdns_rx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         server, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!server->sock) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DDGSM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "mslookup mDNS server: error initializing multicast bind on " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 OSMO_SOCKADDR_STR_FMT_ARGS(bind_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(server);</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return server;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!server)</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_mdns_sock_cleanup(server->sock);</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(server);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/proxy.c b/src/proxy.c</span><br><span>new file mode 100644</span><br><span>index 0000000..7ccedbb</span><br><span>--- /dev/null</span><br><span>+++ b/src/proxy.c</span><br><span>@@ -0,0 +1,557 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/time.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48_ie.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/gsup_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/gsup_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/remote_hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_router.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_PROXY_SUBSCR(proxy_subscr, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDGSM, level, "(Proxy IMSI-%s MSISDN-%s HLR-" OSMO_SOCKADDR_STR_FMT ") " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+           ((proxy_subscr) && *(proxy_subscr)->imsi)? (proxy_subscr)->imsi : "?", \</span><br><span style="color: hsl(120, 100%, 40%);">+      ((proxy_subscr) && *(proxy_subscr)->msisdn)? (proxy_subscr)->msisdn : "?", \</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_SOCKADDR_STR_FMT_ARGS((proxy_subscr)? &(proxy_subscr)->remote_hlr_addr : NULL), \</span><br><span style="color: hsl(120, 100%, 40%);">+         ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup_msg, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_PROXY_SUBSCR(proxy_subscr, level, "%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                  (gsup_msg) ? osmo_gsup_message_type_name((gsup_msg)->message_type) : "NULL", \</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Why have a separate struct to add an llist_head entry?</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is to keep the option open to store the proxy data in the database instead, without any visible effect outside</span><br><span style="color: hsl(120, 100%, 40%);">+ * of proxy.c. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct proxy_subscr_listentry {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_t last_update;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct proxy_subscr data;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Central implementation to set a timestamp to the current time, in case we want to modify this in the future. */</span><br><span style="color: hsl(120, 100%, 40%);">+void timestamp_update(timestamp_t *timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval tv;</span><br><span style="color: hsl(120, 100%, 40%);">+    time_t raw;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct tm utc;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* The simpler way would be just time(&raw), but by using osmo_gettimeofday() we can also use</span><br><span style="color: hsl(120, 100%, 40%);">+      * osmo_gettimeofday_override for unit tests independent from real time. */</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_gettimeofday(&tv, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     raw = tv.tv_sec;</span><br><span style="color: hsl(120, 100%, 40%);">+      gmtime_r(&raw, &utc);</span><br><span style="color: hsl(120, 100%, 40%);">+ *timestamp = mktime(&utc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Calculate seconds since a given timestamp was taken. Return true for a valid age returned in age_p, return false if</span><br><span style="color: hsl(120, 100%, 40%);">+ * the timestamp is either in the future or the age surpasses uint32_t range. When false is returned, *age_p is set to</span><br><span style="color: hsl(120, 100%, 40%);">+ * UINT32_MAX. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool timestamp_age(const timestamp_t *timestamp, uint32_t *age_p)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int64_t age64;</span><br><span style="color: hsl(120, 100%, 40%);">+        timestamp_t now;</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_update(&now);</span><br><span style="color: hsl(120, 100%, 40%);">+   age64 = (int64_t)now - (int64_t)(*timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (age64 < 0 || age64 > UINT32_MAX) {</span><br><span style="color: hsl(120, 100%, 40%);">+          *age_p = UINT32_MAX;</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     *age_p = (uint32_t)age64;</span><br><span style="color: hsl(120, 100%, 40%);">+     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Defer a GSUP message until we know a remote HLR to proxy to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Where to send this GSUP message is indicated by its IMSI: as soon as an MS lookup has yielded the IMSI's home HLR,</span><br><span style="color: hsl(120, 100%, 40%);">+ * that's where the message should go. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_defer_gsup_req(struct proxy *proxy, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct proxy_pending_gsup_req *m;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   m = talloc_zero(proxy, struct proxy_pending_gsup_req);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(m);</span><br><span style="color: hsl(120, 100%, 40%);">+       m->req = req;</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_update(&m->received_at);</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&m->entry, &proxy->pending_gsup_reqs);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Unable to resolve remote HLR for this IMSI, Answer with error back to the sender. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_defer_gsup_message_err(struct proxy *proxy, struct proxy_pending_gsup_req *m)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gsup_req_respond_err(m->req, GMM_CAUSE_IMSI_UNKNOWN, "could not reach home HLR");</span><br><span style="color: hsl(120, 100%, 40%);">+   m->req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Forward spooled message for this IMSI to remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_defer_gsup_message_send(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct proxy_pending_gsup_req *m, struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_PROXY_SUBSCR_MSG(proxy_subscr, &m->req->gsup, LOGL_INFO, "Forwarding deferred message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    proxy_subscr_forward_to_remote_hlr_resolved(proxy, proxy_subscr, remote_hlr, m->req);</span><br><span style="color: hsl(120, 100%, 40%);">+      m->req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. On failure, the proxy_subscr and the</span><br><span style="color: hsl(120, 100%, 40%);">+ * remote_hlr may be passed NULL. The IMSI then reflects who the error was for. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_defer_gsup_message_pop(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const char *imsi, struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct proxy_pending_gsup_req *m, *n;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!imsi && proxy_subscr)</span><br><span style="color: hsl(120, 100%, 40%);">+            imsi = proxy_subscr->imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDGSM, LOGL_ERROR, "IMSI-%s: No remote HLR found, dropping spooled GSUP messages\n", imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry_safe(m, n, &proxy->pending_gsup_reqs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (strcmp(m->req->gsup.imsi, imsi))</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+                      proxy_defer_gsup_message_err(proxy, m);</span><br><span style="color: hsl(120, 100%, 40%);">+               else</span><br><span style="color: hsl(120, 100%, 40%);">+                  proxy_defer_gsup_message_send(proxy, proxy_subscr, m, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          llist_del(&m->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(m);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool proxy_subscr_matches_imsi(const struct proxy_subscr *proxy_subscr, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!proxy_subscr || !imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ return strcmp(proxy_subscr->imsi, imsi) == 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool proxy_subscr_matches_msisdn(const struct proxy_subscr *proxy_subscr, const char *msisdn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!proxy_subscr || !msisdn)</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ return strcmp(proxy_subscr->msisdn, msisdn) == 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct proxy_subscr_listentry *_proxy_get_by_imsi(struct proxy *proxy, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!proxy)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(e, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (proxy_subscr_matches_imsi(&e->data, imsi))</span><br><span style="color: hsl(120, 100%, 40%);">+                 return e;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct proxy_subscr_listentry *_proxy_get_by_msisdn(struct proxy *proxy, const char *msisdn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!proxy)</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(e, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (proxy_subscr_matches_msisdn(&e->data, msisdn))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return e;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!e)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return &e->data;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct proxy_subscr_listentry *e = _proxy_get_by_msisdn(proxy, msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!e)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return &e->data;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscrs_get_by_remote_hlr(struct proxy *proxy, const struct osmo_sockaddr_str *remote_hlr_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   bool (*yield)(struct proxy *proxy, const struct proxy_subscr *subscr, void *data),</span><br><span style="color: hsl(120, 100%, 40%);">+                                    void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!proxy)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(e, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!osmo_sockaddr_str_cmp(remote_hlr_addr, &e->data.remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!yield(proxy, &e->data, data))</span><br><span style="color: hsl(120, 100%, 40%);">+                             return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, proxy_subscr->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Does not exist yet */</span><br><span style="color: hsl(120, 100%, 40%);">+              e = talloc_zero(proxy, struct proxy_subscr_listentry);</span><br><span style="color: hsl(120, 100%, 40%);">+                llist_add(&e->entry, &proxy->subscr_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     e->data = *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+   timestamp_update(&e->last_update);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int _proxy_subscr_del(struct proxy_subscr_listentry *e)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_del(&e->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_del(struct proxy *proxy, const char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct proxy_subscr_listentry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_defer_gsup_message_pop(proxy, NULL, imsi, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        e = _proxy_get_by_imsi(proxy, imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ENOENT;</span><br><span style="color: hsl(120, 100%, 40%);">+       return _proxy_subscr_del(e);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Discard stale proxy entries. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void proxy_cleanup(void *proxy_v)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct proxy *proxy = proxy_v;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct proxy_subscr_listentry *e, *n;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t age;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(e, n, &proxy->subscr_list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!timestamp_age(&e->last_update, &age))</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOGP(DDGSM, LOGL_ERROR, "Invalid timestamp, deleting proxy entry\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               else if (age <= proxy->fresh_time)</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_PROXY_SUBSCR(&e->data, LOGL_INFO, "proxy entry timed out, deleting\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          _proxy_subscr_del(e);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (proxy->gc_period)</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_timer_schedule(&proxy->gc_timer, proxy->gc_period, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_NOTICE, "Proxy cleanup is switched off (gc_period == 0)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    proxy->gc_period = gc_period;</span><br><span style="color: hsl(120, 100%, 40%);">+      proxy_cleanup(proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_init(struct osmo_gsup_server *gsup_server_to_vlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(!gsup_server_to_vlr->proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy *proxy = talloc_zero(gsup_server_to_vlr, struct proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+  *proxy = (struct proxy){</span><br><span style="color: hsl(120, 100%, 40%);">+              .gsup_server_to_vlr = gsup_server_to_vlr,</span><br><span style="color: hsl(120, 100%, 40%);">+             .fresh_time = 60*60,</span><br><span style="color: hsl(120, 100%, 40%);">+          .gc_period = 60,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&proxy->subscr_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&proxy->pending_gsup_reqs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_timer_setup(&proxy->gc_timer, proxy_cleanup, proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Invoke to trigger the first timer schedule */</span><br><span style="color: hsl(120, 100%, 40%);">+      proxy_set_gc_period(proxy, proxy->gc_period);</span><br><span style="color: hsl(120, 100%, 40%);">+      gsup_server_to_vlr->proxy = proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_del(struct proxy *proxy)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_timer_del(&proxy->gc_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_remote_hlr_up(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                               struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_defer_gsup_message_pop(proxy, proxy_subscr, proxy_subscr->imsi, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct proxy_subscr proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!osmo_sockaddr_str_cmp(&remote_hlr->addr, &proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* Already have this remote address */</span><br><span style="color: hsl(120, 100%, 40%);">+                        return;</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOG_PROXY_SUBSCR(proxy_subscr, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    "Remote HLR address changes to " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Store the address. Make a copy to modify. */</span><br><span style="color: hsl(120, 100%, 40%);">+       proxy_subscr_new = *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+     proxy_subscr = &proxy_subscr_new;</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy_subscr_new.remote_hlr_addr = remote_hlr->addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (proxy_subscr_update(proxy, proxy_subscr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_PROXY_SUBSCR(proxy_subscr, LOGL_ERROR, "Failed to store proxy entry for remote HLR\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         /* If no remote HLR is known for the IMSI, the proxy entry is pointless. */</span><br><span style="color: hsl(120, 100%, 40%);">+           proxy_subscr_del(proxy, proxy_subscr->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOG_PROXY_SUBSCR(proxy_subscr, LOGL_DEBUG, "Remote HLR resolved, stored address\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* All GSUP messages sent to the remote HLR pass through this function, to modify the subscriber state or disallow</span><br><span style="color: hsl(120, 100%, 40%);">+ * sending the message. Return 0 to allow sending the message. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             const struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct proxy_subscr proxy_subscr_new = *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool ps;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool cs;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (req->gsup.message_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Store the CS and PS VLR name in vlr_name_preliminary to later update the right {cs,ps} LU timestamp</span><br><span style="color: hsl(120, 100%, 40%);">+                 * when receiving an OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT. Store in vlr_name_preliminary so that in</span><br><span style="color: hsl(120, 100%, 40%);">+           * case the LU fails, we keep the vlr_name intact. */</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (req->gsup.cn_domain) {</span><br><span style="color: hsl(120, 100%, 40%);">+             case OSMO_GSUP_CN_DOMAIN_CS:</span><br><span style="color: hsl(120, 100%, 40%);">+                  proxy_subscr_new.cs.vlr_name_preliminary = req->source_name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case OSMO_GSUP_CN_DOMAIN_PS:</span><br><span style="color: hsl(120, 100%, 40%);">+                  proxy_subscr_new.ps.vlr_name_preliminary = req->source_name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ps = cs = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              if (osmo_gt_cmp(&proxy_subscr_new.cs.vlr_name_preliminary, &proxy_subscr->cs.vlr_name_preliminary))</span><br><span style="color: hsl(120, 100%, 40%);">+                        cs = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (osmo_gt_cmp(&proxy_subscr_new.ps.vlr_name_preliminary, &proxy_subscr->ps.vlr_name_preliminary))</span><br><span style="color: hsl(120, 100%, 40%);">+                        ps = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!(cs || ps)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_DEBUG, "VLR names remain unchanged\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = proxy_subscr_update(proxy, &proxy_subscr_new);</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, rc ? LOGL_ERROR : LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 "%s: preliminary VLR name for%s%s to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                 rc ? "failed to update" : "updated",</span><br><span style="color: hsl(120, 100%, 40%);">+                              cs ? " CS" : "", ps ? " PS" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     osmo_gt_name(&req->source_name));</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* TODO: delete proxy entry in case of a Purge Request? */</span><br><span style="color: hsl(120, 100%, 40%);">+    default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* All GSUP messages received from the remote HLR to be sent to a local MSC pass through this function, to modify the</span><br><span style="color: hsl(120, 100%, 40%);">+ * subscriber state or disallow sending the message. Return 0 to allow sending the message.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The local MSC shall be indicated by gsup.destination_name. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int proxy_acknowledge_gsup_from_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           const struct osmo_gsup_message *gsup,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 struct remote_hlr *from_remote_hlr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           const struct osmo_gt *destination,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            const struct osmo_gt *via_peer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct proxy_subscr proxy_subscr_new = *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool ps;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool cs;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool vlr_name_changed_cs;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool vlr_name_changed_ps;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_gt via_proxy = {};</span><br><span style="color: hsl(120, 100%, 40%);">+        if (osmo_gt_cmp(via_peer, destination))</span><br><span style="color: hsl(120, 100%, 40%);">+               via_proxy = *via_peer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (gsup->message_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Remember the MSISDN of the subscriber. This does not need to be a preliminary record, because when</span><br><span style="color: hsl(120, 100%, 40%);">+          * the HLR tells us about subscriber data, it is definitive info and there is no ambiguity (like there</span><br><span style="color: hsl(120, 100%, 40%);">+                 * would be with failed LU attempts from various sources). */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!gsup->msisdn_enc_len)</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_DEBUG, "No MSISDN in this Insert Data Request\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            else if (gsm48_decode_bcd_number2(proxy_subscr_new.msisdn, sizeof(proxy_subscr_new.msisdn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                             gsup->msisdn_enc, gsup->msisdn_enc_len, 0))</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR, "Failed to decode MSISDN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          else if (!osmo_msisdn_str_valid(proxy_subscr_new.msisdn))</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR, "invalid MSISDN: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                             osmo_quote_str_c(OTC_SELECT, proxy_subscr_new.msisdn, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+              else if (!strcmp(proxy_subscr->msisdn, proxy_subscr_new.msisdn))</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_DEBUG, "already have MSISDN = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       proxy_subscr_new.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+                else if (proxy_subscr_update(proxy, &proxy_subscr_new))</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR, "failed to update MSISDN to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          proxy_subscr_new.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+                else</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_INFO, "stored MSISDN=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        proxy_subscr_new.msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Update the Location Updating timestamp */</span><br><span style="color: hsl(120, 100%, 40%);">+          cs = ps = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!osmo_gt_cmp(destination, &proxy_subscr->cs.vlr_name_preliminary)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       timestamp_update(&proxy_subscr_new.cs.last_lu);</span><br><span style="color: hsl(120, 100%, 40%);">+                   proxy_subscr_new.cs.vlr_name_preliminary = (struct osmo_gt){};</span><br><span style="color: hsl(120, 100%, 40%);">+                        vlr_name_changed_cs =</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_gt_cmp(&proxy_subscr->cs.vlr_name, destination)</span><br><span style="color: hsl(120, 100%, 40%);">+                           || osmo_gt_cmp(&proxy_subscr->cs.vlr_via_proxy, &via_proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+                       proxy_subscr_new.cs.vlr_name = *destination;</span><br><span style="color: hsl(120, 100%, 40%);">+                  proxy_subscr_new.cs.vlr_via_proxy = via_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+                        cs = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!osmo_gt_cmp(destination, &proxy_subscr->ps.vlr_name_preliminary)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       timestamp_update(&proxy_subscr_new.ps.last_lu);</span><br><span style="color: hsl(120, 100%, 40%);">+                   proxy_subscr_new.ps.vlr_name_preliminary = (struct osmo_gt){};</span><br><span style="color: hsl(120, 100%, 40%);">+                        proxy_subscr_new.ps.vlr_name = *destination;</span><br><span style="color: hsl(120, 100%, 40%);">+                  vlr_name_changed_ps =</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_gt_cmp(&proxy_subscr->ps.vlr_name, destination)</span><br><span style="color: hsl(120, 100%, 40%);">+                           || osmo_gt_cmp(&proxy_subscr->ps.vlr_via_proxy, &via_proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+                       proxy_subscr_new.ps.vlr_via_proxy = via_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+                        ps = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!(cs || ps)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "destination is neither CS nor PS VLR: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gt_name(destination));</span><br><span style="color: hsl(120, 100%, 40%);">+                      return GMM_CAUSE_PROTO_ERR_UNSPEC;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = proxy_subscr_update(proxy, &proxy_subscr_new);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, rc ? LOGL_ERROR : LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "%s LU: timestamp for%s%s%s%s%s%s%s%s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               rc ? "failed to update" : "updated",</span><br><span style="color: hsl(120, 100%, 40%);">+                              cs ? " CS" : "", ps ? " PS" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     vlr_name_changed_cs? ", CS VLR=" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    vlr_name_changed_cs? osmo_gt_name(&proxy_subscr_new.cs.vlr_name) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  proxy_subscr_new.cs.vlr_via_proxy.len ? " via proxy " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                               proxy_subscr_new.cs.vlr_via_proxy.len ?</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gt_name(&proxy_subscr_new.cs.vlr_via_proxy) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  vlr_name_changed_ps? ", PS VLR=" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    vlr_name_changed_ps? osmo_gt_name(&proxy_subscr_new.ps.vlr_name) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  proxy_subscr_new.ps.vlr_via_proxy.len ? " via proxy " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                               proxy_subscr_new.ps.vlr_via_proxy.len ?</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gt_name(&proxy_subscr_new.ps.vlr_via_proxy) : ""</span><br><span style="color: hsl(120, 100%, 40%);">+                                  );</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_forward_to_remote_hlr_resolved(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               struct remote_hlr *remote_hlr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (proxy_acknowledge_gsup_to_remote_hlr(proxy, proxy_subscr, req)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_respond_err(req, GMM_CAUSE_PROTO_ERR_UNSPEC, "Proxy does not allow this message");</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   remote_hlr_gsup_forward_to_remote_hlr(remote_hlr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct remote_hlr *remote_hlr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!osmo_sockaddr_str_is_nonzero(&proxy_subscr->remote_hlr_addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* We don't know the remote target yet. Still waiting for an MS lookup response. */</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_DEBUG, "deferring until remote HLR is known\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         proxy_defer_gsup_req(proxy, req);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (req->via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s via proxy %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_gt_name(&req->source_name),</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_gt_name(&req->via_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    osmo_gt_name(&req->source_name));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   remote_hlr = remote_hlr_get(&proxy_subscr->remote_hlr_addr, true);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!remote_hlr) {</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      "Proxy: Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       OSMO_SOCKADDR_STR_FMT_ARGS(&proxy_subscr->remote_hlr_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!remote_hlr->gsupc || !remote_hlr->gsupc->is_connected) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* GSUP link is still busy establishing... */</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  "deferring until link to remote HLR is up\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         proxy_defer_gsup_req(proxy, req);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   proxy_subscr_forward_to_remote_hlr_resolved(proxy, proxy_subscr, remote_hlr, req);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int proxy_subscr_forward_to_vlr(struct proxy *proxy, const struct proxy_subscr *proxy_subscr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                const struct osmo_gsup_message *gsup, struct remote_hlr *from_remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_gt destination;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_conn *vlr_conn;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_gt_set(&destination, gsup->destination_name, gsup->destination_name_len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "no valid Destination Name IE, cannot route to VLR.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return GMM_CAUSE_INV_MAND_INFO;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Route to MSC/SGSN that we're proxying for */</span><br><span style="color: hsl(120, 100%, 40%);">+   vlr_conn = gsup_route_find_gt(proxy->gsup_server_to_vlr, &destination);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!vlr_conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "Destination VLR unreachable: %s\n", osmo_gt_name(&destination));</span><br><span style="color: hsl(120, 100%, 40%);">+          return GMM_CAUSE_MSC_TEMP_NOTREACH;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (proxy_acknowledge_gsup_from_remote_hlr(proxy, proxy_subscr, gsup, from_remote_hlr, &destination,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 &vlr_conn->peer_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "Proxy does not allow forwarding this message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return GMM_CAUSE_PROTO_ERR_UNSPEC;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = osmo_gsup_msgb_alloc("GSUP proxy to VLR");</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_gsup_encode(msg, gsup)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "Failed to re-encode GSUP message, cannot forward\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return GMM_CAUSE_INV_MAND_INFO;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOG_PROXY_SUBSCR_MSG(proxy_subscr, gsup, LOGL_INFO, "VLR<-HLR: forwarding to %s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_gt_name(&destination),</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_gt_cmp(&destination, &vlr_conn->peer_name) ? " via " : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gt_cmp(&destination, &vlr_conn->peer_name) ?</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    osmo_gt_name(&vlr_conn->peer_name) : "");</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_gsup_conn_send(vlr_conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/remote_hlr.c b/src/remote_hlr.c</span><br><span>new file mode 100644</span><br><span>index 0000000..78339d4</span><br><span>--- /dev/null</span><br><span>+++ b/src/remote_hlr.c</span><br><span>@@ -0,0 +1,181 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_04_08_gprs.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsup.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/abis/ipa.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/gsup_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/gsup_router.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/dgsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/remote_hlr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/proxy.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static LLIST_HEAD(remote_hlrs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void remote_hlr_err_reply(struct remote_hlr *rh, const struct osmo_gsup_message *gsup_orig,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 enum gsm48_gmm_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_gsup_message gsup_reply;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* No need to answer if we couldn't parse an ERROR message type, only REQUESTs need an error reply. */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!OSMO_GSUP_IS_MSGT_REQUEST(gsup_orig->message_type))</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gsup_reply = (struct osmo_gsup_message){</span><br><span style="color: hsl(120, 100%, 40%);">+              .cause = cause,</span><br><span style="color: hsl(120, 100%, 40%);">+               .message_type = OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type),</span><br><span style="color: hsl(120, 100%, 40%);">+          .message_class = gsup_orig->message_class,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* RP-Message-Reference is mandatory for SM Service */</span><br><span style="color: hsl(120, 100%, 40%);">+                .sm_rp_mr = gsup_orig->sm_rp_mr,</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_STRLCPY_ARRAY(gsup_reply.imsi, gsup_orig->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* For SS/USSD, it's important to keep both session state and ID IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (gsup_orig->session_state != OSMO_GSUP_SESSION_STATE_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+            gsup_reply.session_state = OSMO_GSUP_SESSION_STATE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+               gsup_reply.session_id = gsup_orig->session_id;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_gsup_client_enc_send(rh->gsupc, &gsup_reply))</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLGSUP, LOGL_ERROR, "Failed to send Error reply (imsi=%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_quote_str(gsup_orig->imsi, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* We are receiving a GSUP message from a remote HLR to go back to a local MSC.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The local MSC shall be indicated by gsup.destination_name. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int remote_hlr_rx(struct osmo_gsup_client *gsupc, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct remote_hlr *rh = gsupc->data;</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct proxy_subscr *proxy_subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_message gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_REMOTE_HLR(rh, LOGL_ERROR, "Failed to decode GSUP message: '%s' (%d) [ %s]\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         get_value_string(gsm48_gmm_cause_names, -rc),</span><br><span style="color: hsl(120, 100%, 40%);">+                         -rc, osmo_hexdump(msg->data, msg->len));</span><br><span style="color: hsl(120, 100%, 40%);">+         return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!osmo_imsi_str_valid(gsup.imsi)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_REMOTE_HLR_MSG(rh, &gsup, LOGL_ERROR, "Invalid IMSI\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            remote_hlr_err_reply(rh, &gsup, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -GMM_CAUSE_INV_MAND_INFO;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   proxy_subscr = proxy_subscr_get_by_imsi(g_hlr->gs->proxy, gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!proxy_subscr) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_REMOTE_HLR_MSG(rh, &gsup, LOGL_ERROR, "No proxy entry for this IMSI\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            remote_hlr_err_reply(rh, &gsup, GMM_CAUSE_NET_FAIL);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -GMM_CAUSE_NET_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = proxy_subscr_forward_to_vlr(g_hlr->gs->proxy, proxy_subscr, &gsup, rh);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_REMOTE_HLR_MSG(rh, &gsup, LOGL_ERROR, "Failed to forward GSUP message towards VLR\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              remote_hlr_err_reply(rh, &gsup, GMM_CAUSE_NET_FAIL);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -GMM_CAUSE_NET_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool remote_hlr_up_yield(struct proxy *proxy, const struct proxy_subscr *proxy_subscr, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct remote_hlr *remote_hlr = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ proxy_subscr_remote_hlr_up(proxy, proxy_subscr, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+  return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool remote_hlr_up_down(struct osmo_gsup_client *gsupc, bool up)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct remote_hlr *remote_hlr = gsupc->data;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!up) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_REMOTE_HLR(remote_hlr, LOGL_NOTICE, "link to remote HLR is down, removing GSUP client\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              remote_hlr_destroy(remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOG_REMOTE_HLR(remote_hlr, LOGL_NOTICE, "link up\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       proxy_subscrs_get_by_remote_hlr(g_hlr->gs->proxy, &remote_hlr->addr, remote_hlr_up_yield, remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct remote_hlr *remote_hlr_get(const struct osmo_sockaddr_str *addr, bool create)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct remote_hlr *rh;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(rh, &remote_hlrs, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!osmo_sockaddr_str_cmp(&rh->addr, addr))</span><br><span style="color: hsl(120, 100%, 40%);">+                   return rh;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!create)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Doesn't exist yet, create a GSUP client to remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+      rh = talloc_zero(dgsm_ctx, struct remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rh);</span><br><span style="color: hsl(120, 100%, 40%);">+      *rh = (struct remote_hlr){</span><br><span style="color: hsl(120, 100%, 40%);">+            .addr = *addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                .gsupc = osmo_gsup_client_create3(rh, &g_hlr->gsup_unit_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            addr->ip, addr->port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 remote_hlr_rx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                remote_hlr_up_down,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           rh),</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!rh->gsupc) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDGSM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Failed to establish connection to remote HLR " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_SOCKADDR_STR_FMT_ARGS(addr));</span><br><span style="color: hsl(120, 100%, 40%);">+               talloc_free(rh);</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     rh->gsupc->data = rh;</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add(&rh->entry, &remote_hlrs);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rh;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_destroy(struct remote_hlr *remote_hlr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_gsup_client_destroy(remote_hlr->gsupc);</span><br><span style="color: hsl(120, 100%, 40%);">+       remote_hlr->gsupc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_del(&remote_hlr->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(remote_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* This function takes ownership of the msg, do not free it after passing to this function. */</span><br><span style="color: hsl(120, 100%, 40%);">+int remote_hlr_msgb_send(struct remote_hlr *remote_hlr, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc = osmo_gsup_client_send(remote_hlr->gsupc, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DDGSM, LOGL_ERROR, "Failed to send GSUP message to " OSMO_SOCKADDR_STR_FMT "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* A GSUP message was received from the MS/MSC side, forward it to the remote HLR. */</span><br><span style="color: hsl(120, 100%, 40%);">+void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = osmo_gsup_msgb_alloc("GSUP proxy to remote HLR");</span><br><span style="color: hsl(120, 100%, 40%);">+        /* To forward to a remote HLR, we need to indicate the source MSC's name in the Source Name IE to make sure the</span><br><span style="color: hsl(120, 100%, 40%);">+    * reply can be routed back. Store the sender MSC in gsup->source_name -- the remote HLR is required to return</span><br><span style="color: hsl(120, 100%, 40%);">+      * this as gsup->destination_name so that the reply gets routed to the original MSC. */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gsup_message forward = req->gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+      forward.source_name = req->source_name.val;</span><br><span style="color: hsl(120, 100%, 40%);">+        forward.source_name_len = req->source_name.len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_gsup_encode(msg, &forward);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Failed to encode GSUP message for forwarding\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     remote_hlr_msgb_send(remote_hlr, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_gsup_req_free(req);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty</span><br><span>index dd8dbcf..ac9ff31 100644</span><br><span>--- a/tests/test_nodes.vty</span><br><span>+++ b/tests/test_nodes.vty</span><br><span>@@ -35,6 +35,7 @@</span><br><span>   show gsup-connections</span><br><span>   subscriber (imsi|msisdn|id|imei) IDENT show</span><br><span>   show subscriber (imsi|msisdn|id|imei) IDENT</span><br><span style="color: hsl(120, 100%, 40%);">+  show mslookup services</span><br><span> </span><br><span> OsmoHLR> enable</span><br><span> OsmoHLR# ?</span><br><span>@@ -89,6 +90,7 @@</span><br><span>   end</span><br><span> ...</span><br><span>   hlr</span><br><span style="color: hsl(120, 100%, 40%);">+  mslookup</span><br><span> </span><br><span> OsmoHLR(config)# hlr</span><br><span> OsmoHLR(config-hlr)# ?</span><br><span>@@ -127,6 +129,7 @@</span><br><span> OsmoHLR(config-hlr-gsup)# list</span><br><span> ...</span><br><span>   bind ip A.B.C.D</span><br><span style="color: hsl(120, 100%, 40%);">+  ipa-name NAME</span><br><span> </span><br><span> OsmoHLR(config-hlr-gsup)# exit</span><br><span> OsmoHLR(config-hlr)# exit</span><br><span>@@ -151,6 +154,7 @@</span><br><span>  logging level auc notice</span><br><span>  logging level ss info</span><br><span>  logging level lu notice</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level dgsm notice</span><br><span> ...</span><br><span> hlr</span><br><span>  store-imei</span><br><span>@@ -160,3 +164,324 @@</span><br><span>  ussd route prefix *#100# internal own-msisdn</span><br><span>  ussd route prefix *#101# internal own-imsi</span><br><span> end</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR# configure terminal</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config)# mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# ?</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns    Convenience shortcut: enable and configure both server and client for mDNS mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+  no      Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+  server  Enable and configure Distributed GSM mslookup server</span><br><span style="color: hsl(120, 100%, 40%);">+  client  Enable and configure Distributed GSM mslookup client</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# list</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns [IP] [<1-65535>]</span><br><span style="color: hsl(120, 100%, 40%);">+  no mdns</span><br><span style="color: hsl(120, 100%, 40%);">+  server</span><br><span style="color: hsl(120, 100%, 40%);">+  no server</span><br><span style="color: hsl(120, 100%, 40%);">+  client</span><br><span style="color: hsl(120, 100%, 40%);">+  no client</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# ?</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns    Convenience shortcut: enable and configure both server and client for mDNS mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+  no      Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+  server  Enable and configure Distributed GSM mslookup server</span><br><span style="color: hsl(120, 100%, 40%);">+  client  Enable and configure Distributed GSM mslookup client</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# no?</span><br><span style="color: hsl(120, 100%, 40%);">+  no  Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# no ?</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns    Disable both server and client for mDNS mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+  server  Disable Distributed GSM mslookup server</span><br><span style="color: hsl(120, 100%, 40%);">+  client  Disable Distributed GSM mslookup client</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# mdns ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [IP]  multicast IPv4 address like 239.192.23.42 or IPv6 address like ff08::23:42</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# mdns 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [<1-65535>]  mDNS UDP Port number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# server</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# ?</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns     Configure where the mDNS server listens for mslookup requests</span><br><span style="color: hsl(120, 100%, 40%);">+  no       Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Configure addresses of local services, as sent in replies to remote mslookup requests.</span><br><span style="color: hsl(120, 100%, 40%);">+  msc      Configure services for individual local MSCs</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# list</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns [IP] [<1-65535>]</span><br><span style="color: hsl(120, 100%, 40%);">+  no mdns</span><br><span style="color: hsl(120, 100%, 40%);">+  service NAME at IP <1-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  no service NAME</span><br><span style="color: hsl(120, 100%, 40%);">+  no service NAME at IP <1-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  msc .UNIT_NAME</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# mdns?</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns  Configure where the mDNS server listens for mslookup requests</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# mdns ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [IP]  multicast IPv4 address like 239.192.23.42 or IPv6 address like ff08::23:42</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# mdns bind ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [<1-65535>]  mDNS UDP Port number</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# mdns bind 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+% There is no matched command.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# mdns bind 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+% There is no matched command.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service?</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Configure addresses of local services, as sent in replies to remote mslookup requests.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service ?</span><br><span style="color: hsl(120, 100%, 40%);">+  NAME  mslookup service name, e.g. sip.voice or smpp.sms</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service foo ?</span><br><span style="color: hsl(120, 100%, 40%);">+  at  at</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service foo at ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service foo at 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  <1-65535>  Service-specific port number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no ?</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns     Disable server for mDNS mslookup (do not answer remote requests)</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Remove one or more service address entries</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service ?</span><br><span style="color: hsl(120, 100%, 40%);">+  NAME  mslookup service name, e.g. sip.voice or smpp.sms</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service foo ?</span><br><span style="color: hsl(120, 100%, 40%);">+  at    at</span><br><span style="color: hsl(120, 100%, 40%);">+  <cr>  </span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service foo at ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service foo at 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  <1-65535>  Service-specific port number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc?</span><br><span style="color: hsl(120, 100%, 40%);">+  msc  Configure services for individual local MSCs</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc ?</span><br><span style="color: hsl(120, 100%, 40%);">+  UNIT_NAME  IPA Unit Name of the local MSC to configure</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# ?</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Configure addresses of local services, as sent in replies to remote mslookup requests.</span><br><span style="color: hsl(120, 100%, 40%);">+  no       Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# list</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  service NAME at IP <1-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  no service NAME</span><br><span style="color: hsl(120, 100%, 40%);">+  no service NAME at IP <1-65535></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service?</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Configure addresses of local services, as sent in replies to remote mslookup requests.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service ?</span><br><span style="color: hsl(120, 100%, 40%);">+  NAME  mslookup service name, e.g. sip.voice or smpp.sms</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service foo ?</span><br><span style="color: hsl(120, 100%, 40%);">+  at  at</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service foo at ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service foo at 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  <1-65535>  Service-specific port number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no ?</span><br><span style="color: hsl(120, 100%, 40%);">+  service  Remove one or more service address entries</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service ?</span><br><span style="color: hsl(120, 100%, 40%);">+  NAME  mslookup service name, e.g. sip.voice or smpp.sms</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service foo ?</span><br><span style="color: hsl(120, 100%, 40%);">+  at    at</span><br><span style="color: hsl(120, 100%, 40%);">+  <cr>  </span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service foo at ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service foo at 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  <1-65535>  Service-specific port number</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# client</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# ?</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  timeout        How long should the mslookup client wait for remote responses before evaluating received results</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns           Enable mDNS client, and configure multicast address to send mDNS mslookup requests to</span><br><span style="color: hsl(120, 100%, 40%);">+  no             Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+  gateway-proxy  Configure a fixed IP address to send all GSUP requests for unknown IMSIs to, without invoking a lookup for IMSI</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# list</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  timeout <1-100000></span><br><span style="color: hsl(120, 100%, 40%);">+  mdns [IP] [<1-65535>]</span><br><span style="color: hsl(120, 100%, 40%);">+  no mdns</span><br><span style="color: hsl(120, 100%, 40%);">+  gateway-proxy IP [<1-65535>]</span><br><span style="color: hsl(120, 100%, 40%);">+  no gateway-proxy</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# timeout?</span><br><span style="color: hsl(120, 100%, 40%);">+  timeout  How long should the mslookup client wait for remote responses before evaluating received results</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# timeout ?</span><br><span style="color: hsl(120, 100%, 40%);">+  <1-100000>  timeout in milliseconds</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# mdns?</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns  Enable mDNS client, and configure multicast address to send mDNS mslookup requests to</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# mdns to ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [<1-65535>]  mDNS UDP Port number</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# mdns to 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+% There is no matched command.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy?</span><br><span style="color: hsl(120, 100%, 40%);">+  gateway-proxy  Configure a fixed IP address to send all GSUP requests for unknown IMSIs to, without invoking a lookup for IMSI</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IP address of the remote HLR</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [<1-65535>]  GSUP port number (omit for default 4222)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# no?</span><br><span style="color: hsl(120, 100%, 40%);">+  no  Negate a command or set its defaults</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# no ?</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns           Disable mDNS client, do not query remote services by mDNS</span><br><span style="color: hsl(120, 100%, 40%);">+  gateway-proxy  Disable gateway proxy for GSUP with unknown IMSIs</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy ?</span><br><span style="color: hsl(120, 100%, 40%);">+  IP  IP address of the remote HLR</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4 ?</span><br><span style="color: hsl(120, 100%, 40%);">+  [<1-65535>]  GSUP port number (omit for default 4222)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# do show mslookup?</span><br><span style="color: hsl(120, 100%, 40%);">+  mslookup  Distributed GSM / mslookup related information</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# do show mslookup ?</span><br><span style="color: hsl(120, 100%, 40%);">+  services  List configured service addresses as sent to remote mslookup requests</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# gateway-proxy 1.2.3.4</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# mdns</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# server</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service qwert at 123.45.67.89 qwert</span><br><span style="color: hsl(120, 100%, 40%);">+% Unknown command.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service qwert at qwert 1234</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: Invalid address for service qwert: qwert 1234</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service baz.bar at a:b:c::d 1819</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 999:999:999::999 9999</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service baz.bar at dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 2.2.2.2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# service baz.bar at 2222:2222:2222::2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# do show mslookup services</span><br><span style="color: hsl(120, 100%, 40%);">+Local GSUP HLR address returned in mslookup responses for local IMSIs: 127.0.0.1:4222</span><br><span style="color: hsl(120, 100%, 40%);">+service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+service baz.bar at a:b:c::d 1819</span><br><span style="color: hsl(120, 100%, 40%);">+msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 2.2.2.2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 2222:2222:2222::2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+ server</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns bind 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at a:b:c::d 1819</span><br><span style="color: hsl(120, 100%, 40%);">+ msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at 2.2.2.2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at 2222:2222:2222::2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+ client</span><br><span style="color: hsl(120, 100%, 40%);">+  gateway-proxy 1.2.3.4 4222</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns to 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service baz.bar</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service asdf</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: cannot remove service 'asdf'</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service baz.bar at dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: cannot remove service 'baz.bar' to dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service asdf at asdf asdf</span><br><span style="color: hsl(120, 100%, 40%);">+% Unknown command.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service asdf at asdf 3210</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: Invalid address for 'no service' asdf: asdf 3210</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# no service asdf at dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: cannot remove service 'asdf' to dd:cc:bb::a 3210</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server-msc)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service baz.bar at 2.2.2.2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: cannot remove service 'baz.bar' to 2.2.2.2 2222</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# no service baz.bar at a:b:c::d 1819</span><br><span style="color: hsl(120, 100%, 40%);">+% mslookup server: cannot remove service 'baz.bar' to a:b:c::d 1819</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# client</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# no gateway-proxy</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# do show mslookup services</span><br><span style="color: hsl(120, 100%, 40%);">+Local GSUP HLR address returned in mslookup responses for local IMSIs: 127.0.0.1:4222</span><br><span style="color: hsl(120, 100%, 40%);">+service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+ server</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns bind 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+ msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+ client</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns to 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-client)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup)# server</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# service gsup.hlr at 23.42.17.11 4223</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# do show mslookup services</span><br><span style="color: hsl(120, 100%, 40%);">+Local GSUP HLR address returned in mslookup responses for local IMSIs: 23.42.17.11:4223</span><br><span style="color: hsl(120, 100%, 40%);">+service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+service gsup.hlr at 23.42.17.11 4223</span><br><span style="color: hsl(120, 100%, 40%);">+msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoHLR(config-mslookup-server)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+mslookup</span><br><span style="color: hsl(120, 100%, 40%);">+ server</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns bind 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+ service foo.bar at 123.45.67.89 1011</span><br><span style="color: hsl(120, 100%, 40%);">+ service baz.bar at 121.31.41.5 1617</span><br><span style="color: hsl(120, 100%, 40%);">+ service gsup.hlr at 23.42.17.11 4223</span><br><span style="color: hsl(120, 100%, 40%);">+ msc MSC-1</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-23</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 76.54.32.10 1234</span><br><span style="color: hsl(120, 100%, 40%);">+  service baz.bar at 12.11.10.98 7654</span><br><span style="color: hsl(120, 100%, 40%);">+ msc msc-901-70-42</span><br><span style="color: hsl(120, 100%, 40%);">+  service foo.bar at 1.1.1.1 1111</span><br><span style="color: hsl(120, 100%, 40%);">+ client</span><br><span style="color: hsl(120, 100%, 40%);">+  mdns to 239.192.23.42 4266</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16209">change 16209</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-hlr/+/16209"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-hlr </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ife4a61d71926d08f310a1aeed9d9f1974f64178b </div>
<div style="display:none"> Gerrit-Change-Number: 16209 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-CC: Jenkins Builder </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>