<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16205">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add lu_fsm and osmo_gsup_req<br><br>These are seemingly orthogonal changes in one patch, because they are in fact<br>sufficiently intertwined that we are not willing to spend the time to separate<br>them. They are also refactoring changes, unlikely to make sense on their own.<br><br>** lu_fsm:<br><br>Attempting to make luop.c keep state about incoming GSUP requests made me find<br>shortcomings in several places:<br>- since it predates osmo_fsm, it is a state machine that does not strictly<br>  enforce the order of state transitions or the right sequence of incoming<br>  events.<br>- several places OSMO_ASSERT() on data received from the network.<br>- modifies the subscriber state before a LU is accepted.<br>- dead code about canceling a subscriber in a previous VLR. That would be a<br>  good thing to actually do, which should also be trivial now that we record<br>  vlr_name and sgsn_name, but I decided to remove the dead code for now.<br><br>To both step up the LU game *and* make it easier for me to integrate<br>osmo_gsup_req handling, I decided to create a lu_fsm, drawing from my, by now,<br>ample experience of writing osmo_fsms.<br><br>** osmo_gsup_req:<br><br>Prepare for D-GSM, where osmo-hlr will do proxy routing for remote HLRs /<br>communicate with remote MSCs via a proxy:<br><br>a) It is important that a response that osmo-hlr generates and that is sent<br>back to a requesting MSC contains all IEs that are needed to route it back to<br>the requester. Particularly source_name must become destination_name in the<br>response to be able to even reach the requesting MSC. Other fields are also<br>necessary to match, which were so far taken care of in individual numerous code<br>paths.<br><br>b) For some operations, the response to a GSUP request is generated<br>asynchronously (like Update Location Request -> Response, or taking the<br>response from an EUSE, or the upcoming proxying to a remote HLR). To be able to<br>feed a request message's information back into the response, we must thus keep<br>the request data around. Since struct osmo_gsup_message references a lot of<br>external data, usually with pointers directly into the received msgb, it is not<br>so trivial to pass GSUP message data around asynchronously, on its own.<br><br>osmo_gsup_req is the combined solution for both a and b: it keeps all data for<br>a GSUP message by taking ownership of the incoming msgb, and it provides an<br>explicit API "forcing" callers to respond with osmo_gsup_req_respond(), so that<br>all code paths trivially are definitely responding with the correct IEs set to<br>match the request's routing (by using osmo_gsup_make_response() recently added<br>to libosmocore).<br><br>Adjust all osmo-hlr code paths to use *only* osmo_gsup_req to respond to<br>incoming requests received on the GSUP server (above LU code being one of<br>them).<br><br>In fact, the same should be done on the client side. Hence osmo_gsup_req is<br>implemented in a server/client agnostic way, and is placed in<br>libosmo-gsupclient. As soon as we see routing errors in complex GSUP setups,<br>using osmo_gsup_req in the related GSUP client is likely to resolve those<br>problems without much thinking required beyond making all code paths use it.<br><br>libosmo-gsupclient is hence added to osmo-hlr binary's own library<br>dependencies. It would have been added by the D-GSM proxy routing anyway, we<br>are just doing it a little sooner.<br><br>** global_title.c / osmo_gt:<br><br>We so far handle a Global Title a.k.a. an IPA unit name as pointer + size, or<br>as just pointer with implicit talloc size. To ease working with GSUP peer<br>identification data, I require:<br><br>- a non-allocated storage of a Global Title. It brings the drawback of being<br>  size limited, but our current implementation is anyway only able to handle<br>  MSC and SGSN names of 31 characters (see struct hlr_subscriber).<br>- a single-argument handle for Global Title,<br>- easy to use utility functions like osmo_gt_name(), osmo_gt_cmp(), and copying<br>  by simple assignment, a = b.<br><br>Hence this patch adds a osmo_gt in global_title.h and global_title.c. Heavily<br>used in LU and osmo_gsup_req.<br><br>Change-Id: I3a8dff3d4a1cbe10d6ab08257a0138d6b2a082d9<br>---<br>M include/Makefile.am<br>A include/osmocom/gsupclient/global_title.h<br>A include/osmocom/gsupclient/gsup_req.h<br>M include/osmocom/hlr/Makefile.am<br>M include/osmocom/hlr/db.h<br>M include/osmocom/hlr/gsup_router.h<br>M include/osmocom/hlr/gsup_server.h<br>M include/osmocom/hlr/hlr.h<br>M include/osmocom/hlr/hlr_ussd.h<br>M include/osmocom/hlr/logging.h<br>A include/osmocom/hlr/lu_fsm.h<br>D include/osmocom/hlr/luop.h<br>M src/Makefile.am<br>M src/db.c<br>M src/db_hlr.c<br>M src/gsup_router.c<br>M src/gsup_send.c<br>M src/gsup_server.c<br>M src/gsupclient/Makefile.am<br>A src/gsupclient/global_title.c<br>M src/gsupclient/gsup_client.c<br>A src/gsupclient/gsup_req.c<br>M src/hlr.c<br>M src/hlr_ussd.c<br>M src/logging.c<br>A src/lu_fsm.c<br>D src/luop.c<br>M src/mslookup/mdns_record.c<br>M tests/db/Makefile.am<br>M tests/db/db_test.c<br>M tests/db/db_test.err<br>M tests/gsup_server/Makefile.am<br>M tests/test_nodes.vty<br>33 files changed, 1,227 insertions(+), 910 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/05/16205/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 9827950..91401e7 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -1,7 +1,9 @@</span><br><span> SUBDIRS = osmocom</span><br><span> </span><br><span> nobase_include_HEADERS = \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmocom/gsupclient/global_title.h \</span><br><span>  osmocom/gsupclient/gsup_client.h \</span><br><span style="color: hsl(120, 100%, 40%);">+    osmocom/gsupclient/gsup_req.h \</span><br><span>      osmocom/mslookup/mdns.h \</span><br><span>    osmocom/mslookup/mdns_sock.h \</span><br><span>       osmocom/mslookup/mslookup_client_fake.h \</span><br><span>diff --git a/include/osmocom/gsupclient/global_title.h b/include/osmocom/gsupclient/global_title.h</span><br><span>new file mode 100644</span><br><span>index 0000000..b10582a</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsupclient/global_title.h</span><br><span>@@ -0,0 +1,19 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Global Title: Arbitrary length blob, not necessarily zero-terminated.</span><br><span style="color: hsl(120, 100%, 40%);">+ * In osmo-hlr, struct hlr_subscriber is mostly used as static reference and cannot serve as talloc context, which is</span><br><span style="color: hsl(120, 100%, 40%);">+ * why this is also implemented as a fixed-maximum-size buffer instead of a talloc'd arbitrary sized buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * NOTE: The length of val may be extended in the future if it becomes necessary.</span><br><span style="color: hsl(120, 100%, 40%);">+ * At the time of writing, this holds IPA unit name strings of very limited length.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gt {</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t val[128];</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 osmo_gt_set(struct osmo_gt *gt, const uint8_t *val, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gt_set_str(struct osmo_gt *gt, const char *str_fmt, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gt_cmp(const struct osmo_gt *a, const struct osmo_gt *b);</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_gt_name(const struct osmo_gt *gt);</span><br><span>diff --git a/include/osmocom/gsupclient/gsup_req.h b/include/osmocom/gsupclient/gsup_req.h</span><br><span>new file mode 100644</span><br><span>index 0000000..29a222a</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsupclient/gsup_req.h</span><br><span>@@ -0,0 +1,90 @@</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/gsm/gsup.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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_GSUP_REQ_CAT_SRC(req, subsys, level, file, line, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGPSRC(subsys, level, file, line, "GSUP %u: %s: IMSI-%s %s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+               (req) ? (req)->nr : 0, \</span><br><span style="color: hsl(120, 100%, 40%);">+           (req) ? osmo_gt_name(&(req)->source_name) : "NULL", \</span><br><span style="color: hsl(120, 100%, 40%);">+                (req) ? (req)->gsup.imsi : "NULL", \</span><br><span style="color: hsl(120, 100%, 40%);">+             (req) ? osmo_gsup_message_type_name((req)->gsup.message_type) : "NULL", \</span><br><span style="color: hsl(120, 100%, 40%);">+                ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_GSUP_REQ_CAT(req, subsys, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_GSUP_REQ_CAT_SRC(req, subsys, level, __FILE__, __LINE__, fmt, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_GSUP_REQ_SRC(req, level, file, line, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_GSUP_REQ_CAT_SRC(req, DLGSUP, level, file, line, fmt, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_GSUP_REQ(req, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_GSUP_REQ_SRC(req, level, __FILE__, __LINE__, fmt, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*osmo_gsup_req_send_response_t)(struct osmo_gsup_req *req, struct osmo_gsup_message *response);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Keep track of an incoming request, to route back a response when it is ready.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Particularly, a GSUP response to a request should be made and/or checked by osmo_gsup_make_response(), for GSUP routing</span><br><span style="color: hsl(120, 100%, 40%);">+ * to work, and for session states to remain valid.</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%);">+      /* The incoming GSUP message in decoded form. */</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct osmo_gsup_message gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Decoding result code. If decoding failed, this will be != 0. */</span><br><span style="color: hsl(120, 100%, 40%);">+    int decode_rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* The ultimate source of this message: the source_name form the GSUP message, or, if not present, then the</span><br><span style="color: hsl(120, 100%, 40%);">+    * immediate GSUP peer. GSUP messages going via a proxy reflect the initial source in the source_name.</span><br><span style="color: hsl(120, 100%, 40%);">+         * This source_name is implicitly added to the routes for the conn the message was received on. */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gt source_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If the source_name is not an immediate GSUP peer, this is set to the closest intermediate peer between here</span><br><span style="color: hsl(120, 100%, 40%);">+         * and source_name. */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gt via_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Identify this request by number, for logging. */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* osmo_gsup_req can be used by both gsup_server and gsup_client. The individual method of actually sending a</span><br><span style="color: hsl(120, 100%, 40%);">+  * GSUP message is provided by this callback. */</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_gsup_req_send_response_t send_response_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* User supplied data pointer, may be used to provide context to send_response_cb(). */</span><br><span style="color: hsl(120, 100%, 40%);">+       void *cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* List entry that can be used to keep a list of osmo_gsup_req instances; not used directly by osmo_gsup_req.c,</span><br><span style="color: hsl(120, 100%, 40%);">+        * it is up to using implementations to keep a list. If this is non-NULL, osmo_gsup_req_free() calls</span><br><span style="color: hsl(120, 100%, 40%);">+   * llist_del() on this. */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* A decoded GSUP message still points into the received msgb. For a decoded osmo_gsup_message to remain valid,</span><br><span style="color: hsl(120, 100%, 40%);">+        * we also need to keep the msgb. */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gt *from_peer, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        osmo_gsup_req_send_response_t send_response_cb, void *cb_data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        struct llist_head *add_to_list);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_gsup_req_free(struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE) \</span><br><span style="color: hsl(120, 100%, 40%);">+     _osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE, __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,</span><br><span style="color: hsl(120, 100%, 40%);">+                      bool error, bool final_response, const char *file, int line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Call _osmo_gsup_req_respond_msgt() to convey the sender's source file and line in the logs. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE) \</span><br><span style="color: hsl(120, 100%, 40%);">+   _osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE, __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                              bool final_response, const char *file, int line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Log an error message, and call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define osmo_gsup_req_respond_err(REQ, CAUSE, FMT, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_GSUP_REQ(REQ, LOGL_ERROR, "%s: " FMT "\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                       get_value_string(gsm48_gmm_cause_names, CAUSE), ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+               _osmo_gsup_req_respond_err(REQ, CAUSE, __FILE__, __LINE__); \</span><br><span style="color: hsl(120, 100%, 40%);">+ } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+void _osmo_gsup_req_respond_err(struct osmo_gsup_req *req, enum gsm48_gmm_cause cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const char *file, int line);</span><br><span>diff --git a/include/osmocom/hlr/Makefile.am b/include/osmocom/hlr/Makefile.am</span><br><span>index 77a8764..532fa5d 100644</span><br><span>--- a/include/osmocom/hlr/Makefile.am</span><br><span>+++ b/include/osmocom/hlr/Makefile.am</span><br><span>@@ -9,6 +9,6 @@</span><br><span>      hlr_vty.h \</span><br><span>  hlr_vty_subscr.h \</span><br><span>   logging.h \</span><br><span style="color: hsl(0, 100%, 40%);">-     luop.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      lu_fsm.h \</span><br><span>   rand.h \</span><br><span>     $(NULL)</span><br><span>diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h</span><br><span>index eacc78e..592a976 100644</span><br><span>--- a/include/osmocom/hlr/db.h</span><br><span>+++ b/include/osmocom/hlr/db.h</span><br><span>@@ -3,6 +3,8 @@</span><br><span> #include <stdbool.h></span><br><span> #include <sqlite3.h></span><br><span> </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> struct hlr;</span><br><span> </span><br><span> enum stmt_idx {</span><br><span>@@ -151,13 +153,12 @@</span><br><span> int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_subscriber *subscr);</span><br><span> int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps);</span><br><span> int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,</span><br><span style="color: hsl(0, 100%, 40%);">-               const char *vlr_or_sgsn_number, bool is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+          const struct osmo_gt *vlr_name, bool is_ps,</span><br><span style="color: hsl(120, 100%, 40%);">+           const struct osmo_gt *via_proxy);</span><br><span> </span><br><span> int db_subscr_purge(struct db_context *dbc, const char *by_imsi,</span><br><span>               bool purge_val, bool is_ps);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! Call sqlite3_column_text() and copy result to a char[].</span><br><span>  * \param[out] buf  A char[] used as sizeof() arg(!) and osmo_strlcpy() target.</span><br><span>  * \param[in] stmt  An sqlite3_stmt*.</span><br><span>@@ -168,3 +169,14 @@</span><br><span>          const char *_txt = (const char *) sqlite3_column_text(stmt, idx); \</span><br><span>          osmo_strlcpy(buf, _txt, sizeof(buf)); \</span><br><span>      } while (0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Call sqlite3_column_text() and copy result to a struct osmo_gt.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] gt  A struct osmo_gt* to write to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] stmt  An sqlite3_stmt*.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] idx  Index in stmt's returned columns.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define copy_sqlite3_text_to_gt(gt, stmt, idx) \</span><br><span style="color: hsl(120, 100%, 40%);">+ do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *_txt = (const char *) sqlite3_column_text(stmt, idx); \</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_gt_set_str(gt, _txt); \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while (0)</span><br><span>diff --git a/include/osmocom/hlr/gsup_router.h b/include/osmocom/hlr/gsup_router.h</span><br><span>index 0fc10d0..e3023d1 100644</span><br><span>--- a/include/osmocom/hlr/gsup_router.h</span><br><span>+++ b/include/osmocom/hlr/gsup_router.h</span><br><span>@@ -3,6 +3,8 @@</span><br><span> #include <stdint.h></span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gsup_route {</span><br><span>      struct llist_head list;</span><br><span> </span><br><span>@@ -12,10 +14,12 @@</span><br><span> </span><br><span> struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,</span><br><span>                                         const uint8_t *addr, size_t addrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_conn *gsup_route_find_gt(struct osmo_gsup_server *gs, const struct osmo_gt *gt);</span><br><span> </span><br><span> struct gsup_route *gsup_route_find_by_conn(const struct osmo_gsup_conn *conn);</span><br><span> </span><br><span> /* add a new route for the given address to the given conn */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsup_route_add_gt(struct osmo_gsup_conn *conn, const struct osmo_gt *gt);</span><br><span> int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addrlen);</span><br><span> </span><br><span> /* delete all routes for the given connection */</span><br><span>@@ -24,3 +28,6 @@</span><br><span> int osmo_gsup_addr_send(struct osmo_gsup_server *gs,</span><br><span>                      const uint8_t *addr, size_t addrlen,</span><br><span>                         struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gsup_gt_send(struct osmo_gsup_server *gs, const struct osmo_gt *gt, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gsup_gt_enc_send(struct osmo_gsup_server *gs, const struct osmo_gt *gt,</span><br><span style="color: hsl(120, 100%, 40%);">+                   const struct osmo_gsup_message *gsup);</span><br><span>diff --git a/include/osmocom/hlr/gsup_server.h b/include/osmocom/hlr/gsup_server.h</span><br><span>index 14f5013..c3efea2 100644</span><br><span>--- a/include/osmocom/hlr/gsup_server.h</span><br><span>+++ b/include/osmocom/hlr/gsup_server.h</span><br><span>@@ -5,6 +5,8 @@</span><br><span> #include <osmocom/abis/ipa.h></span><br><span> #include <osmocom/abis/ipaccess.h></span><br><span> #include <osmocom/gsm/gsup.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> </span><br><span> #ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN</span><br><span> #define OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN       43 /* TS 24.008 10.5.4.7 */</span><br><span>@@ -22,9 +24,6 @@</span><br><span>      /* list of osmo_gsup_conn */</span><br><span>         struct llist_head clients;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  /* lu_operations list */</span><br><span style="color: hsl(0, 100%, 40%);">-        struct llist_head *luop;</span><br><span style="color: hsl(0, 100%, 40%);">-</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>@@ -45,10 +44,15 @@</span><br><span>      /* Set when Location Update is received: */</span><br><span>  bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */</span><br><span>       bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* The IPA unit name received on this link. Routes with more unit names serviced by this link may exist in</span><br><span style="color: hsl(120, 100%, 40%);">+     * osmo_gsup_server->routes, but this is the name the immediate peer identified as in the IPA handshake. */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gt peer_name;</span><br><span> };</span><br><span> </span><br><span> struct msgb *osmo_gsup_msgb_alloc(const char *label);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb *msg);</span><br><span> int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg);</span><br><span> int osmo_gsup_conn_ccm_get(const struct osmo_gsup_conn *clnt, uint8_t **addr,</span><br><span>                           uint8_t tag);</span><br><span>@@ -57,7 +61,6 @@</span><br><span>                                                  const char *ip_addr,</span><br><span>                                                 uint16_t tcp_port,</span><br><span>                                           osmo_gsup_read_cb_t read_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            struct llist_head *lu_op_lst,</span><br><span>                                                void *priv);</span><br><span> </span><br><span> void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);</span><br><span>diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h</span><br><span>index 18c4a1d..2214a8b 100644</span><br><span>--- a/include/osmocom/hlr/hlr.h</span><br><span>+++ b/include/osmocom/hlr/hlr.h</span><br><span>@@ -24,10 +24,16 @@</span><br><span> </span><br><span> #include <stdbool.h></span><br><span> #include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/ipa.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span> </span><br><span> #define HLR_DEFAULT_DB_FILE_PATH "hlr.db"</span><br><span> </span><br><span> struct hlr_euse;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_conn;</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_gsup_message_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct osmo_tdef g_hlr_tdefs[];</span><br><span> </span><br><span> struct hlr {</span><br><span>   /* GSUP server pointer */</span><br><span>@@ -43,6 +49,7 @@</span><br><span> </span><br><span>    /* Local bind addr */</span><br><span>        char *gsup_bind_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ipaccess_unit gsup_unit_name;</span><br><span> </span><br><span>     struct llist_head euse_list;</span><br><span>         struct hlr_euse *euse_default;</span><br><span>@@ -68,3 +75,4 @@</span><br><span> struct hlr_subscriber;</span><br><span> </span><br><span> void osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr);</span><br><span style="color: hsl(120, 100%, 40%);">+int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);</span><br><span>diff --git a/include/osmocom/hlr/hlr_ussd.h b/include/osmocom/hlr/hlr_ussd.h</span><br><span>index 08e810e..8b2e837 100644</span><br><span>--- a/include/osmocom/hlr/hlr_ussd.h</span><br><span>+++ b/include/osmocom/hlr/hlr_ussd.h</span><br><span>@@ -46,8 +46,8 @@</span><br><span>                                              struct hlr_euse *euse);</span><br><span> void ussd_route_del(struct hlr_ussd_route *rt);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_proc_ss_error(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+void rx_proc_ss_req(struct osmo_gsup_req *req);</span><br><span style="color: hsl(120, 100%, 40%);">+void rx_proc_ss_error(struct osmo_gsup_req *req);</span><br><span> </span><br><span> struct ss_session;</span><br><span> struct ss_request;</span><br><span>@@ -56,6 +56,5 @@</span><br><span> struct hlr_iuse {</span><br><span>         const char *name;</span><br><span>    /* call-back to be called for any incoming USSD messages for this IUSE */</span><br><span style="color: hsl(0, 100%, 40%);">-       int (*handle_ussd)(struct osmo_gsup_conn *conn, struct ss_session *ss,</span><br><span style="color: hsl(0, 100%, 40%);">-                     const struct osmo_gsup_message *gsup, const struct ss_request *req);</span><br><span style="color: hsl(120, 100%, 40%);">+       int (*handle_ussd)(struct ss_session *ss, const struct osmo_gsup_message *gsup, const struct ss_request *req);</span><br><span> };</span><br><span>diff --git a/include/osmocom/hlr/logging.h b/include/osmocom/hlr/logging.h</span><br><span>index 83f1acd..4e0a25c 100644</span><br><span>--- a/include/osmocom/hlr/logging.h</span><br><span>+++ b/include/osmocom/hlr/logging.h</span><br><span>@@ -9,6 +9,7 @@</span><br><span>      DAUC,</span><br><span>        DSS,</span><br><span>         DMSLOOKUP,</span><br><span style="color: hsl(120, 100%, 40%);">+    DLU,</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/lu_fsm.h b/include/osmocom/hlr/lu_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..f9a33bd</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hlr/lu_fsm.h</span><br><span>@@ -0,0 +1,2 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void lu_rx_gsup(struct osmo_gsup_req *req);</span><br><span>diff --git a/include/osmocom/hlr/luop.h b/include/osmocom/hlr/luop.h</span><br><span>deleted file mode 100644</span><br><span>index 77a1dec..0000000</span><br><span>--- a/include/osmocom/hlr/luop.h</span><br><span>+++ /dev/null</span><br><span>@@ -1,81 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/* OsmoHLR TX/RX lu operations */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(0, 100%, 40%);">- * All Rights Reserved</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Author: Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">- * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">- * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(0, 100%, 40%);">- * (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">- * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU Affero General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(0, 100%, 40%);">- * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#pragma once</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <stdbool.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/timer.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/gsup.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/db.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define CANCEL_TIMEOUT_SECS  30</span><br><span style="color: hsl(0, 100%, 40%);">-#define ISD_TIMEOUT_SECS      30</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum lu_state {</span><br><span style="color: hsl(0, 100%, 40%);">-       LU_S_NULL,</span><br><span style="color: hsl(0, 100%, 40%);">-      LU_S_LU_RECEIVED,</span><br><span style="color: hsl(0, 100%, 40%);">-       LU_S_CANCEL_SENT,</span><br><span style="color: hsl(0, 100%, 40%);">-       LU_S_CANCEL_ACK_RECEIVED,</span><br><span style="color: hsl(0, 100%, 40%);">-       LU_S_ISD_SENT,</span><br><span style="color: hsl(0, 100%, 40%);">-  LU_S_ISD_ACK_RECEIVED,</span><br><span style="color: hsl(0, 100%, 40%);">-  LU_S_COMPLETE,</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-extern const struct value_string lu_state_names[];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation {</span><br><span style="color: hsl(0, 100%, 40%);">- /*! entry in global list of location update operations */</span><br><span style="color: hsl(0, 100%, 40%);">-       struct llist_head list;</span><br><span style="color: hsl(0, 100%, 40%);">- /*! to which gsup_server do we belong */</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_server *gsup_server;</span><br><span style="color: hsl(0, 100%, 40%);">-   /*! state of the location update */</span><br><span style="color: hsl(0, 100%, 40%);">-     enum lu_state state;</span><br><span style="color: hsl(0, 100%, 40%);">-    /*! CS (false) or PS (true) Location Update? */</span><br><span style="color: hsl(0, 100%, 40%);">- bool is_ps;</span><br><span style="color: hsl(0, 100%, 40%);">-     /*! currently running timer */</span><br><span style="color: hsl(0, 100%, 40%);">-  struct osmo_timer_list timer;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   /*! subscriber related to this operation */</span><br><span style="color: hsl(0, 100%, 40%);">-     struct hlr_subscriber subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-   /*! peer VLR/SGSN starting the request */</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t *peer;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv);</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn);</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_statechg(struct lu_operation *luop, enum lu_state new_state);</span><br><span style="color: hsl(0, 100%, 40%);">-bool lu_op_fill_subscr(struct lu_operation *luop, struct db_context *dbc,</span><br><span style="color: hsl(0, 100%, 40%);">-                    const char *imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_by_imsi(const char *imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                              const struct llist_head *lst);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_error(struct lu_operation *luop, enum gsm48_gmm_cause cause);</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_ack(struct lu_operation *luop);</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_cancel_old(struct lu_operation *luop);</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_insert_subscr_data(struct lu_operation *luop);</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_del_subscr_data(struct lu_operation *luop);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_free(struct lu_operation *luop);</span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index f858ff0..3a83616 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -41,7 +41,6 @@</span><br><span>   auc.c \</span><br><span>      ctrl.c \</span><br><span>     db.c \</span><br><span style="color: hsl(0, 100%, 40%);">-  luop.c \</span><br><span>     db_auc.c \</span><br><span>   db_hlr.c \</span><br><span>   gsup_router.c \</span><br><span>@@ -53,9 +52,11 @@</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%);">+  lu_fsm.c \</span><br><span>   $(NULL)</span><br><span> </span><br><span> osmo_hlr_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(top_builddir)/src/gsupclient/libosmo-gsup-client.la \</span><br><span>      $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOVTY_LIBS) \</span><br><span>@@ -71,6 +72,7 @@</span><br><span>     logging.c \</span><br><span>  rand_urandom.c \</span><br><span>     dbd_decode_binary.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(srcdir)/gsupclient/global_title.c \</span><br><span>        $(NULL)</span><br><span> </span><br><span> osmo_hlr_db_tool_LDADD = \</span><br><span>diff --git a/src/db.c b/src/db.c</span><br><span>index 5e5ad35..e38bdaa 100644</span><br><span>--- a/src/db.c</span><br><span>+++ b/src/db.c</span><br><span>@@ -22,9 +22,11 @@</span><br><span> #include <stdbool.h></span><br><span> #include <sqlite3.h></span><br><span> #include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span> </span><br><span> #include <osmocom/hlr/logging.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "db_bootstrap.h"</span><br><span> </span><br><span> /* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */</span><br><span>diff --git a/src/db_hlr.c b/src/db_hlr.c</span><br><span>index b3e3887..0f9b367 100644</span><br><span>--- a/src/db_hlr.c</span><br><span>+++ b/src/db_hlr.c</span><br><span>@@ -28,6 +28,7 @@</span><br><span> #include <time.h></span><br><span> </span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span> #include <osmocom/crypt/auth.h></span><br><span> #include <osmocom/gsm/gsm23003.h></span><br><span> </span><br><span>@@ -36,8 +37,7 @@</span><br><span> #include <osmocom/hlr/logging.h></span><br><span> #include <osmocom/hlr/hlr.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/luop.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span> </span><br><span> #define LOGHLR(imsi, level, fmt, args ...)      LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)</span><br><span> </span><br><span>@@ -734,7 +734,8 @@</span><br><span>  *         -EIO on database errors.</span><br><span>  */</span><br><span> int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,</span><br><span style="color: hsl(0, 100%, 40%);">-             const char *vlr_or_sgsn_number, bool is_ps)</span><br><span style="color: hsl(120, 100%, 40%);">+           const struct osmo_gt *vlr_name, bool is_ps,</span><br><span style="color: hsl(120, 100%, 40%);">+           const struct osmo_gt *via_proxy)</span><br><span> {</span><br><span>       sqlite3_stmt *stmt;</span><br><span>  int rc, ret = 0;</span><br><span>@@ -746,7 +747,7 @@</span><br><span>       if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))</span><br><span>             return -EIO;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        if (!db_bind_text(stmt, "$number", vlr_or_sgsn_number))</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!db_bind_text(stmt, "$number", (char*)vlr_name->val))</span><br><span>               return -EIO;</span><br><span> </span><br><span>     /* execute the statement */</span><br><span>@@ -873,51 +874,3 @@</span><br><span> </span><br><span>       return ret;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Update nam_cs/nam_ps in the db and trigger notifications to GSUP clients.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in,out] hlr  Global hlr context.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] subscr   Subscriber from a fresh db_subscr_get_by_*() call.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] nam_val  True to enable CS/PS, false to disable.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[in] is_ps    True to enable/disable PS, false for CS.</span><br><span style="color: hsl(0, 100%, 40%);">- * \returns 0 on success, ENOEXEC if there is no need to change, a negative</span><br><span style="color: hsl(0, 100%, 40%);">- *          value on error.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct lu_operation *luop;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_conn *co;</span><br><span style="color: hsl(0, 100%, 40%);">-     bool is_val = is_ps? subscr->nam_ps : subscr->nam_cs;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (is_val == nam_val) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGHLR(subscr->imsi, LOGL_DEBUG, "Already has the requested value when asked to %s %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 nam_val ? "enable" : "disable", is_ps ? "PS" : "CS");</span><br><span style="color: hsl(0, 100%, 40%);">-            return ENOEXEC;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = db_subscr_nam(hlr->dbc, subscr->imsi, nam_val, is_ps);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc)</span><br><span style="color: hsl(0, 100%, 40%);">-         return rc > 0? -rc : rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* If we're disabling, send a notice out to the GSUP client that is</span><br><span style="color: hsl(0, 100%, 40%);">-  * responsible. Otherwise no need. */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (nam_val)</span><br><span style="color: hsl(0, 100%, 40%);">-            return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* FIXME: only send to single SGSN where latest update for IMSI came from */</span><br><span style="color: hsl(0, 100%, 40%);">-    llist_for_each_entry(co, &hlr->gs->clients, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-           luop = lu_op_alloc_conn(co);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (!luop) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    LOGHLR(subscr->imsi, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                            "Cannot notify GSUP client, cannot allocate lu_operation,"</span><br><span style="color: hsl(0, 100%, 40%);">-                            " for %s:%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                               co && co->conn && co->conn->server? co->conn->server->addr : "unset",</span><br><span style="color: hsl(0, 100%, 40%);">-                               co && co->conn && co->conn->server? co->conn->server->port : 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                       continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               luop->subscr = *subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-              lu_op_tx_del_subscr_data(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-         lu_op_free(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/gsup_router.c b/src/gsup_router.c</span><br><span>index adf3af7..671f787 100644</span><br><span>--- a/src/gsup_router.c</span><br><span>+++ b/src/gsup_router.c</span><br><span>@@ -47,6 +47,11 @@</span><br><span>     return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_conn *gsup_route_find_gt(struct osmo_gsup_server *gs, const struct osmo_gt *gt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return gsup_route_find(gs, gt->val, gt->len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Find a GSUP connection's route (to read the IPA address from the route).</span><br><span>  * \param[in] conn GSUP connection</span><br><span>  * \return GSUP route</span><br><span>@@ -67,10 +72,15 @@</span><br><span> int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addrlen)</span><br><span> {</span><br><span>       struct gsup_route *gr;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gsup_conn *exists_on_conn;</span><br><span> </span><br><span>   /* Check if we already have a route for this address */</span><br><span style="color: hsl(0, 100%, 40%);">- if (gsup_route_find(conn->server, addr, addrlen))</span><br><span style="color: hsl(0, 100%, 40%);">-            return -EEXIST;</span><br><span style="color: hsl(120, 100%, 40%);">+       exists_on_conn = gsup_route_find(conn->server, addr, addrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (exists_on_conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (exists_on_conn != conn)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -EEXIST;</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        /* allocate new route and populate it */</span><br><span>     gr = talloc_zero(conn->server, struct gsup_route);</span><br><span>@@ -86,6 +96,11 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int gsup_route_add_gt(struct osmo_gsup_conn *conn, const struct osmo_gt *gt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return gsup_route_add(conn, gt->val, gt->len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* delete all routes for the given connection */</span><br><span> int gsup_route_del_conn(struct osmo_gsup_conn *conn)</span><br><span> {</span><br><span>@@ -95,7 +110,7 @@</span><br><span>      llist_for_each_entry_safe(gr, gr2, &conn->server->routes, list) {</span><br><span>          if (gr->conn == conn) {</span><br><span>                   LOGP(DMAIN, LOGL_INFO, "Removing GSUP route for %s (GSUP disconnect)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                           gr->addr);</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_quote_str_c(OTC_SELECT, (char*)gr->addr, talloc_total_size(gr->addr)));</span><br><span>                      llist_del(&gr->list);</span><br><span>                         talloc_free(gr);</span><br><span>                     num_deleted++;</span><br><span>diff --git a/src/gsup_send.c b/src/gsup_send.c</span><br><span>index 29aeaa5..d650e48 100644</span><br><span>--- a/src/gsup_send.c</span><br><span>+++ b/src/gsup_send.c</span><br><span>@@ -42,7 +42,8 @@</span><br><span> </span><br><span>      conn = gsup_route_find(gs, addr, addrlen);</span><br><span>   if (!conn) {</span><br><span style="color: hsl(0, 100%, 40%);">-            DEBUGP(DLGSUP, "Cannot find route for addr %s\n", osmo_quote_str((const char*)addr, addrlen));</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLGSUP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "Cannot find route for addr %s\n", osmo_quote_str((const char*)addr, addrlen));</span><br><span>               msgb_free(msg);</span><br><span>              return -ENODEV;</span><br><span>      }</span><br><span>@@ -50,3 +51,41 @@</span><br><span>       return osmo_gsup_conn_send(conn, msg);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Send a msgb to a given address using routing.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] gs  gsup server</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] gt  IPA unit name of the client (SGSN, MSC/VLR, proxy).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg  message buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_gsup_gt_send(struct osmo_gsup_server *gs, const struct osmo_gt *gt, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (gt->val[gt->len - 1]) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Is not nul terminated. But for legacy reasons we (still) require that. */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (gt->len >= sizeof(gt->val)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGP(DLGSUP, LOGL_ERROR, "Global title (IPA unit name) is too long: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_gt_name(gt));</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%);">+             struct osmo_gt gt2 = *gt;</span><br><span style="color: hsl(120, 100%, 40%);">+             gt2.val[gt->len] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+           gt2.len++;</span><br><span style="color: hsl(120, 100%, 40%);">+            return osmo_gsup_addr_send(gs, gt2.val, gt2.len, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_gsup_addr_send(gs, gt->val, gt->len, msg);</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 osmo_gsup_gt_enc_send(struct osmo_gsup_server *gs, const struct osmo_gt *gt,</span><br><span style="color: hsl(120, 100%, 40%);">+                     const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg = osmo_gsup_msgb_alloc("GSUP Tx");</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_gsup_encode(msg, gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLGSUP, LOGL_ERROR, "IMSI-%s: Cannot encode GSUP: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    gsup->imsi, osmo_gsup_message_type_name(gsup->message_type));</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DLGSUP, LOGL_DEBUG, "IMSI-%s: Tx: %s\n", gsup->imsi, osmo_gsup_message_type_name(gsup->message_type));</span><br><span style="color: hsl(120, 100%, 40%);">+   return osmo_gsup_gt_send(gs, gt, msg);</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 ed1b285..fb162c0 100644</span><br><span>--- a/src/gsup_server.c</span><br><span>+++ b/src/gsup_server.c</span><br><span>@@ -26,10 +26,15 @@</span><br><span> #include <osmocom/abis/ipaccess.h></span><br><span> #include <osmocom/gsm/gsm48_ie.h></span><br><span> #include <osmocom/gsm/apn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm23003.h></span><br><span> </span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span> #include <osmocom/hlr/gsup_router.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_GSUP_CONN(conn, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+      (conn) ? osmo_gt_name(&(conn)->peer_name) : "NULL", ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct msgb *osmo_gsup_msgb_alloc(const char *label)</span><br><span> {</span><br><span>     struct msgb *msg = msgb_alloc_headroom(1024+16, 16, label);</span><br><span>@@ -57,6 +62,107 @@</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo_gsup_message *response)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_gsup_server *server = req->cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gsup_conn *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = osmo_gsup_msgb_alloc("GSUP Tx");</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%);">+     conn = gsup_route_find_gt(server, &req->source_name);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP client that sent this request was disconnected, cannot respond\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_free(msg);</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%);">+   rc = osmo_gsup_encode(msg, response);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_GSUP_REQ(req, LOGL_ERROR, "Unable to encode: {%s}\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_message_name_c(OTC_SELECT, response));</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</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%);">+   rc = osmo_gsup_conn_send(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_GSUP_CONN(conn, LOGL_ERROR, "Unable to send: %s\n", osmo_gsup_message_name_c(OTC_SELECT, response));</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_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gsup_req *req = osmo_gsup_req_new(conn->server, &conn->peer_name, msg, gsup_server_send_req_response,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 conn->server, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!req)</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%);">+        if (req->via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* The source of the GSUP message is not the immediate GSUP peer, but that peer is our proxy for that</span><br><span style="color: hsl(120, 100%, 40%);">+          * source. Add it to the routes for this conn (so we can route responses back). */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (gsup_route_add_gt(conn, &req->source_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOG_GSUP_REQ(req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "GSUP message received from %s via peer %s, but there already exists a"</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " different route to this source, message is not routable\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(&conn->peer_name));</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);</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%);">+   return 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%);">+/* Encode an error reponse to the given GSUP message with the given cause.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Determine the error message type via OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type).</span><br><span style="color: hsl(120, 100%, 40%);">+ * Only send an error response if the original message is a Request message.</span><br><span style="color: hsl(120, 100%, 40%);">+ * On failure, log an error, but don't return anything: if an error occurs while trying to report an earlier error,</span><br><span style="color: hsl(120, 100%, 40%);">+ * there is nothing we can do really except log the error (there are no callers that would use the return code).</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_gsup_conn_send_err_reply(struct osmo_gsup_conn *conn, 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_err;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg_out;</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%);">+     /* 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_err = (struct osmo_gsup_message){</span><br><span style="color: hsl(120, 100%, 40%);">+                .cause = cause,</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = osmo_gsup_make_response(&gsup_err, gsup_orig, true, true);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_GSUP_CONN(conn, LOGL_ERROR, "Invalid response (rc=%d): request={%s}, response={%s}\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        rc, osmo_gsup_message_name_c(OTC_SELECT, gsup_orig),</span><br><span style="color: hsl(120, 100%, 40%);">+                          osmo_gsup_message_name_c(OTC_SELECT, &gsup_err));</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 (gsup_orig->session_state != OSMO_GSUP_SESSION_STATE_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+              gsup_err.session_state = OSMO_GSUP_SESSION_STATE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msg_out = osmo_gsup_msgb_alloc("GSUP ERR response");</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_gsup_encode(msg_out, &gsup_err);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLGSUP, LOGL_ERROR, "%s: Unable to encode error response %s (rc=%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_quote_str(gsup_orig->imsi, -1), osmo_gsup_message_type_name(gsup_err.message_type),</span><br><span style="color: hsl(120, 100%, 40%);">+                   rc);</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(DLGSUP, LOGL_DEBUG, "%s: GSUP tx %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_quote_str(gsup_orig->imsi, -1), osmo_gsup_message_type_name(gsup_err.message_type));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = osmo_gsup_conn_send(conn, msg_out);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLGSUP, LOGL_ERROR, "%s: Unable to send error response %s (rc=%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_quote_str(gsup_orig->imsi, -1), osmo_gsup_message_type_name(gsup_err.message_type),</span><br><span style="color: hsl(120, 100%, 40%);">+                   rc);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int osmo_gsup_conn_oap_handle(struct osmo_gsup_conn *conn,</span><br><span>                          struct msgb *msg_rx)</span><br><span> {</span><br><span>@@ -202,10 +308,18 @@</span><br><span>            return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   gsup_route_add(clnt, addr, addr_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gt_set(&clnt->peer_name, addr, addr_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ gsup_route_add_gt(clnt, &clnt->peer_name);</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void osmo_gsup_conn_free(struct osmo_gsup_conn *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   gsup_route_del_conn(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_del(&conn->list);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn)</span><br><span> {</span><br><span>  struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data;</span><br><span>@@ -213,10 +327,7 @@</span><br><span>         LOGP(DLGSUP, LOGL_INFO, "Lost GSUP client %s:%d\n",</span><br><span>                conn->addr, conn->port);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      gsup_route_del_conn(clnt);</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_del(&clnt->list);</span><br><span style="color: hsl(0, 100%, 40%);">-  talloc_free(clnt);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_gsup_conn_free(clnt);</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -298,8 +409,7 @@</span><br><span> </span><br><span> struct osmo_gsup_server *</span><br><span> osmo_gsup_server_create(void *ctx, const char *ip_addr, uint16_t tcp_port,</span><br><span style="color: hsl(0, 100%, 40%);">-                 osmo_gsup_read_cb_t read_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                    struct llist_head *lu_op_lst, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_gsup_read_cb_t read_cb, void *priv)</span><br><span> {</span><br><span>        struct osmo_gsup_server *gsups;</span><br><span>      int rc;</span><br><span>@@ -325,8 +435,6 @@</span><br><span>        if (rc < 0)</span><br><span>               goto failed;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        gsups->luop = lu_op_lst;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  return gsups;</span><br><span> </span><br><span> failed:</span><br><span>@@ -367,6 +475,7 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /**</span><br><span>  * Populate a gsup message structure with an Insert Subscriber Data Message.</span><br><span>  * All required memory buffers for data pointed to by pointers in struct omso_gsup_message</span><br><span>@@ -383,39 +492,41 @@</span><br><span>  * \returns 0 on success, and negative on error.</span><br><span>  */</span><br><span> int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,</span><br><span style="color: hsl(0, 100%, 40%);">-                                           uint8_t *msisdn_enc, size_t msisdn_enc_size,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            uint8_t *apn_buf, size_t apn_buf_size,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          enum osmo_gsup_cn_domain cn_domain)</span><br><span style="color: hsl(120, 100%, 40%);">+                                               uint8_t *msisdn_enc, size_t msisdn_enc_size,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               uint8_t *apn_buf, size_t apn_buf_size,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               enum osmo_gsup_cn_domain cn_domain)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        int len;</span><br><span style="color: hsl(120, 100%, 40%);">+       int len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+       *gsup = (struct osmo_gsup_message){</span><br><span style="color: hsl(120, 100%, 40%);">+            .message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+       };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       gsup->message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST;</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN)</span><br><span style="color: hsl(0, 100%, 40%);">-            return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ENOSPC;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(msisdn_enc);</span><br><span style="color: hsl(0, 100%, 40%);">-        len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (len < 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);</span><br><span style="color: hsl(0, 100%, 40%);">-             return -ENOSPC;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       gsup->msisdn_enc = msisdn_enc;</span><br><span style="color: hsl(0, 100%, 40%);">-       gsup->msisdn_enc_len = len;</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(msisdn_enc);</span><br><span style="color: hsl(120, 100%, 40%);">+       len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (len < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+       gsup->msisdn_enc = msisdn_enc;</span><br><span style="color: hsl(120, 100%, 40%);">+       gsup->msisdn_enc_len = len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     #pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"</span><br><span style="color: hsl(120, 100%, 40%);">+       #pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       gsup->cn_domain = cn_domain;</span><br><span style="color: hsl(0, 100%, 40%);">- if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(apn_buf_size >= APN_MAXLEN);</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(apn_buf);</span><br><span style="color: hsl(0, 100%, 40%);">-           /* FIXME: PDP infos - use more fine-grained access control</span><br><span style="color: hsl(0, 100%, 40%);">-                 instead of wildcard APN */</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(120, 100%, 40%);">+       gsup->cn_domain = cn_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(apn_buf_size >= APN_MAXLEN);</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(apn_buf);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: PDP infos - use more fine-grained access control</span><br><span style="color: hsl(120, 100%, 40%);">+                  instead of wildcard APN */</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span> }</span><br><span>diff --git a/src/gsupclient/Makefile.am b/src/gsupclient/Makefile.am</span><br><span>index 4a449ec..111d20d 100644</span><br><span>--- a/src/gsupclient/Makefile.am</span><br><span>+++ b/src/gsupclient/Makefile.am</span><br><span>@@ -8,7 +8,11 @@</span><br><span> </span><br><span> lib_LTLIBRARIES = libosmo-gsup-client.la</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-libosmo_gsup_client_la_SOURCES = gsup_client.c</span><br><span style="color: hsl(120, 100%, 40%);">+libosmo_gsup_client_la_SOURCES = \</span><br><span style="color: hsl(120, 100%, 40%);">+        global_title.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      gsup_client.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       gsup_req.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(NULL)</span><br><span> </span><br><span> libosmo_gsup_client_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined</span><br><span> libosmo_gsup_client_la_LIBADD = $(TALLOC_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOABIS_LIBS)</span><br><span>diff --git a/src/gsupclient/global_title.c b/src/gsupclient/global_title.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b1d143b</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsupclient/global_title.c</span><br><span>@@ -0,0 +1,73 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.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%);">+int osmo_gt_set(struct osmo_gt *gt, const uint8_t *val, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!val || !len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           *gt = (struct osmo_gt){};</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%);">+     if (len > sizeof(gt->val))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+       gt->len = len;</span><br><span style="color: hsl(120, 100%, 40%);">+     memcpy(gt->val, val, len);</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 osmo_gt_set_str(struct osmo_gt *gt, const char *str_fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!str_fmt)</span><br><span style="color: hsl(120, 100%, 40%);">+         return osmo_gt_set(gt, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    va_start(ap, str_fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+        vsnprintf((char*)(gt->val), sizeof(gt->val), str_fmt, ap);</span><br><span style="color: hsl(120, 100%, 40%);">+      va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+   gt->len = strlen((char*)(gt->val))+1;</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 osmo_gt_cmp(const struct osmo_gt *a, const struct osmo_gt *b)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (a == b)</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!a)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!b)</span><br><span style="color: hsl(120, 100%, 40%);">+               return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!a->len && !b->len)</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!a->len && b->len)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!b->len && a->len)</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%);">+   if (a->len == b->len)</span><br><span style="color: hsl(120, 100%, 40%);">+           return memcmp(a->val, b->val, a->len);</span><br><span style="color: hsl(120, 100%, 40%);">+       else if (a->len < b->len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          cmp = memcmp(a->val, b->val, a->len);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!cmp)</span><br><span style="color: hsl(120, 100%, 40%);">+                     cmp = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+             return cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* a->len > b->len */</span><br><span style="color: hsl(120, 100%, 40%);">+                cmp = memcmp(a->val, b->val, b->len);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!cmp)</span><br><span style="color: hsl(120, 100%, 40%);">+                     cmp = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+              return cmp;</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%);">+/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_gt_name(const struct osmo_gt *gt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t len = gt->len;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!len)</span><br><span style="color: hsl(120, 100%, 40%);">+             return "";</span><br><span style="color: hsl(120, 100%, 40%);">+  if (gt->val[len-1] == '\0')</span><br><span style="color: hsl(120, 100%, 40%);">+                len--;</span><br><span style="color: hsl(120, 100%, 40%);">+        return osmo_escape_str_c(OTC_SELECT, (char*)gt->val, len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gsupclient/gsup_client.c b/src/gsupclient/gsup_client.c</span><br><span>index 814d5a2..52985c9 100644</span><br><span>--- a/src/gsupclient/gsup_client.c</span><br><span>+++ b/src/gsupclient/gsup_client.c</span><br><span>@@ -291,14 +291,15 @@</span><br><span>        if (rc != 0)</span><br><span>                 goto failed;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        gsupc->link = ipa_client_conn_create(gsupc,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       /* no e1inp */ NULL,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            0,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      ip_addr, tcp_port,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      gsup_client_updown_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          gsup_client_read_cb,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            /* default write_cb */ NULL,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            gsupc);</span><br><span style="color: hsl(120, 100%, 40%);">+  gsupc->link = ipa_client_conn_create2(gsupc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             /* no e1inp */ NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            /* no specific local IP:port */ NULL, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              ip_addr, tcp_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            gsup_client_updown_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gsup_client_read_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* default write_cb */ NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          gsupc);</span><br><span>        if (!gsupc->link)</span><br><span>                 goto failed;</span><br><span> </span><br><span>diff --git a/src/gsupclient/gsup_req.c b/src/gsupclient/gsup_req.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1f3aab1</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsupclient/gsup_req.c</span><br><span>@@ -0,0 +1,152 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+/*! Create a new osmo_gsup_req record, decode GSUP and add to a provided list of requests.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function takes ownership of the msgb, which will, on success, be owned by the returned osmo_gsup_req instance</span><br><span style="color: hsl(120, 100%, 40%);">+ * until osmo_gsup_req_free(). If a decoding error occurs, send an error response immediately, and return NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * When this function returns, the original sender is found in req->source_name. If this is not the immediate peer name,</span><br><span style="color: hsl(120, 100%, 40%);">+ * then req->via_proxy is set to the immediate peer, and it is the responsibility of the caller to add req->source_name</span><br><span style="color: hsl(120, 100%, 40%);">+ * to the GSUP routes that are serviced by req->via_proxy (usually not relevant for clients with a single GSUP conn).</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Note: osmo_gsup_req API makes use of OTC_SELECT to allocate volatile buffers for logging. Use of</span><br><span style="color: hsl(120, 100%, 40%);">+ * osmo_select_main_ctx() is mandatory when using osmo_gsup_req.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] ctx  Talloc context for allocation of the new request.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] from_peer  The IPA unit name of the immediate GSUP peer from which this msgb was received.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] msg  The GSUP message buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] send_response_cb  User specific method to send a GSUP response message, invoked upon</span><br><span style="color: hsl(120, 100%, 40%);">+ *                               osmo_gsup_req_respond*() functions.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] cb_data  Context data to be used freely by the caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] add_to_list  List to which to append this request, or NULL for no list.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return a newly allocated osmo_gsup_req, or NULL on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gt *from_peer, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     osmo_gsup_req_send_response_t send_response_cb, void *cb_data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        struct llist_head *add_to_list)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    static unsigned int next_req_nr = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_gsup_req *req;</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%);">+     if (!msgb_l2(msg) || !msgb_l2len(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: missing or empty L2 data\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_gt_name(from_peer));</span><br><span style="color: hsl(120, 100%, 40%);">+                msgb_free(msg);</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%);">+   req = talloc_zero(ctx, struct osmo_gsup_req);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(req);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Note: req->gsup is declared const, so that the incoming message cannot be modified by handlers. */</span><br><span style="color: hsl(120, 100%, 40%);">+      req->nr = next_req_nr++;</span><br><span style="color: hsl(120, 100%, 40%);">+   req->msg = msg;</span><br><span style="color: hsl(120, 100%, 40%);">+    req->send_response_cb = send_response_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+  req->cb_data = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (from_peer)</span><br><span style="color: hsl(120, 100%, 40%);">+                req->source_name = *from_peer;</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = osmo_gsup_decode(msgb_l2(req->msg), msgb_l2len(req->msg), (struct osmo_gsup_message*)&req->gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: cannot decode (rc=%d)\n", osmo_gt_name(from_peer), rc);</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_gsup_req_free(req);</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%);">+   LOG_GSUP_REQ(req, LOGL_DEBUG, "new request: {%s}\n", osmo_gsup_message_name_c(OTC_SELECT, &req->gsup));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (req->gsup.source_name_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (osmo_gt_set(&req->source_name, req->gsup.source_name, req->gsup.source_name_len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DLGSUP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "Rx GSUP from %s: failed to decode source_name, message is not routable\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_gt_name(from_peer));</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);</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%);">+           /* The source of the GSUP message is not the immediate GSUP peer; the peer is our proxy for that source.</span><br><span style="color: hsl(120, 100%, 40%);">+               */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (osmo_gt_cmp(&req->source_name, from_peer))</span><br><span style="color: hsl(120, 100%, 40%);">+                 req->via_proxy = *from_peer;</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(req->gsup.imsi)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "invalid IMSI: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   osmo_quote_str(req->gsup.imsi, -1));</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%);">+   if (add_to_list)</span><br><span style="color: hsl(120, 100%, 40%);">+              llist_add_tail(&req->entry, add_to_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      return 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 osmo_gsup_req_free(struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       LOG_GSUP_REQ(req, LOGL_DEBUG, "free\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    if (req->msg)</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(req->msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (req->entry.prev)</span><br><span style="color: hsl(120, 100%, 40%);">+               llist_del(&req->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(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 _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,</span><br><span style="color: hsl(120, 100%, 40%);">+                        bool error, bool final_response, const char *file, int line)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = osmo_gsup_make_response(response, &req->gsup, error, final_response);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOG_GSUP_REQ_SRC(req, LOGL_ERROR, file, line, "Invalid response (rc=%d): {%s}\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            rc, osmo_gsup_message_name_c(OTC_SELECT, response));</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         goto exit_cleanup;</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->send_response_cb) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_GSUP_REQ_SRC(req, LOGL_ERROR, file, line, "No send_response_cb set, cannot send: {%s}\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                osmo_gsup_message_name_c(OTC_SELECT, response));</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         goto exit_cleanup;</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_GSUP_REQ_SRC(req, LOGL_DEBUG, file, line, "Tx response: {%s}\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_gsup_message_name_c(OTC_SELECT, response));</span><br><span style="color: hsl(120, 100%, 40%);">+     req->send_response_cb(req, response);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+exit_cleanup:</span><br><span style="color: hsl(120, 100%, 40%);">+     if (final_response)</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_gsup_req_free(req);</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%);">+int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                         bool final_response, const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_message response = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .message_type = message_type,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+    return _osmo_gsup_req_respond(req, &response, OSMO_GSUP_IS_MSGT_ERROR(message_type), final_response,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    file, line);</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_gsup_req_respond_err(struct osmo_gsup_req *req, enum gsm48_gmm_cause cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gsup_message response = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .cause = cause,</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%);">+  /* 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(req->gsup.message_type)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_gsup_req_free(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%);">+   osmo_gsup_req_respond(req, &response, true, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/hlr.c b/src/hlr.c</span><br><span>index 763ee66..d1647a0 100644</span><br><span>--- a/src/hlr.c</span><br><span>+++ b/src/hlr.c</span><br><span>@@ -35,8 +35,9 @@</span><br><span> #include <osmocom/gsm/apn.h></span><br><span> #include <osmocom/gsm/gsm48_ie.h></span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm23003.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span> #include <osmocom/hlr/hlr.h></span><br><span> #include <osmocom/hlr/ctrl.h></span><br><span>@@ -44,14 +45,20 @@</span><br><span> #include <osmocom/hlr/gsup_server.h></span><br><span> #include <osmocom/hlr/gsup_router.h></span><br><span> #include <osmocom/hlr/rand.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/luop.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/lu_fsm.h></span><br><span> </span><br><span> struct hlr *g_hlr;</span><br><span> static void *hlr_ctx = NULL;</span><br><span> static int quit = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_tdef g_hlr_tdefs[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    /* 4222 is also the OSMO_GSUP_PORT */</span><br><span style="color: hsl(120, 100%, 40%);">+ { .T = -4222, .default_val = 30, .desc = "GSUP Update Location timeout" },</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> /* Trigger 'Insert Subscriber Data' messages to all connected GSUP clients.</span><br><span>  *</span><br><span>  * \param[in] subscr  A subscriber we have new data to send for.</span><br><span>@@ -69,6 +76,8 @@</span><br><span>                return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: send only to current vlr_number and sgsn_number */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       llist_for_each_entry(co, &g_hlr->gs->clients, list) {</span><br><span>              struct osmo_gsup_message gsup = { };</span><br><span>                 uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];</span><br><span>@@ -222,136 +231,92 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Update nam_cs/nam_ps in the db and trigger notifications to GSUP clients.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in,out] hlr  Global hlr context.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] subscr   Subscriber from a fresh db_subscr_get_by_*() call.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] nam_val  True to enable CS/PS, false to disable.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] is_ps    True to enable/disable PS, false for CS.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 on success, ENOEXEC if there is no need to change, a negative</span><br><span style="color: hsl(120, 100%, 40%);">+ *          value on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps)</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%);">+       bool is_val = is_ps? subscr->nam_ps : subscr->nam_cs;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gt vlr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_message gsup_del_data = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .message_type = OSMO_GSUP_MSGT_DELETE_DATA_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_STRLCPY_ARRAY(gsup_del_data.imsi, subscr->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (is_val == nam_val) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DAUC, LOGL_DEBUG, "IMSI-%s: Already has the requested value when asked to %s %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 subscr->imsi, nam_val ? "enable" : "disable", is_ps ? "PS" : "CS");</span><br><span style="color: hsl(120, 100%, 40%);">+           return ENOEXEC;</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 = db_subscr_nam(hlr->dbc, subscr->imsi, nam_val, is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               return rc > 0? -rc : rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If we're disabling, send a notice out to the GSUP client that is</span><br><span style="color: hsl(120, 100%, 40%);">+        * responsible. Otherwise no need. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nam_val)</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%);">+   if (subscr->vlr_number && osmo_gt_set_str(&vlr_name, subscr->vlr_number))</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_gsup_gt_enc_send(g_hlr->gs, &vlr_name, &gsup_del_data);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (subscr->sgsn_number && osmo_gt_set_str(&vlr_name, subscr->sgsn_number))</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_gt_enc_send(g_hlr->gs, &vlr_name, &gsup_del_data);</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> /***********************************************************************</span><br><span>  * Send Auth Info handling</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span> /* process an incoming SAI request */</span><br><span style="color: hsl(0, 100%, 40%);">-static int rx_send_auth_info(struct osmo_gsup_conn *conn,</span><br><span style="color: hsl(0, 100%, 40%);">-                          const struct osmo_gsup_message *gsup,</span><br><span style="color: hsl(0, 100%, 40%);">-                           struct db_context *dbc)</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct osmo_gsup_message gsup_out;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct msgb *msg_out;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_gsup_message gsup_out = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span>   int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     subscr_create_on_demand(gsup->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+       subscr_create_on_demand(req->gsup.imsi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* initialize return message structure */</span><br><span style="color: hsl(0, 100%, 40%);">-       memset(&gsup_out, 0, sizeof(gsup_out));</span><br><span style="color: hsl(0, 100%, 40%);">-     memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  rc = db_get_auc(dbc, gsup->imsi, conn->auc_3g_ind,</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = db_get_auc(g_hlr->dbc, req->gsup.imsi, auc_3g_ind,</span><br><span>                        gsup_out.auth_vectors,</span><br><span>                       ARRAY_SIZE(gsup_out.auth_vectors),</span><br><span style="color: hsl(0, 100%, 40%);">-                      gsup->rand, gsup->auts);</span><br><span style="color: hsl(120, 100%, 40%);">+                        req->gsup.rand, req->gsup.auts);</span><br><span>       if (rc <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;</span><br><span>                 switch (rc) {</span><br><span>                case 0:</span><br><span>                      /* 0 means "0 tuples generated", which shouldn't happen.</span><br><span>                        * Treat the same as "no auth data". */</span><br><span>            case -ENOKEY:</span><br><span style="color: hsl(0, 100%, 40%);">-                   LOGP(DAUC, LOGL_NOTICE, "%s: IMSI known, but has no auth data;"</span><br><span style="color: hsl(0, 100%, 40%);">-                            " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                             gsup->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                    gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  "IMSI known, but has no auth data;"</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");</span><br><span style="color: hsl(120, 100%, 40%);">+                  return rc;</span><br><span>           case -ENOENT:</span><br><span style="color: hsl(0, 100%, 40%);">-                   LOGP(DAUC, LOGL_NOTICE, "%s: IMSI not known\n", gsup->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                       gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");</span><br><span style="color: hsl(120, 100%, 40%);">+                     return rc;</span><br><span>           default:</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGP(DAUC, LOGL_ERROR, "%s: failure to look up IMSI in db\n", gsup->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                 gsup_out.cause = GMM_CAUSE_NET_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span>           }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT;</span><br><span style="color: hsl(0, 100%, 40%);">-           gsup_out.num_auth_vectors = rc;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+     gsup_out.num_auth_vectors = rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     msg_out = osmo_gsup_msgb_alloc("GSUP AUC response");</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo_gsup_encode(msg_out, &gsup_out);</span><br><span style="color: hsl(0, 100%, 40%);">-       return osmo_gsup_conn_send(conn, msg_out);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_gsup_req_respond(req, &gsup_out, false, true);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * LU Operation State / Structure</span><br><span style="color: hsl(0, 100%, 40%);">- ***********************************************************************/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static LLIST_HEAD(g_lu_ops);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Receive Cancel Location Result from old VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_rx_cancel_old_ack(struct lu_operation *luop,</span><br><span style="color: hsl(0, 100%, 40%);">-                       const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Receive Update Location Request, creates new lu_operation */</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_upd_loc_req(struct osmo_gsup_conn *conn, struct osmo_gsup_req *req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(luop->state == LU_S_CANCEL_SENT);</span><br><span style="color: hsl(0, 100%, 40%);">-        /* FIXME: Check for spoofing */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_del(&luop->timer);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* FIXME */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     lu_op_tx_insert_subscr_data(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Receive Insert Subscriber Data Result from new VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-static void lu_op_rx_insert_subscr_data_ack(struct lu_operation *luop,</span><br><span style="color: hsl(0, 100%, 40%);">-                             const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(luop->state == LU_S_ISD_SENT);</span><br><span style="color: hsl(0, 100%, 40%);">-   /* FIXME: Check for spoofing */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_del(&luop->timer);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* Subscriber_Present_HLR */</span><br><span style="color: hsl(0, 100%, 40%);">-    /* CS only: Check_SS_required? -> MAP-FW-CHECK_SS_IND.req */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Send final ACK towards inquiring VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_tx_ack(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Receive GSUP message for given \ref lu_operation */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_rx_gsup(struct lu_operation *luop,</span><br><span style="color: hsl(0, 100%, 40%);">-                  const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        switch (gsup->message_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-        case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:</span><br><span style="color: hsl(0, 100%, 40%);">-          /* FIXME */</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:</span><br><span style="color: hsl(0, 100%, 40%);">-         lu_op_rx_insert_subscr_data_ack(luop, gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:</span><br><span style="color: hsl(0, 100%, 40%);">-              /* FIXME */</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:</span><br><span style="color: hsl(0, 100%, 40%);">-             lu_op_rx_cancel_old_ack(luop, gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DMAIN, LOGL_ERROR, "Unhandled GSUP msg_type 0x%02x\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   gsup->message_type);</span><br><span style="color: hsl(0, 100%, 40%);">-         break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Receive Update Location Request, creates new \ref lu_operation */</span><br><span style="color: hsl(0, 100%, 40%);">-static int rx_upd_loc_req(struct osmo_gsup_conn *conn,</span><br><span style="color: hsl(0, 100%, 40%);">-                     const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct hlr_subscriber *subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct lu_operation *luop = lu_op_alloc_conn(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!luop) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DMAIN, LOGL_ERROR, "LU REQ from conn without addr?\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       subscr = &luop->subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  lu_op_statechg(luop, LU_S_LU_RECEIVED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (gsup->cn_domain) {</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (req->gsup.cn_domain) {</span><br><span>    case OSMO_GSUP_CN_DOMAIN_CS:</span><br><span>                 conn->supports_cs = true;</span><br><span>                 break;</span><br><span>@@ -362,144 +327,64 @@</span><br><span>               * a request, the PS Domain is assumed." */</span><br><span>     case OSMO_GSUP_CN_DOMAIN_PS:</span><br><span>                 conn->supports_ps = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            luop->is_ps = true;</span><br><span>               break;</span><br><span>       }</span><br><span style="color: hsl(0, 100%, 40%);">-       llist_add(&luop->list, &g_lu_ops);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       subscr_create_on_demand(gsup->imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+       subscr_create_on_demand(req->gsup.imsi);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* check if subscriber is known at all */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!lu_op_fill_subscr(luop, g_hlr->dbc, gsup->imsi)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* Send Error back: Subscriber Unknown in HLR */</span><br><span style="color: hsl(0, 100%, 40%);">-                osmo_strlcpy(luop->subscr.imsi, gsup->imsi, sizeof(luop->subscr.imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-                lu_op_tx_error(luop, GMM_CAUSE_IMSI_UNKNOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-           return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Check if subscriber is generally permitted on CS or PS</span><br><span style="color: hsl(0, 100%, 40%);">-        * service (as requested) */</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!luop->is_ps && !luop->subscr.nam_cs) {</span><br><span style="color: hsl(0, 100%, 40%);">-               lu_op_tx_error(luop, GMM_CAUSE_PLMN_NOTALLOWED);</span><br><span style="color: hsl(0, 100%, 40%);">-                return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       } else if (luop->is_ps && !luop->subscr.nam_ps) {</span><br><span style="color: hsl(0, 100%, 40%);">-         lu_op_tx_error(luop, GMM_CAUSE_GPRS_NOTALLOWED);</span><br><span style="color: hsl(0, 100%, 40%);">-                return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* TODO: Set subscriber tracing = deactive in VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">-  /* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (luop->is_ps == false &&</span><br><span style="color: hsl(0, 100%, 40%);">-      strcmp(subscr->vlr_number, vlr_number)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                lu_op_tx_cancel_old(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-      } else if (luop->is_ps == true &&</span><br><span style="color: hsl(0, 100%, 40%);">-               strcmp(subscr->sgsn_number, sgsn_number)) {</span><br><span style="color: hsl(0, 100%, 40%);">-               lu_op_tx_cancel_old(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-      } else</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing %s = %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number",</span><br><span style="color: hsl(0, 100%, 40%);">-             osmo_quote_str((const char*)luop->peer, -1));</span><br><span style="color: hsl(0, 100%, 40%);">-   if (db_subscr_lu(g_hlr->dbc, subscr->id, (const char *)luop->peer, luop->is_ps))</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DAUC, LOGL_ERROR, "IMSI='%s': Cannot update %s in the database\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* TODO: Subscriber allowed to roam in PLMN? */</span><br><span style="color: hsl(0, 100%, 40%);">- /* TODO: Update RoutingInfo */</span><br><span style="color: hsl(0, 100%, 40%);">-  /* TODO: Reset Flag MS Purged (cs/ps) */</span><br><span style="color: hsl(0, 100%, 40%);">-        /* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_tx_insert_subscr_data(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+    lu_rx_gsup(req);</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int rx_purge_ms_req(struct osmo_gsup_conn *conn,</span><br><span style="color: hsl(0, 100%, 40%);">-                          const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_purge_ms_req(struct osmo_gsup_req *req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct osmo_gsup_message gsup_reply = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-      struct msgb *msg_out;</span><br><span style="color: hsl(0, 100%, 40%);">-   bool is_ps = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   bool is_ps = (req->gsup.cn_domain != OSMO_GSUP_CN_DOMAIN_CS);</span><br><span>     int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-           is_ps ? "PS" : "CS");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)</span><br><span style="color: hsl(0, 100%, 40%);">-               is_ps = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_GSUP_REQ_CAT(req, DAUC, LOGL_INFO, "Purge MS (%s)\n", is_ps ? "PS" : "CS");</span><br><span> </span><br><span>    /* FIXME: check if the VLR that sends the purge is the same that</span><br><span>      * we have on record. Only update if yes */</span><br><span> </span><br><span>      /* Perform the actual update of the DB */</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = db_subscr_purge(g_hlr->dbc, gsup->imsi, true, is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = db_subscr_purge(g_hlr->dbc, req->gsup.imsi, true, is_ps);</span><br><span> </span><br><span>     if (rc == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-            gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;</span><br><span style="color: hsl(0, 100%, 40%);">-       else if (rc == -ENOENT) {</span><br><span style="color: hsl(0, 100%, 40%);">-               gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;</span><br><span style="color: hsl(0, 100%, 40%);">-                gsup_reply.cause = GMM_CAUSE_IMSI_UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-      } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;</span><br><span style="color: hsl(0, 100%, 40%);">-                gsup_reply.cause = GMM_CAUSE_NET_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msg_out = osmo_gsup_msgb_alloc("GSUP AUC response");</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo_gsup_encode(msg_out, &gsup_reply);</span><br><span style="color: hsl(0, 100%, 40%);">-     return osmo_gsup_conn_send(conn, msg_out);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_PURGE_MS_RESULT, true);</span><br><span style="color: hsl(120, 100%, 40%);">+        else if (rc == -ENOENT)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "db error");</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int gsup_send_err_reply(struct osmo_gsup_conn *conn, const char *imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                enum osmo_gsup_message_type type_in, uint8_t err_cause)</span><br><span style="color: hsl(120, 100%, 40%);">+static int rx_check_imei_req(struct osmo_gsup_req *req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   int type_err = OSMO_GSUP_TO_MSGT_ERROR(type_in);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_message gsup_reply = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-      struct msgb *msg_out;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_STRLCPY_ARRAY(gsup_reply.imsi, imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-      gsup_reply.message_type = type_err;</span><br><span style="color: hsl(0, 100%, 40%);">-     gsup_reply.cause = err_cause;</span><br><span style="color: hsl(0, 100%, 40%);">-   msg_out = osmo_gsup_msgb_alloc("GSUP ERR response");</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(msg_out);</span><br><span style="color: hsl(0, 100%, 40%);">-   osmo_gsup_encode(msg_out, &gsup_reply);</span><br><span style="color: hsl(0, 100%, 40%);">-     LOGP(DMAIN, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(type_err));</span><br><span style="color: hsl(0, 100%, 40%);">-   return osmo_gsup_conn_send(conn, msg_out);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int rx_check_imei_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct osmo_gsup_message gsup_reply = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-      struct msgb *msg_out;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_gsup_message gsup_reply;</span><br><span>         char imei[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1] = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_gsup_message *gsup = &req->gsup;</span><br><span>    int rc;</span><br><span> </span><br><span>  /* Require IMEI */</span><br><span>   if (!gsup->imei_enc) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DMAIN, LOGL_ERROR, "%s: missing IMEI\n", gsup->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-         gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "missing IMEI");</span><br><span>           return -1;</span><br><span>   }</span><br><span> </span><br><span>        /* Decode IMEI (fails if IMEI is too long) */</span><br><span>        rc = gsm48_decode_bcd_number2(imei, sizeof(imei), gsup->imei_enc, gsup->imei_enc_len, 0);</span><br><span>      if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DMAIN, LOGL_ERROR, "%s: failed to decode IMEI (rc: %i)\n", gsup->imsi, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-           gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         "failed to decode IMEI %s (rc: %d)",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        osmo_hexdump_c(OTC_SELECT, gsup->imei_enc, gsup->imei_enc_len),</span><br><span style="color: hsl(120, 100%, 40%);">+                                         rc);</span><br><span>               return -1;</span><br><span>   }</span><br><span> </span><br><span>        /* Check if IMEI is too short */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (strlen(imei) != GSM23003_IMEI_NUM_DIGITS_NO_CHK) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DMAIN, LOGL_ERROR, "%s: wrong encoded IMEI length (IMEI: '%s', %lu, %i)\n", gsup->imsi, imei,</span><br><span style="color: hsl(0, 100%, 40%);">-              strlen(imei), GSM23003_IMEI_NUM_DIGITS_NO_CHK);</span><br><span style="color: hsl(0, 100%, 40%);">-            gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!osmo_imei_str_valid(imei, false)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         "invalid IMEI: %s", osmo_quote_str_c(OTC_SELECT, imei, -1));</span><br><span>             return -1;</span><br><span>   }</span><br><span> </span><br><span>@@ -509,7 +394,7 @@</span><br><span>  if (g_hlr->store_imei) {</span><br><span>          LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing IMEI = %s\n", gsup->imsi, imei);</span><br><span>             if (db_subscr_update_imei_by_imsi(g_hlr->dbc, gsup->imsi, imei) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "Failed to store IMEI in HLR db");</span><br><span>                         return -1;</span><br><span>           }</span><br><span>    } else {</span><br><span>@@ -517,176 +402,135 @@</span><br><span>           LOGP(DMAIN, LOGL_INFO, "IMSI='%s': has IMEI = %s (consider setting 'store-imei')\n", gsup->imsi, imei);</span><br><span>                 struct hlr_subscriber subscr;</span><br><span>                if (db_subscr_get_by_imsi(g_hlr->dbc, gsup->imsi, &subscr) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "IMSI unknown");</span><br><span>                   return -1;</span><br><span>           }</span><br><span>    }</span><br><span> </span><br><span>        /* Accept all IMEIs */</span><br><span style="color: hsl(0, 100%, 40%);">-  gsup_reply.imei_result = OSMO_GSUP_IMEI_RESULT_ACK;</span><br><span style="color: hsl(0, 100%, 40%);">-     gsup_reply.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT;</span><br><span style="color: hsl(0, 100%, 40%);">-     msg_out = osmo_gsup_msgb_alloc("GSUP Check_IMEI response");</span><br><span style="color: hsl(0, 100%, 40%);">-   memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_gsup_encode(msg_out, &gsup_reply);</span><br><span style="color: hsl(0, 100%, 40%);">-     return osmo_gsup_conn_send(conn, msg_out);</span><br><span style="color: hsl(120, 100%, 40%);">+    gsup_reply = (struct osmo_gsup_message){</span><br><span style="color: hsl(120, 100%, 40%);">+              .message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,</span><br><span style="color: hsl(120, 100%, 40%);">+             .imei_result = OSMO_GSUP_IMEI_RESULT_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+    return osmo_gsup_req_respond(req, &gsup_reply, false, true);</span><br><span> }</span><br><span> </span><br><span> static char namebuf[255];</span><br><span> #define LOGP_GSUP_FWD(gsup, level, fmt, args ...) \</span><br><span>        LOGP(DMAIN, level, "Forward %s (class=%s, IMSI=%s, %s->%s): " fmt, \</span><br><span style="color: hsl(0, 100%, 40%);">-            osmo_gsup_message_type_name(gsup->message_type), \</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_gsup_message_class_name(gsup->message_class), \</span><br><span style="color: hsl(0, 100%, 40%);">-         gsup->imsi, \</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_quote_str((const char *)gsup->source_name, gsup->source_name_len), \</span><br><span style="color: hsl(0, 100%, 40%);">-         osmo_quote_str_buf2(namebuf, sizeof(namebuf), (const char *)gsup->destination_name, gsup->destination_name_len), \</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_gsup_message_type_name((gsup)->message_type), \</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_gsup_message_class_name((gsup)->message_class), \</span><br><span style="color: hsl(120, 100%, 40%);">+             (gsup)->imsi, \</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_quote_str((const char *)(gsup)->source_name, (gsup)->source_name_len), \</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_quote_str_buf2(namebuf, sizeof(namebuf), (const char *)(gsup)->destination_name, (gsup)->destination_name_len), \</span><br><span>         ## args)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int read_cb_forward(struct osmo_gsup_conn *conn, struct msgb *msg, const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+static int read_cb_forward(struct osmo_gsup_req *req)</span><br><span> {</span><br><span>         int ret = -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct osmo_gsup_message *gsup_err;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* FIXME: it would be better if the msgb never were deallocated immediately by osmo_gsup_addr_send(), which a</span><br><span style="color: hsl(0, 100%, 40%);">-    * select-loop volatile talloc context could facilitate. Then we would still be able to access gsup-> members</span><br><span style="color: hsl(0, 100%, 40%);">-         * (pointing into the msgb) even after sending failed, and we wouldn't need to copy this data before sending: */</span><br><span style="color: hsl(0, 100%, 40%);">-    /* Prepare error message (before IEs get deallocated) */</span><br><span style="color: hsl(0, 100%, 40%);">-        gsup_err = talloc_zero(hlr_ctx, struct osmo_gsup_message);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_STRLCPY_ARRAY(gsup_err->imsi, gsup->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-   gsup_err->message_class = gsup->message_class;</span><br><span style="color: hsl(0, 100%, 40%);">-    gsup_err->destination_name = talloc_memdup(gsup_err, gsup->destination_name, gsup->destination_name_len);</span><br><span style="color: hsl(0, 100%, 40%);">-      gsup_err->destination_name_len = gsup->destination_name_len;</span><br><span style="color: hsl(0, 100%, 40%);">-      gsup_err->message_type = gsup->message_type;</span><br><span style="color: hsl(0, 100%, 40%);">-      gsup_err->session_state = gsup->session_state;</span><br><span style="color: hsl(0, 100%, 40%);">-    gsup_err->session_id = gsup->session_id;</span><br><span style="color: hsl(0, 100%, 40%);">-  gsup_err->source_name = talloc_memdup(gsup_err, gsup->source_name, gsup->source_name_len);</span><br><span style="color: hsl(0, 100%, 40%);">-     gsup_err->source_name_len = gsup->source_name_len;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct osmo_gsup_message *gsup = &req->gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_gsup_message gsup_err;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *forward_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_gt destination_name;</span><br><span> </span><br><span>         /* Check for routing IEs */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!gsup->source_name || !gsup->source_name_len || !gsup->destination_name || !gsup->destination_name_len) {</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP_GSUP_FWD(gsup, LOGL_ERROR, "missing routing IEs\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             goto end;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!req->gsup.source_name[0] || !req->gsup.source_name_len</span><br><span style="color: hsl(120, 100%, 40%);">+         || !req->gsup.destination_name[0] || !req->gsup.destination_name_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP_GSUP_FWD(&req->gsup, LOGL_ERROR, "missing routing IEs\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              goto routing_error;</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Verify source name (e.g. "MSC-00-00-00-00-00-00") */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (gsup_route_find(conn->server, gsup->source_name, gsup->source_name_len) != conn) {</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP_GSUP_FWD(gsup, LOGL_ERROR, "mismatching source name\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         goto end;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_gt_set(&destination_name, req->gsup.destination_name, req->gsup.destination_name_len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP_GSUP_FWD(&req->gsup, LOGL_ERROR, "invalid destination name\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         goto routing_error;</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Forward message without re-encoding (so we don't remove unknown IEs) */</span><br><span style="color: hsl(0, 100%, 40%);">-  LOGP_GSUP_FWD(gsup, LOGL_INFO, "checks passed, forwarding\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_gt_name(&destination_name));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  /* Remove incoming IPA header to be able to prepend an outgoing IPA header */</span><br><span style="color: hsl(0, 100%, 40%);">-   msgb_pull_to_l2(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-   ret = osmo_gsup_addr_send(g_hlr->gs, gsup->destination_name, gsup->destination_name_len, msg);</span><br><span style="color: hsl(0, 100%, 40%);">- /* AT THIS POINT, THE msg MAY BE DEALLOCATED and the data like gsup->imsi, gsup->source_name etc may all be</span><br><span style="color: hsl(0, 100%, 40%);">-        * invalid and cause segfaults. */</span><br><span style="color: hsl(0, 100%, 40%);">-      msg = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-     gsup = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    if (ret == -ENODEV)</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "destination not connected\n");</span><br><span style="color: hsl(0, 100%, 40%);">-   else if (ret)</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "unknown error %i\n", ret);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-end:</span><br><span style="color: hsl(0, 100%, 40%);">-   /* Send error back to source */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Forward message without re-encoding (so we don't remove unknown IEs).</span><br><span style="color: hsl(120, 100%, 40%);">+   * Copy GSUP part to forward, removing incoming IPA header to be able to prepend an outgoing IPA header */</span><br><span style="color: hsl(120, 100%, 40%);">+    forward_msg = osmo_gsup_msgb_alloc("GSUP forward");</span><br><span style="color: hsl(120, 100%, 40%);">+ forward_msg->l2h = msgb_put(forward_msg, msgb_l2len(req->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(forward_msg->l2h, msgb_l2(req->msg), msgb_l2len(req->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+   ret = osmo_gsup_gt_send(g_hlr->gs, &destination_name, forward_msg);</span><br><span>   if (ret) {</span><br><span style="color: hsl(0, 100%, 40%);">-              struct msgb *msg_err = osmo_gsup_msgb_alloc("GSUP forward ERR response");</span><br><span style="color: hsl(0, 100%, 40%);">-             OSMO_ASSERT(msg_err);</span><br><span style="color: hsl(0, 100%, 40%);">-           gsup_err->message_type = OSMO_GSUP_MSGT_E_ROUTING_ERROR;</span><br><span style="color: hsl(0, 100%, 40%);">-             osmo_gsup_encode(msg_err, gsup_err);</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP_GSUP_FWD(gsup_err, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(gsup_err->message_type));</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_gsup_conn_send(conn, msg_err);</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP_GSUP_FWD(gsup, LOGL_ERROR, "%s (rc=%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ret == -ENODEV ? "destination not connected" : "unknown error",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ret);</span><br><span style="color: hsl(120, 100%, 40%);">+           goto routing_error;</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-       talloc_free(gsup_err);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (msg)</span><br><span style="color: hsl(0, 100%, 40%);">-                msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_gsup_req_free(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%);">+routing_error:</span><br><span style="color: hsl(120, 100%, 40%);">+   gsup_err = (struct osmo_gsup_message){</span><br><span style="color: hsl(120, 100%, 40%);">+                .message_type = OSMO_GSUP_MSGT_ROUTING_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+         .source_name = gsup->destination_name,</span><br><span style="color: hsl(120, 100%, 40%);">+             .source_name_len = gsup->destination_name_len,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_gsup_req_respond(req, &gsup_err, true, true);</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span> }</span><br><span> </span><br><span> static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   static struct osmo_gsup_message gsup;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msgb_l2(msg) || !msgb_l2len(msg)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DMAIN, LOGL_ERROR, "missing or empty L2 data\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_gsup_req *req = osmo_gsup_conn_rx(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!req)</span><br><span>            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* If the GSUP recipient is other than this HLR, forward. */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (req->gsup.destination_name_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_gt destination_name;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct osmo_gt my_name;</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gt_set_str(&my_name, g_hlr->gsup_unit_name.serno);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!osmo_gt_set(&destination_name, req->gsup.destination_name, req->gsup.destination_name_len)</span><br><span style="color: hsl(120, 100%, 40%);">+                 && osmo_gt_cmp(&destination_name, &my_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return read_cb_forward(req);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DMAIN, LOGL_ERROR, "error in GSUP decode: %d\n", rc);</span><br><span style="color: hsl(0, 100%, 40%);">-            msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-         return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* 3GPP TS 23.003 Section 2.2 clearly states that an IMSI with less than 5</span><br><span style="color: hsl(0, 100%, 40%);">-       * digits is impossible.  Even 5 digits is a highly theoretical case */</span><br><span style="color: hsl(0, 100%, 40%);">- if (strlen(gsup.imsi) < 5) { /* TODO: move this check to libosmogsm/gsup.c? */</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DMAIN, LOGL_ERROR, "IMSI too short: %s\n", osmo_quote_str(gsup.imsi, -1));</span><br><span style="color: hsl(0, 100%, 40%);">-               gsup_send_err_reply(conn, gsup.imsi, gsup.message_type, GMM_CAUSE_INV_MAND_INFO);</span><br><span style="color: hsl(0, 100%, 40%);">-               msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-         return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (gsup.destination_name_len)</span><br><span style="color: hsl(0, 100%, 40%);">-          return read_cb_forward(conn, msg, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   switch (gsup.message_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  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 style="color: hsl(0, 100%, 40%);">-             rx_send_auth_info(conn, &gsup, g_hlr->dbc);</span><br><span style="color: hsl(120, 100%, 40%);">+            rx_send_auth_info(conn->auc_3g_ind, req);</span><br><span>                 break;</span><br><span>       case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:</span><br><span style="color: hsl(0, 100%, 40%);">-            rx_upd_loc_req(conn, &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+              rx_upd_loc_req(conn, req);</span><br><span>           break;</span><br><span>       case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:</span><br><span style="color: hsl(0, 100%, 40%);">-           rx_purge_ms_req(conn, &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+             rx_purge_ms_req(req);</span><br><span>                break;</span><br><span>       /* responses to requests sent by us */</span><br><span>       case OSMO_GSUP_MSGT_DELETE_DATA_ERROR:</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DMAIN, LOGL_ERROR, "Error while deleting subscriber data "</span><br><span style="color: hsl(0, 100%, 40%);">-                    "for IMSI %s\n", gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_GSUP_REQ(req, LOGL_ERROR, "Peer responds with: Error while deleting subscriber data\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_gsup_req_free(req);</span><br><span>             break;</span><br><span>       case OSMO_GSUP_MSGT_DELETE_DATA_RESULT:</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DMAIN, LOGL_ERROR, "Deleting subscriber data for IMSI %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_GSUP_REQ(req, LOGL_DEBUG, "Peer responds with: Subscriber data deleted\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_free(req);</span><br><span>             break;</span><br><span>       case OSMO_GSUP_MSGT_PROC_SS_REQUEST:</span><br><span>         case OSMO_GSUP_MSGT_PROC_SS_RESULT:</span><br><span style="color: hsl(0, 100%, 40%);">-             rx_proc_ss_req(conn, &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+              rx_proc_ss_req(req);</span><br><span>                 break;</span><br><span>       case OSMO_GSUP_MSGT_PROC_SS_ERROR:</span><br><span style="color: hsl(0, 100%, 40%);">-              rx_proc_ss_error(conn, &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+            rx_proc_ss_error(req);</span><br><span>               break;</span><br><span>       case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:</span><br><span>       case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:</span><br><span>      case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:</span><br><span>   case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:</span><br><span style="color: hsl(0, 100%, 40%);">-             {</span><br><span style="color: hsl(0, 100%, 40%);">-                       struct lu_operation *luop = lu_op_by_imsi(gsup.imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                              &g_lu_ops);</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!luop) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            LOGP(DMAIN, LOGL_ERROR, "GSUP message %s for "</span><br><span style="color: hsl(0, 100%, 40%);">-                                     "unknown IMSI %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                  osmo_gsup_message_type_name(gsup.message_type),</span><br><span style="color: hsl(0, 100%, 40%);">-                                    gsup.imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-                             break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-                       lu_op_rx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(120, 100%, 40%);">+             lu_rx_gsup(req);</span><br><span>             break;</span><br><span>       case OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST:</span><br><span style="color: hsl(0, 100%, 40%);">-         rx_check_imei_req(conn, &gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+           rx_check_imei_req(req);</span><br><span>              break;</span><br><span>       default:</span><br><span>             LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                osmo_gsup_message_type_name(gsup.message_type));</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_gsup_message_type_name(req->gsup.message_type));</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_free(req);</span><br><span>             break;</span><br><span>       }</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_free(msg);</span><br><span>      return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -897,7 +741,7 @@</span><br><span> </span><br><span> </span><br><span>     g_hlr->gs = osmo_gsup_server_create(hlr_ctx, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT,</span><br><span style="color: hsl(0, 100%, 40%);">-                                           read_cb, &g_lu_ops, g_hlr);</span><br><span style="color: hsl(120, 100%, 40%);">+                                       read_cb, g_hlr);</span><br><span>         if (!g_hlr->gs) {</span><br><span>                 LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");</span><br><span>           exit(1);</span><br><span>@@ -920,7 +764,8 @@</span><br><span>       }</span><br><span> </span><br><span>        while (!quit)</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_select_main_ctx(0);</span><br><span style="color: hsl(120, 100%, 40%);">+</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_ussd.c b/src/hlr_ussd.c</span><br><span>index d5c0fa8..395882a 100644</span><br><span>--- a/src/hlr_ussd.c</span><br><span>+++ b/src/hlr_ussd.c</span><br><span>@@ -170,12 +170,14 @@</span><br><span>        /* subscriber's vlr_number</span><br><span>        * MO USSD: originating MSC's vlr_number</span><br><span>          * MT USSD: looked up once per session and cached here */</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t *vlr_number;</span><br><span style="color: hsl(0, 100%, 40%);">-    size_t vlr_number_len;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gt vlr_name;</span><br><span> </span><br><span>         /* we don't keep a pointer to the osmo_gsup_{route,conn} towards the MSC/VLR here,</span><br><span>        * as this might change during inter-VLR hand-over, and we simply look-up the serving MSC/VLR</span><br><span>         * every time we receive an USSD component from the EUSE */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_gsup_req *initial_req_from_ms;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gsup_req *initial_req_from_euse;</span><br><span> };</span><br><span> </span><br><span> struct ss_session *ss_session_find(struct hlr *hlr, const char *imsi, uint32_t session_id)</span><br><span>@@ -191,6 +193,10 @@</span><br><span> void ss_session_free(struct ss_session *ss)</span><br><span> {</span><br><span>      osmo_timer_del(&ss->timeout);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ss->initial_req_from_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_req_free(ss->initial_req_from_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ss->initial_req_from_euse)</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_gsup_req_free(ss->initial_req_from_euse);</span><br><span>    llist_del(&ss->list);</span><br><span>         talloc_free(ss);</span><br><span> }</span><br><span>@@ -230,59 +236,71 @@</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span> /* Resolve the target MSC by ss->imsi and send GSUP message. */</span><br><span style="color: hsl(0, 100%, 40%);">-static int ss_gsup_send(struct ss_session *ss, struct osmo_gsup_server *gs, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+static int ss_gsup_send_to_ms(struct ss_session *ss, struct osmo_gsup_server *gs, struct osmo_gsup_message *gsup)</span><br><span> {</span><br><span>    struct hlr_subscriber subscr = {};</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg;</span><br><span>    int rc;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   if (ss->initial_req_from_ms) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Use non-final osmo_gsup_req_respond() to not deallocate the ss->initial_req_from_ms */</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_gsup_req_respond(ss->initial_req_from_ms, gsup, false, false);</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%);">+   msg = osmo_gsup_msgb_alloc("GSUP USSD FW");</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_gsup_encode(msg, gsup);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPSS(ss, LOGL_ERROR, "Failed to encode GSUP message\n");</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>  /* Use vlr_number as looked up by the caller, or look up now. */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!ss->vlr_number) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ss->vlr_name.len) {</span><br><span>          rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);</span><br><span>                 if (rc < 0) {</span><br><span>                     LOGPSS(ss, LOGL_ERROR, "Cannot find subscriber, cannot route GSUP message\n");</span><br><span>                     msgb_free(msg);</span><br><span>                      return -EINVAL;</span><br><span>              }</span><br><span style="color: hsl(0, 100%, 40%);">-               ss->vlr_number = (uint8_t *)talloc_strdup(ss, subscr.vlr_number);</span><br><span style="color: hsl(0, 100%, 40%);">-            ss->vlr_number_len = strlen(subscr.vlr_number) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_gt_set_str(&ss->vlr_name, subscr.vlr_number);</span><br><span>    }</span><br><span> </span><br><span>        /* Check for empty string (all vlr_number strings end in "\0", because otherwise gsup_route_find() fails) */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (ss->vlr_number_len == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ss->vlr_name.len <= 1) {</span><br><span>           LOGPSS(ss, LOGL_ERROR, "Cannot send GSUP message, no VLR number stored for subscriber\n");</span><br><span>                 msgb_free(msg);</span><br><span>              return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOGPSS(ss, LOGL_DEBUG, "Tx SS/USSD to VLR %s\n", osmo_quote_str((char *)ss->vlr_number, ss->vlr_number_len));</span><br><span style="color: hsl(0, 100%, 40%);">-   return osmo_gsup_addr_send(gs, ss->vlr_number, ss->vlr_number_len, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGPSS(ss, LOGL_DEBUG, "Tx SS/USSD to VLR %s\n", osmo_gt_name(&ss->vlr_name));</span><br><span style="color: hsl(120, 100%, 40%);">+       return osmo_gsup_gt_send(gs, &ss->vlr_name, msg);</span><br><span> }</span><br><span> </span><br><span> static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_msg_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                   bool final, struct msgb *ss_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+                     bool final, struct msgb *ss_msg)</span><br><span> </span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_message resp = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-    struct msgb *resp_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_gsup_message resp = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .message_type = gsup_msg_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                .session_id = ss->session_id,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     resp.message_type = gsup_msg_type;</span><br><span>   OSMO_STRLCPY_ARRAY(resp.imsi, ss->imsi);</span><br><span>  if (final)</span><br><span>           resp.session_state = OSMO_GSUP_SESSION_STATE_END;</span><br><span>    else</span><br><span>                 resp.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;</span><br><span style="color: hsl(0, 100%, 40%);">-  resp.session_id = ss->session_id;</span><br><span>         if (ss_msg) {</span><br><span>                resp.ss_info = msgb_data(ss_msg);</span><br><span>            resp.ss_info_len = msgb_length(ss_msg);</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   resp_msg = msgb_alloc_headroom(4000, 64, __func__);</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(resp_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo_gsup_encode(resp_msg, &resp);</span><br><span style="color: hsl(0, 100%, 40%);">-  msgb_free(ss_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = ss_gsup_send_to_ms(ss, g_hlr->gs, &resp);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       return ss_gsup_send(ss, g_hlr->gs, resp_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_free(ss_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    return rc;</span><br><span> }</span><br><span> </span><br><span> #if 0</span><br><span>@@ -297,7 +315,7 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int ss_tx_error(struct ss_session *ss, uint8_t invoke_id, uint8_t error_code)</span><br><span style="color: hsl(120, 100%, 40%);">+static int ss_tx_to_ms_error(struct ss_session *ss, uint8_t invoke_id, uint8_t error_code)</span><br><span> {</span><br><span>   struct msgb *msg = gsm0480_gen_return_error(invoke_id, error_code);</span><br><span>  LOGPSS(ss, LOGL_NOTICE, "Tx ReturnError(%u, 0x%02x)\n", invoke_id, error_code);</span><br><span>@@ -305,7 +323,7 @@</span><br><span>      return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int ss_tx_ussd_7bit(struct ss_session *ss, bool final, uint8_t invoke_id, const char *text)</span><br><span style="color: hsl(120, 100%, 40%);">+static int ss_tx_to_ms_ussd_7bit(struct ss_session *ss, bool final, uint8_t invoke_id, const char *text)</span><br><span> {</span><br><span>  struct msgb *msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);</span><br><span>      LOGPSS(ss, LOGL_INFO, "Tx USSD '%s'\n", text);</span><br><span>@@ -319,7 +337,7 @@</span><br><span> </span><br><span> #include <osmocom/hlr/db.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int handle_ussd_own_msisdn(struct osmo_gsup_conn *conn, struct ss_session *ss,</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_ussd_own_msisdn(struct ss_session *ss,</span><br><span>                             const struct osmo_gsup_message *gsup, const struct ss_request *req)</span><br><span> {</span><br><span>   struct hlr_subscriber subscr;</span><br><span>@@ -333,25 +351,25 @@</span><br><span>                        snprintf(buf, sizeof(buf), "You have no MSISDN!");</span><br><span>                 else</span><br><span>                         snprintf(buf, sizeof(buf), "Your extension is %s", subscr.msisdn);</span><br><span style="color: hsl(0, 100%, 40%);">-            ss_tx_ussd_7bit(ss, true, req->invoke_id, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+            ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);</span><br><span>             break;</span><br><span>       case -ENOENT:</span><br><span style="color: hsl(0, 100%, 40%);">-           ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);</span><br><span style="color: hsl(120, 100%, 40%);">+              ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);</span><br><span>               break;</span><br><span>       case -EIO:</span><br><span>   default:</span><br><span style="color: hsl(0, 100%, 40%);">-                ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+          ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);</span><br><span>           break;</span><br><span>       }</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int handle_ussd_own_imsi(struct osmo_gsup_conn *conn, struct ss_session *ss,</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_ussd_own_imsi(struct ss_session *ss,</span><br><span>                                const struct osmo_gsup_message *gsup, const struct ss_request *req)</span><br><span> {</span><br><span>     char buf[GSM0480_USSD_7BIT_STRING_LEN+1];</span><br><span>    snprintf(buf, sizeof(buf), "Your IMSI is %s", ss->imsi);</span><br><span style="color: hsl(0, 100%, 40%);">-   ss_tx_ussd_7bit(ss, true, req->invoke_id, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+    ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -398,37 +416,26 @@</span><br><span> }</span><br><span> </span><br><span> /* is this GSUP connection an EUSE (true) or not (false)? */</span><br><span style="color: hsl(0, 100%, 40%);">-static bool conn_is_euse(struct osmo_gsup_conn *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+static bool peer_name_is_euse(const struct osmo_gt *peer_name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *addr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  rc = osmo_gsup_conn_ccm_get(conn, &addr, IPAC_IDTAG_SERNR);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc <= 5)</span><br><span style="color: hsl(120, 100%, 40%);">+       if (peer_name->len <= 5)</span><br><span>               return false;</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!strncmp((char *)addr, "EUSE-", 5))</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!strncmp((char *)(peer_name->val), "EUSE-", 5))</span><br><span>             return true;</span><br><span>         else</span><br><span>                 return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct hlr_euse *euse_by_conn(struct osmo_gsup_conn *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct hlr_euse *euse_by_name(const struct osmo_gt *peer_name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- char *addr;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct hlr *hlr = conn->server->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &addr, IPAC_IDTAG_SERNR);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (rc <= 5)</span><br><span style="color: hsl(0, 100%, 40%);">-         return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    if (strncmp(addr, "EUSE-", 5))</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!peer_name_is_euse(peer_name))</span><br><span>           return NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        return euse_find(hlr, addr+5);</span><br><span style="color: hsl(120, 100%, 40%);">+        return euse_find(g_hlr, (const char*)(peer_name->val)+5);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int handle_ss(struct ss_session *ss, const struct osmo_gsup_message *gsup,</span><br><span style="color: hsl(0, 100%, 40%);">-                  const struct ss_request *req)</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_ss(struct ss_session *ss, bool is_euse_originated, const struct osmo_gsup_message *gsup,</span><br><span style="color: hsl(120, 100%, 40%);">+                  const struct ss_request *req)</span><br><span> {</span><br><span>      uint8_t comp_type = gsup->ss_info[0];</span><br><span> </span><br><span>@@ -441,17 +448,16 @@</span><br><span>          * we don't handle "structured" SS requests at all.</span><br><span>     */</span><br><span>  LOGPSS(ss, LOGL_NOTICE, "Structured SS requests are not supported, rejecting...\n");</span><br><span style="color: hsl(0, 100%, 40%);">-  ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED);</span><br><span style="color: hsl(120, 100%, 40%);">+  ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED);</span><br><span>   return -ENOTSUP;</span><br><span> }</span><br><span> </span><br><span> /* Handle a USSD GSUP message for a given SS Session received from VLR or EUSE */</span><br><span style="color: hsl(0, 100%, 40%);">-static int handle_ussd(struct osmo_gsup_conn *conn, struct ss_session *ss,</span><br><span style="color: hsl(0, 100%, 40%);">-                        const struct osmo_gsup_message *gsup, const struct ss_request *req)</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_ussd(struct ss_session *ss, bool is_euse_originated, const struct osmo_gsup_message *gsup,</span><br><span style="color: hsl(120, 100%, 40%);">+                    const struct ss_request *req)</span><br><span> {</span><br><span>    uint8_t comp_type = gsup->ss_info[0];</span><br><span>     struct msgb *msg_out;</span><br><span style="color: hsl(0, 100%, 40%);">-   bool is_euse_originated = conn_is_euse(conn);</span><br><span> </span><br><span>    LOGPSS(ss, LOGL_INFO, "USSD CompType=%s, OpCode=%s '%s'\n",</span><br><span>                gsm0480_comp_type_name(comp_type), gsm0480_op_code_name(req->opcode),</span><br><span>@@ -459,27 +465,27 @@</span><br><span> </span><br><span>         if ((ss->is_external && !ss->u.euse) || !ss->u.iuse) {</span><br><span>              LOGPSS(ss, LOGL_NOTICE, "USSD for unknown code '%s'\n", req->ussd_text);</span><br><span style="color: hsl(0, 100%, 40%);">-           ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_SS_NOT_AVAILABLE);</span><br><span style="color: hsl(120, 100%, 40%);">+                ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_SS_NOT_AVAILABLE);</span><br><span>                 return 0;</span><br><span>    }</span><br><span> </span><br><span>        if (is_euse_originated) {</span><br><span style="color: hsl(0, 100%, 40%);">-               msg_out = osmo_gsup_msgb_alloc("GSUP USSD FW");</span><br><span style="color: hsl(0, 100%, 40%);">-               OSMO_ASSERT(msg_out);</span><br><span>                /* Received from EUSE, Forward to VLR */</span><br><span style="color: hsl(0, 100%, 40%);">-                osmo_gsup_encode(msg_out, gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-                ss_gsup_send(ss, conn->server, msg_out);</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Need a non-const osmo_gsup_message, because sending might modify some (routing related?) parts. */</span><br><span style="color: hsl(120, 100%, 40%);">+         struct osmo_gsup_message forward = *gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+             ss_gsup_send_to_ms(ss, g_hlr->gs, &forward);</span><br><span>  } else {</span><br><span>             /* Received from VLR (MS) */</span><br><span>                 if (ss->is_external) {</span><br><span>                    /* Forward to EUSE */</span><br><span style="color: hsl(0, 100%, 40%);">-                   char addr[128];</span><br><span style="color: hsl(0, 100%, 40%);">-                 strcpy(addr, "EUSE-");</span><br><span style="color: hsl(0, 100%, 40%);">-                        osmo_strlcpy(addr+5, ss->u.euse->name, sizeof(addr)-5);</span><br><span style="color: hsl(0, 100%, 40%);">-                   conn = gsup_route_find(conn->server, (uint8_t *)addr, strlen(addr)+1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_gt euse_name;</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct osmo_gsup_conn *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_gt_set_str(&euse_name, "EUSE-%s", ss->u.euse->name);</span><br><span style="color: hsl(120, 100%, 40%);">+                 conn = gsup_route_find_gt(g_hlr->gs, &euse_name);</span><br><span>                     if (!conn) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            LOGPSS(ss, LOGL_ERROR, "Cannot find conn for EUSE %s\n", addr);</span><br><span style="color: hsl(0, 100%, 40%);">-                               ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+                          LOGPSS(ss, LOGL_ERROR, "Cannot find conn for EUSE %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   osmo_gt_name(&euse_name));</span><br><span style="color: hsl(120, 100%, 40%);">+                         ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);</span><br><span>                   } else {</span><br><span>                             msg_out = osmo_gsup_msgb_alloc("GSUP USSD FW");</span><br><span>                            OSMO_ASSERT(msg_out);</span><br><span>@@ -488,9 +494,10 @@</span><br><span>                         }</span><br><span>            } else {</span><br><span>                     /* Handle internally */</span><br><span style="color: hsl(0, 100%, 40%);">-                 ss->u.iuse->handle_ussd(conn, ss, gsup, req);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ss->u.iuse->handle_ussd(ss, gsup, req);</span><br><span>                        /* Release session immediately */</span><br><span>                    ss_session_free(ss);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return 0;</span><br><span>            }</span><br><span>    }</span><br><span> </span><br><span>@@ -500,12 +507,16 @@</span><br><span> </span><br><span> /* this function is called for any SS_REQ/SS_RESP messages from both the MSC/VLR side as well</span><br><span>  * as from the EUSE side */</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        struct hlr *hlr = conn->server->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct hlr *hlr = g_hlr;</span><br><span>     struct ss_session *ss;</span><br><span>       struct ss_request req = {0};</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsup_route *gsup_rt;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_gsup_message *gsup = &gsup_req->gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Remember whether this function should free the incoming gsup_req: if it is placed as ss->initial_req_from_*,</span><br><span style="color: hsl(120, 100%, 40%);">+     * do not free it here. If not, free it here. */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_gsup_req *free_gsup_req = gsup_req;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool is_euse_originated = peer_name_is_euse(&gsup_req->source_name);</span><br><span> </span><br><span>      LOGP(DSS, LOGL_DEBUG, "%s/0x%08x: Process SS (%s)\n", gsup->imsi, gsup->session_id,</span><br><span>          osmo_gsup_session_state_name(gsup->session_state));</span><br><span>@@ -516,14 +527,15 @@</span><br><span>                       LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Unable to parse SS request: %s\n",</span><br><span>                              gsup->imsi, gsup->session_id,</span><br><span>                          osmo_hexdump(gsup->ss_info, gsup->ss_info_len));</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* FIXME: Send a Reject component? */</span><br><span style="color: hsl(0, 100%, 40%);">-                   goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "error parsing SS request");</span><br><span style="color: hsl(120, 100%, 40%);">+                   return;</span><br><span>              }</span><br><span>    } else if (gsup->session_state != OSMO_GSUP_SESSION_STATE_END) {</span><br><span>          LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Missing SS payload for '%s'\n",</span><br><span>                      gsup->imsi, gsup->session_id,</span><br><span>                  osmo_gsup_session_state_name(gsup->session_state));</span><br><span style="color: hsl(0, 100%, 40%);">-             goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "missing SS payload");</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span>      }</span><br><span> </span><br><span>        switch (gsup->session_state) {</span><br><span>@@ -532,32 +544,29 @@</span><br><span>            if (ss_session_find(hlr, gsup->imsi, gsup->session_id)) {</span><br><span>                      LOGP(DSS, LOGL_ERROR, "%s/0x%08x: BEGIN with non-unique session ID!\n",</span><br><span>                            gsup->imsi, gsup->session_id);</span><br><span style="color: hsl(0, 100%, 40%);">-                    goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "BEGIN with non-unique session ID");</span><br><span style="color: hsl(120, 100%, 40%);">+                   return;</span><br><span>              }</span><br><span>            ss = ss_session_alloc(hlr, gsup->imsi, gsup->session_id);</span><br><span>              if (!ss) {</span><br><span>                   LOGP(DSS, LOGL_ERROR, "%s/0x%08x: Unable to allocate SS session\n",</span><br><span>                                gsup->imsi, gsup->session_id);</span><br><span style="color: hsl(0, 100%, 40%);">-                    goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_NET_FAIL, "Unable to allocate SS session");</span><br><span style="color: hsl(120, 100%, 40%);">+                   return;</span><br><span>              }</span><br><span>            /* Get IPA name from VLR conn and save as ss->vlr_number */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!conn_is_euse(conn)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      gsup_rt = gsup_route_find_by_conn(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (gsup_rt) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          ss->vlr_number = (uint8_t *)talloc_strdup(ss, (const char *)gsup_rt->addr);</span><br><span style="color: hsl(0, 100%, 40%);">-                               ss->vlr_number_len = strlen((const char *)gsup_rt->addr) + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                             LOGPSS(ss, LOGL_DEBUG, "Destination IPA name retrieved from GSUP route: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                       osmo_quote_str((const char *)ss->vlr_number, ss->vlr_number_len));</span><br><span style="color: hsl(0, 100%, 40%);">-                 } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                LOGPSS(ss, LOGL_NOTICE, "Could not find GSUP route, therefore can't set the destination"</span><br><span style="color: hsl(0, 100%, 40%);">-                                                  " IPA name. We'll try to look it up later, but this should not"</span><br><span style="color: hsl(0, 100%, 40%);">-                                                   " have happened.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                 }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!is_euse_originated) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ss->initial_req_from_ms = gsup_req;</span><br><span style="color: hsl(120, 100%, 40%);">+                        free_gsup_req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                 ss->vlr_name = gsup_req->source_name;</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ss->initial_req_from_euse = gsup_req;</span><br><span style="color: hsl(120, 100%, 40%);">+                      free_gsup_req = NULL;</span><br><span>                }</span><br><span>            if (ss_op_is_ussd(req.opcode)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (conn_is_euse(conn)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (is_euse_originated) {</span><br><span>                            /* EUSE->VLR: MT USSD. EUSE is known ('conn'), VLR is to be resolved */</span><br><span style="color: hsl(0, 100%, 40%);">-                              ss->u.euse = euse_by_conn(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ss->u.euse = euse_by_name(&gsup_req->source_name);</span><br><span>                         } else {</span><br><span>                             /* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */</span><br><span>                           struct hlr_ussd_route *rt;</span><br><span>@@ -578,10 +587,10 @@</span><br><span>                           }</span><br><span>                    }</span><br><span>                    /* dispatch unstructured SS to routing */</span><br><span style="color: hsl(0, 100%, 40%);">-                       handle_ussd(conn, ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_ussd(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>               } else {</span><br><span>                     /* dispatch non-call SS to internal code */</span><br><span style="color: hsl(0, 100%, 40%);">-                     handle_ss(ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_ss(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>                 }</span><br><span>            break;</span><br><span>       case OSMO_GSUP_SESSION_STATE_CONTINUE:</span><br><span>@@ -589,7 +598,8 @@</span><br><span>                 if (!ss) {</span><br><span>                   LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n",</span><br><span>                              gsup->imsi, gsup->session_id);</span><br><span style="color: hsl(0, 100%, 40%);">-                    goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "CONTINUE for unknown SS session");</span><br><span style="color: hsl(120, 100%, 40%);">+                    return;</span><br><span>              }</span><br><span> </span><br><span>                /* Reschedule self-destruction timer */</span><br><span>@@ -598,10 +608,10 @@</span><br><span> </span><br><span>          if (ss_op_is_ussd(req.opcode)) {</span><br><span>                     /* dispatch unstructured SS to routing */</span><br><span style="color: hsl(0, 100%, 40%);">-                       handle_ussd(conn, ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_ussd(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>               } else {</span><br><span>                     /* dispatch non-call SS to internal code */</span><br><span style="color: hsl(0, 100%, 40%);">-                     handle_ss(ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                        handle_ss(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>                 }</span><br><span>            break;</span><br><span>       case OSMO_GSUP_SESSION_STATE_END:</span><br><span>@@ -609,17 +619,17 @@</span><br><span>            if (!ss) {</span><br><span>                   LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n",</span><br><span>                           gsup->imsi, gsup->session_id);</span><br><span style="color: hsl(0, 100%, 40%);">-                    goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+                 return;</span><br><span>              }</span><br><span> </span><br><span>                /* SS payload is optional for END */</span><br><span>                 if (gsup->ss_info && gsup->ss_info_len) {</span><br><span>                      if (ss_op_is_ussd(req.opcode)) {</span><br><span>                             /* dispatch unstructured SS to routing */</span><br><span style="color: hsl(0, 100%, 40%);">-                               handle_ussd(conn, ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                                handle_ussd(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>                       } else {</span><br><span>                             /* dispatch non-call SS to internal code */</span><br><span style="color: hsl(0, 100%, 40%);">-                             handle_ss(ss, gsup, &req);</span><br><span style="color: hsl(120, 100%, 40%);">+                                handle_ss(ss, is_euse_originated, &gsup_req->gsup, &req);</span><br><span>                         }</span><br><span>            }</span><br><span> </span><br><span>@@ -628,18 +638,15 @@</span><br><span>        default:</span><br><span>             LOGP(DSS, LOGL_ERROR, "%s/0x%08x: Unknown SS State %d\n", gsup->imsi,</span><br><span>                   gsup->session_id, gsup->session_state);</span><br><span style="color: hsl(0, 100%, 40%);">-           goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-out_err:</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (free_gsup_req)</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_gsup_req_free(free_gsup_req);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int rx_proc_ss_error(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(120, 100%, 40%);">+void rx_proc_ss_error(struct osmo_gsup_req *req)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", gsup->imsi, gsup->session_id,</span><br><span style="color: hsl(0, 100%, 40%);">-              osmo_gsup_session_state_name(gsup->session_state));</span><br><span style="color: hsl(0, 100%, 40%);">-  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id,</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_gsup_session_state_name(req->gsup.session_state));</span><br><span> }</span><br><span>diff --git a/src/logging.c b/src/logging.c</span><br><span>index 3713ab3..d123fcd 100644</span><br><span>--- a/src/logging.c</span><br><span>+++ b/src/logging.c</span><br><span>@@ -25,6 +25,12 @@</span><br><span>                .color = "\033[1;34m",</span><br><span>             .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span>       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DLU] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "DLU",</span><br><span style="color: hsl(120, 100%, 40%);">+              .description = "Location Updating",</span><br><span style="color: hsl(120, 100%, 40%);">+         .color = "\033[1;33m",</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/lu_fsm.c b/src/lu_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6479077</span><br><span>--- /dev/null</span><br><span>+++ b/src/lu_fsm.c</span><br><span>@@ -0,0 +1,289 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.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/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/apn.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%);">+</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%);">+#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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hlr/db.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_LU(lu, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGPFSML((lu)? (lu)->fi : NULL, level, fmt, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_LU_REQ(lu, req, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGPFSML((lu)? (lu)->fi : NULL, level, "%s:" fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_message_type_name((req)->gsup.message_type), ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct lu {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_req *update_location_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Subscriber state at time of initial Update Location Request */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hlr_subscriber subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool is_ps;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* VLR requesting the LU. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_gt vlr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* If the LU request was received via a proxy and not immediately from a local VLR, this indicates the closest</span><br><span style="color: hsl(120, 100%, 40%);">+         * peer that forwarded the GSUP message. */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gt via_proxy;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+LLIST_HEAD(g_all_lu);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum lu_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+   LU_EV_RX_GSUP,</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%);">+enum lu_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+     LU_ST_UNVALIDATED,</span><br><span style="color: hsl(120, 100%, 40%);">+    LU_ST_WAIT_INSERT_DATA_RESULT,</span><br><span style="color: hsl(120, 100%, 40%);">+        LU_ST_WAIT_LOCATION_CANCEL_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 const struct value_string lu_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(LU_EV_RX_GSUP),</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 struct osmo_tdef_state_timeout lu_fsm_timeouts[32] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       [LU_ST_WAIT_INSERT_DATA_RESULT] = { .T = -4222 },</span><br><span style="color: hsl(120, 100%, 40%);">+     [LU_ST_WAIT_LOCATION_CANCEL_RESULT] = { .T = -4222 },</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 lu_state_chg(lu, state) \</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_tdef_fsm_inst_state_chg((lu)->fi, state, lu_fsm_timeouts, g_hlr_tdefs, 5)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void lu_success(struct lu *lu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!lu->update_location_req)</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_LU(lu, LOGL_ERROR, "No request for this LU\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_gsup_req_respond_msgt(lu->update_location_req, OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT, true);</span><br><span style="color: hsl(120, 100%, 40%);">+  lu->update_location_req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fsm_inst_term(lu->fi, OSMO_FSM_TERM_REGULAR, 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%);">+#define lu_failure(LU, CAUSE, log_msg, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!(LU)->update_location_req) \</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_LU(LU, LOGL_ERROR, "No request for this LU\n"); \</span><br><span style="color: hsl(120, 100%, 40%);">+               else \</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_gsup_req_respond_err((LU)->update_location_req, CAUSE, log_msg, ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+            (LU)->update_location_req = NULL; \</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_term((LU)->fi, OSMO_FSM_TERM_REGULAR, NULL); \</span><br><span style="color: hsl(120, 100%, 40%);">+       } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm lu_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void lu_start(struct osmo_gsup_req *update_location_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lu *lu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(update_location_req);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(update_location_req->gsup.message_type == OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   fi = osmo_fsm_inst_alloc(&lu_fsm, g_hlr, NULL, LOGL_DEBUG, update_location_req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    lu = talloc(fi, struct lu);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(lu);</span><br><span style="color: hsl(120, 100%, 40%);">+      fi->priv = lu;</span><br><span style="color: hsl(120, 100%, 40%);">+     *lu = (struct lu){</span><br><span style="color: hsl(120, 100%, 40%);">+            .fi = fi,</span><br><span style="color: hsl(120, 100%, 40%);">+             .update_location_req = update_location_req,</span><br><span style="color: hsl(120, 100%, 40%);">+           .vlr_name = update_location_req->source_name,</span><br><span style="color: hsl(120, 100%, 40%);">+              .via_proxy = update_location_req->via_proxy,</span><br><span style="color: hsl(120, 100%, 40%);">+               /* According to GSUP specs, OSMO_GSUP_CN_DOMAIN_PS is the default. */</span><br><span style="color: hsl(120, 100%, 40%);">+         .is_ps = (update_location_req->gsup.cn_domain != OSMO_GSUP_CN_DOMAIN_CS),</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_add(&lu->entry, &g_all_lu);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_fsm_inst_update_id_f_sanitize(fi, '_', "%s:IMSI-%s", lu->is_ps ? "PS" : "CS", update_location_req->gsup.imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!lu->vlr_name.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           lu_failure(lu, GMM_CAUSE_NET_FAIL, "LU without a VLR");</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 (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lu_failure(lu, GMM_CAUSE_IMSI_UNKNOWN, "Subscriber does not exist");</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%);">+   /* Check if subscriber is generally permitted on CS or PS</span><br><span style="color: hsl(120, 100%, 40%);">+      * service (as requested) */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!lu->is_ps && !lu->subscr.nam_cs) {</span><br><span style="color: hsl(120, 100%, 40%);">+         lu_failure(lu, GMM_CAUSE_PLMN_NOTALLOWED, "nam_cs == false");</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%);">+     if (lu->is_ps && !lu->subscr.nam_ps) {</span><br><span style="color: hsl(120, 100%, 40%);">+          lu_failure(lu, GMM_CAUSE_GPRS_NOTALLOWED, "nam_ps == false");</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%);">+   /* TODO: Set subscriber tracing = deactive in VLR/SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!lu->is_ps && strcmp(subscr->vlr_number, vlr_number)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lu_op_tx_cancel_old(lu);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (lu->is_ps && strcmp(subscr->sgsn_number, sgsn_number)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lu_op_tx_cancel_old(lu);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (lu->via_proxy.len) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s, via proxy %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         lu->is_ps ? "SGSN number" : "VLR number",</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_gt_name(&lu->vlr_name),</span><br><span style="color: hsl(120, 100%, 40%);">+                           osmo_gt_name(&lu->via_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               lu->is_ps ? "SGSN number" : "VLR number",</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_gt_name(&lu->vlr_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 (db_subscr_lu(g_hlr->dbc, lu->subscr.id, &lu->vlr_name, lu->is_ps, &lu->via_proxy)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               lu_failure(lu, GMM_CAUSE_NET_FAIL, "Cannot update %s in the database",</span><br><span style="color: hsl(120, 100%, 40%);">+                         lu->is_ps ? "SGSN number" : "VLR number");</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%);">+   /* TODO: Subscriber allowed to roam in PLMN? */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* TODO: Update RoutingInfo */</span><br><span style="color: hsl(120, 100%, 40%);">+        /* TODO: Reset Flag MS Purged (cs/ps) */</span><br><span style="color: hsl(120, 100%, 40%);">+      /* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     lu_state_chg(lu, LU_ST_WAIT_INSERT_DATA_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%);">+void lu_rx_gsup(struct osmo_gsup_req *req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct lu *lu;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (req->gsup.message_type == OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST)</span><br><span style="color: hsl(120, 100%, 40%);">+              return lu_start(req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(lu, &g_all_lu, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (strcmp(lu->subscr.imsi, req->gsup.imsi))</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (osmo_fsm_inst_dispatch(lu->fi, LU_EV_RX_GSUP, req)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_LU_REQ(lu, req, LOGL_ERROR, "Cannot receive GSUP messages in this state\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_gsup_req_respond_err(req, GMM_CAUSE_MSGT_INCOMP_P_STATE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           "LU does not accept GSUP rx");</span><br><span style="color: hsl(120, 100%, 40%);">+            }</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_gsup_req_respond_err(req, GMM_CAUSE_MSGT_INCOMP_P_STATE, "No Location Updating in progress for this 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%);">+static int lu_fsm_timer_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct lu *lu = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  lu_failure(lu, GSM_CAUSE_NET_FAIL, "Timeout");</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 void lu_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct lu *lu = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (lu->update_location_req)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_req_respond_err(lu->update_location_req, GSM_CAUSE_NET_FAIL, "LU aborted");</span><br><span style="color: hsl(120, 100%, 40%);">+    lu->update_location_req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_del(&lu->entry);</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 lu_fsm_wait_insert_data_result_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Transmit Insert Data Request to the VLR */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct lu *lu = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hlr_subscriber *subscr = &lu->subscr;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_gsup_message gsup;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t apn[APN_MAXLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   subscr->msisdn, msisdn_enc, sizeof(msisdn_enc),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    apn, sizeof(apn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     lu->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data 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%);">+   if (osmo_gsup_req_respond(lu->update_location_req, &gsup, false, false))</span><br><span style="color: hsl(120, 100%, 40%);">+               lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot send %s", osmo_gsup_message_type_name(gsup.message_type));</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 lu_fsm_wait_insert_data_result(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct lu *lu = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_gsup_req *req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case LU_EV_RX_GSUP:</span><br><span style="color: hsl(120, 100%, 40%);">+           req = data;</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%);">+              OSMO_ASSERT(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%);">+   switch (req->gsup.message_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_gsup_req_free(req);</span><br><span style="color: hsl(120, 100%, 40%);">+              lu_success(lu);</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_INSERT_DATA_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+                lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type));</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%);">+              osmo_gsup_req_respond_err(req, GMM_CAUSE_MSGT_INCOMP_P_STATE, "unexpected message type in this state");</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define S(x) (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_fsm_state lu_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       [LU_ST_UNVALIDATED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .name = "UNVALIDATED",</span><br><span style="color: hsl(120, 100%, 40%);">+              .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LU_ST_WAIT_INSERT_DATA_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%);">+    [LU_ST_WAIT_INSERT_DATA_RESULT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "WAIT_INSERT_DATA_RESULT",</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LU_EV_RX_GSUP)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .onenter = lu_fsm_wait_insert_data_result_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = lu_fsm_wait_insert_data_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm lu_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .name = "lu",</span><br><span style="color: hsl(120, 100%, 40%);">+       .states = lu_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+      .num_states = ARRAY_SIZE(lu_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+      .log_subsys = DLU,</span><br><span style="color: hsl(120, 100%, 40%);">+    .event_names = lu_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+    .timer_cb = lu_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+  .cleanup = lu_fsm_cleanup,</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 __attribute__((constructor)) void lu_fsm_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/luop.c b/src/luop.c</span><br><span>deleted file mode 100644</span><br><span>index f63cf92..0000000</span><br><span>--- a/src/luop.c</span><br><span>+++ /dev/null</span><br><span>@@ -1,259 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/* OsmoHLR TX/RX lu operations */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(0, 100%, 40%);">- * All Rights Reserved</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Author: Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">- * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">- * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(0, 100%, 40%);">- * (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">- * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU Affero General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(0, 100%, 40%);">- * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <stdbool.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <string.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <errno.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/logging.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/gsup.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/apn.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/gsup_server.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/gsup_router.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/logging.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/hlr/luop.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-const struct value_string lu_state_names[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-    { LU_S_NULL,                    "NULL" },</span><br><span style="color: hsl(0, 100%, 40%);">-     { LU_S_LU_RECEIVED,             "LU RECEIVED" },</span><br><span style="color: hsl(0, 100%, 40%);">-      { LU_S_CANCEL_SENT,             "CANCEL SENT" },</span><br><span style="color: hsl(0, 100%, 40%);">-      { LU_S_CANCEL_ACK_RECEIVED,     "CANCEL-ACK RECEIVED" },</span><br><span style="color: hsl(0, 100%, 40%);">-      { LU_S_ISD_SENT,                "ISD SENT" },</span><br><span style="color: hsl(0, 100%, 40%);">- { LU_S_ISD_ACK_RECEIVED,        "ISD-ACK RECEIVED" },</span><br><span style="color: hsl(0, 100%, 40%);">- { LU_S_COMPLETE,                "COMPLETE" },</span><br><span style="color: hsl(0, 100%, 40%);">- { 0, NULL }</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Transmit a given GSUP message for the given LU operation */</span><br><span style="color: hsl(0, 100%, 40%);">-static void _luop_tx_gsup(struct lu_operation *luop,</span><br><span style="color: hsl(0, 100%, 40%);">-                   const struct osmo_gsup_message *gsup)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct msgb *msg_out;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   msg_out = osmo_gsup_msgb_alloc("GSUP LUOP");</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(msg_out);</span><br><span style="color: hsl(0, 100%, 40%);">-   osmo_gsup_encode(msg_out, gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_gsup_addr_send(luop->gsup_server, luop->peer,</span><br><span style="color: hsl(0, 100%, 40%);">-                            talloc_total_size(luop->peer),</span><br><span style="color: hsl(0, 100%, 40%);">-                       msg_out);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static inline void fill_gsup_msg(struct osmo_gsup_message *out,</span><br><span style="color: hsl(0, 100%, 40%);">-                            const struct lu_operation *lu,</span><br><span style="color: hsl(0, 100%, 40%);">-                          enum osmo_gsup_message_type mt)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       memset(out, 0, sizeof(struct osmo_gsup_message));</span><br><span style="color: hsl(0, 100%, 40%);">-       if (lu)</span><br><span style="color: hsl(0, 100%, 40%);">-         osmo_strlcpy(out->imsi, lu->subscr.imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                       GSM23003_IMSI_MAX_DIGITS + 1);</span><br><span style="color: hsl(0, 100%, 40%);">-     out->message_type = mt;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* timer call-back in case LU operation doesn't receive an response */</span><br><span style="color: hsl(0, 100%, 40%);">-static void lu_op_timer_cb(void *data)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct lu_operation *luop = data;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       DEBUGP(DMAIN, "LU OP timer expired in state %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            get_value_string(lu_state_names, luop->state));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      switch (luop->state) {</span><br><span style="color: hsl(0, 100%, 40%);">-       case LU_S_CANCEL_SENT:</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case LU_S_ISD_SENT:</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       lu_op_tx_error(luop, GMM_CAUSE_NET_FAIL);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-bool lu_op_fill_subscr(struct lu_operation *luop, struct db_context *dbc,</span><br><span style="color: hsl(0, 100%, 40%);">-                    const char *imsi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct hlr_subscriber *subscr = &luop->subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (db_subscr_get_by_imsi(dbc, imsi, subscr) < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-            return false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return true;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct lu_operation *luop;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      luop = talloc_zero(srv, struct lu_operation);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-      luop->gsup_server = srv;</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_timer_setup(&luop->timer, lu_op_timer_cb, luop);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return luop;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_free(struct lu_operation *luop)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        /* Only attempt to remove when it was ever added to a list. */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (luop->list.next)</span><br><span style="color: hsl(0, 100%, 40%);">-         llist_del(&luop->list);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* Delete timer just in case it is still pending. */</span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_timer_del(&luop->timer);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    talloc_free(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_alloc_conn(struct osmo_gsup_conn *conn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  uint8_t *peer_addr;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct lu_operation *luop = lu_op_alloc(conn->server);</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc = osmo_gsup_conn_ccm_get(conn, &peer_addr, IPAC_IDTAG_SERNR);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                lu_op_free(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-               return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       luop->peer = talloc_memdup(luop, peer_addr, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     return luop;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* FIXME: this doesn't seem to work at all */</span><br><span style="color: hsl(0, 100%, 40%);">-struct lu_operation *lu_op_by_imsi(const char *imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 const struct llist_head *lst)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct lu_operation *luop;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      llist_for_each_entry(luop, lst, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-         if (!strcmp(imsi, luop->subscr.imsi))</span><br><span style="color: hsl(0, 100%, 40%);">-                        return luop;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_statechg(struct lu_operation *luop, enum lu_state new_state)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   enum lu_state old_state = luop->state;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       DEBUGP(DMAIN, "LU OP state change: %s -> ",</span><br><span style="color: hsl(0, 100%, 40%);">-                get_value_string(lu_state_names, old_state));</span><br><span style="color: hsl(0, 100%, 40%);">-   DEBUGPC(DMAIN, "%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                get_value_string(lu_state_names, new_state));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   luop->state = new_state;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Transmit UPD_LOC_ERROR and destroy lu_operation */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_error(struct lu_operation *luop, enum gsm48_gmm_cause cause)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct osmo_gsup_message gsup;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  DEBUGP(DMAIN, "%s: LU OP Tx Error (cause %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             luop->subscr.imsi, get_value_string(gsm48_gmm_cause_names,</span><br><span style="color: hsl(0, 100%, 40%);">-                                               cause));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     fill_gsup_msg(&gsup, luop, OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR);</span><br><span style="color: hsl(0, 100%, 40%);">-   gsup.cause = cause;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     _luop_tx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_free(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Transmit UPD_LOC_RESULT and destroy lu_operation */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_ack(struct lu_operation *luop)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct osmo_gsup_message gsup;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  fill_gsup_msg(&gsup, luop, OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT);</span><br><span style="color: hsl(0, 100%, 40%);">-  //FIXME gsup.hlr_enc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   _luop_tx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_free(luop);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Send Cancel Location to old VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_cancel_old(struct lu_operation *luop)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct osmo_gsup_message gsup;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(luop->state == LU_S_LU_RECEIVED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        fill_gsup_msg(&gsup, NULL, OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST);</span><br><span style="color: hsl(0, 100%, 40%);">- //gsup.cause = FIXME;</span><br><span style="color: hsl(0, 100%, 40%);">-   //gsup.cancel_type = FIXME;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     _luop_tx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_statechg(luop, LU_S_CANCEL_SENT);</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_timer_schedule(&luop->timer, CANCEL_TIMEOUT_SECS, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Transmit Insert Subscriber Data to new VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_insert_subscr_data(struct lu_operation *luop)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct hlr_subscriber *subscr = &luop->subscr;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct osmo_gsup_message gsup = { };</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t apn[APN_MAXLEN];</span><br><span style="color: hsl(0, 100%, 40%);">-        enum osmo_gsup_cn_domain cn_domain;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_ASSERT(luop->state == LU_S_LU_RECEIVED ||</span><br><span style="color: hsl(0, 100%, 40%);">-                   luop->state == LU_S_CANCEL_ACK_RECEIVED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (luop->is_ps)</span><br><span style="color: hsl(0, 100%, 40%);">-             cn_domain = OSMO_GSUP_CN_DOMAIN_PS;</span><br><span style="color: hsl(0, 100%, 40%);">-     else</span><br><span style="color: hsl(0, 100%, 40%);">-            cn_domain = OSMO_GSUP_CN_DOMAIN_CS;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                      sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                "IMSI='%s': Cannot notify GSUP client; could not create gsup message "</span><br><span style="color: hsl(0, 100%, 40%);">-                "for %s\n", subscr->imsi, luop->peer);</span><br><span style="color: hsl(0, 100%, 40%);">-           return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Send ISD to new VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-  _luop_tx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lu_op_statechg(luop, LU_S_ISD_SENT);</span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_timer_schedule(&luop->timer, ISD_TIMEOUT_SECS, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Transmit Delete Subscriber Data to new VLR/SGSN.</span><br><span style="color: hsl(0, 100%, 40%);">- * The luop is not freed. */</span><br><span style="color: hsl(0, 100%, 40%);">-void lu_op_tx_del_subscr_data(struct lu_operation *luop)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct osmo_gsup_message gsup;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  fill_gsup_msg(&gsup, luop, OSMO_GSUP_MSGT_DELETE_DATA_REQUEST);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_PS;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* Send ISD to new VLR/SGSN */</span><br><span style="color: hsl(0, 100%, 40%);">-  _luop_tx_gsup(luop, &gsup);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/mslookup/mdns_record.c b/src/mslookup/mdns_record.c</span><br><span>index c9b6e4c..05788ca 100644</span><br><span>--- a/src/mslookup/mdns_record.c</span><br><span>+++ b/src/mslookup/mdns_record.c</span><br><span>@@ -95,10 +95,10 @@</span><br><span>          return -EINVAL;</span><br><span> </span><br><span>  /* Parse key */</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_token_copy(key_buf, key_size, key_value, sep - key_value);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_print_n(key_buf, key_size, key_value, sep - key_value);</span><br><span> </span><br><span>     /* Parse value */</span><br><span>    value = sep + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_token_copy(value_buf, value_size, value, key_value_end - value);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_print_n(value_buf, value_size, value, key_value_end - value);</span><br><span>   return 0;</span><br><span> }</span><br><span>diff --git a/tests/db/Makefile.am b/tests/db/Makefile.am</span><br><span>index f13824d..1539145 100644</span><br><span>--- a/tests/db/Makefile.am</span><br><span>+++ b/tests/db/Makefile.am</span><br><span>@@ -30,6 +30,7 @@</span><br><span>      $(top_builddir)/src/db_auc.o \</span><br><span>       $(top_builddir)/src/db_hlr.o \</span><br><span>       $(top_builddir)/src/db.o \</span><br><span style="color: hsl(120, 100%, 40%);">+    $(top_builddir)/src/global_title.o \</span><br><span>         $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOABIS_LIBS) \</span><br><span>diff --git a/tests/db/db_test.c b/tests/db/db_test.c</span><br><span>index d6060dd..0ea2cfb 100644</span><br><span>--- a/tests/db/db_test.c</span><br><span>+++ b/tests/db/db_test.c</span><br><span>@@ -27,6 +27,7 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/logging.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsupclient/global_title.h></span><br><span> #include <osmocom/hlr/db.h></span><br><span> #include <osmocom/hlr/logging.h></span><br><span> </span><br><span>@@ -145,6 +146,8 @@</span><br><span> #define Ps(name) \</span><br><span>    if (*subscr->name) \</span><br><span>              Pfo(name, "'%s'", subscr)</span><br><span style="color: hsl(120, 100%, 40%);">+#define Pgt(name) \</span><br><span style="color: hsl(120, 100%, 40%);">+      Pfv(name, "%s", osmo_gt_name(&subscr->name))</span><br><span> #define Pd(name) \</span><br><span>  Pfv(name, "%"PRId64, (int64_t)subscr->name)</span><br><span> #define Pd_nonzero(name) \</span><br><span>@@ -235,6 +238,14 @@</span><br><span> static const char *short_imsi = "123456";</span><br><span> static const char *unknown_imsi = "999999999";</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                      const char *vlr_or_sgsn_number, bool is_ps)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_gt vlr_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_gt_set_str(&vlr_nr, vlr_or_sgsn_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void test_subscr_create_update_sel_delete()</span><br><span> {</span><br><span>       int64_t id0, id1, id2, id_short;</span><br><span>@@ -386,39 +397,39 @@</span><br><span> </span><br><span>         comment("Record LU for PS and CS (SGSN and VLR names)");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ASSERT_RC(db_subscr_lu(dbc, id0, "5952", true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "5952", true), 0);</span><br><span>    ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, "712", false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "712", false), 0);</span><br><span>    ASSERT_SEL(id, id0, 0);</span><br><span> </span><br><span>  comment("Record LU for PS and CS (SGSN and VLR names) *again*");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);</span><br><span>     ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);</span><br><span>     ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);</span><br><span>    ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);</span><br><span>    ASSERT_SEL(id, id0, 0);</span><br><span> </span><br><span>  comment("Unset LU info for PS and CS (SGSN and VLR names)");</span><br><span style="color: hsl(0, 100%, 40%);">-  ASSERT_RC(db_subscr_lu(dbc, id0, "", true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ASSERT_RC(db_subscr_lu_str(dbc, id0, "", true), 0);</span><br><span>        ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, "", false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    ASSERT_RC(db_subscr_lu_str(dbc, id0, "", false), 0);</span><br><span>       ASSERT_SEL(id, id0, 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, id0, "111", true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ASSERT_RC(db_subscr_lu_str(dbc, id0, "222", false), 0);</span><br><span>    ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, NULL, true), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ASSERT_RC(db_subscr_lu_str(dbc, id0, NULL, true), 0);</span><br><span>        ASSERT_SEL(id, id0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ASSERT_RC(db_subscr_lu(dbc, id0, NULL, false), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    ASSERT_RC(db_subscr_lu_str(dbc, id0, NULL, false), 0);</span><br><span>       ASSERT_SEL(id, id0, 0);</span><br><span> </span><br><span>  comment("Record LU for non-existent ID");</span><br><span style="color: hsl(0, 100%, 40%);">-     ASSERT_RC(db_subscr_lu(dbc, 99999, "5952", true), -ENOENT);</span><br><span style="color: hsl(0, 100%, 40%);">-   ASSERT_RC(db_subscr_lu(dbc, 99999, "712", false), -ENOENT);</span><br><span style="color: hsl(120, 100%, 40%);">+ ASSERT_RC(db_subscr_lu_str(dbc, 99999, "5952", true), -ENOENT);</span><br><span style="color: hsl(120, 100%, 40%);">+     ASSERT_RC(db_subscr_lu_str(dbc, 99999, "712", false), -ENOENT);</span><br><span>    ASSERT_SEL(id, 99999, -ENOENT);</span><br><span> </span><br><span>  comment("Purge and un-purge PS and CS");</span><br><span>diff --git a/tests/db/db_test.err b/tests/db/db_test.err</span><br><span>index a3e4d58..87c7d0e 100644</span><br><span>--- a/tests/db/db_test.err</span><br><span>+++ b/tests/db/db_test.err</span><br><span>@@ -435,7 +435,7 @@</span><br><span> </span><br><span> --- Record LU for PS and CS (SGSN and VLR names)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "5952", true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "5952", true) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -445,7 +445,7 @@</span><br><span>   .sgsn_number = '5952',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "712", false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "712", false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -459,7 +459,7 @@</span><br><span> </span><br><span> --- Record LU for PS and CS (SGSN and VLR names) *again*</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "111", true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "111", true) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -470,7 +470,7 @@</span><br><span>   .sgsn_number = '111',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "111", true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "111", true) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -481,7 +481,7 @@</span><br><span>   .sgsn_number = '111',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "222", false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "222", false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -492,7 +492,7 @@</span><br><span>   .sgsn_number = '111',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "222", false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "222", false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -506,7 +506,7 @@</span><br><span> </span><br><span> --- Unset LU info for PS and CS (SGSN and VLR names)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "", true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "", true) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -516,7 +516,7 @@</span><br><span>   .vlr_number = '222',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "", false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "", false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -525,9 +525,9 @@</span><br><span>   .msisdn = '543210123456789',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "111", true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "111", true) --> 0</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, "222", false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, "222", false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -538,7 +538,7 @@</span><br><span>   .sgsn_number = '111',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, NULL, true) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, NULL, true) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -548,7 +548,7 @@</span><br><span>   .vlr_number = '222',</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, id0, NULL, false) --> 0</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, id0, NULL, false) --> 0</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0</span><br><span> struct hlr_subscriber {</span><br><span>@@ -560,10 +560,10 @@</span><br><span> </span><br><span> --- Record LU for non-existent ID</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, 99999, "5952", true) --> -ENOENT</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, 99999, "5952", true) --> -ENOENT</span><br><span> DAUC Cannot update SGSN number for subscriber ID=99999: no such subscriber</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-db_subscr_lu(dbc, 99999, "712", false) --> -ENOENT</span><br><span style="color: hsl(120, 100%, 40%);">+db_subscr_lu_str(dbc, 99999, "712", false) --> -ENOENT</span><br><span> DAUC Cannot update VLR number for subscriber ID=99999: no such subscriber</span><br><span> </span><br><span> db_subscr_get_by_id(dbc, 99999, &g_subscr) --> -ENOENT</span><br><span>diff --git a/tests/gsup_server/Makefile.am b/tests/gsup_server/Makefile.am</span><br><span>index e64ac4a..bdc9eca 100644</span><br><span>--- a/tests/gsup_server/Makefile.am</span><br><span>+++ b/tests/gsup_server/Makefile.am</span><br><span>@@ -31,6 +31,8 @@</span><br><span> gsup_server_test_LDADD = \</span><br><span>        $(top_srcdir)/src/gsup_server.c \</span><br><span>    $(top_srcdir)/src/gsup_router.c \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(top_srcdir)/src/gsupclient/global_title.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(top_srcdir)/src/gsupclient/gsup_req.c \</span><br><span>    $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOABIS_LIBS) \</span><br><span>diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty</span><br><span>index ccc30ba..dd8dbcf 100644</span><br><span>--- a/tests/test_nodes.vty</span><br><span>+++ b/tests/test_nodes.vty</span><br><span>@@ -150,6 +150,7 @@</span><br><span>  logging level db notice</span><br><span>  logging level auc notice</span><br><span>  logging level ss info</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level lu notice</span><br><span> ...</span><br><span> hlr</span><br><span>  store-imei</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hlr/+/16205">change 16205</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/+/16205"/><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: I3a8dff3d4a1cbe10d6ab08257a0138d6b2a082d9 </div>
<div style="display:none"> Gerrit-Change-Number: 16205 </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-MessageType: newchange </div>