<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/20357">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">LCS: implement the bulk of Location Services<br><br>Depends: I4d7302a4853518916b6b425e710c10568eb2ffe5 (libosmocore)<br>Change-Id: I28314ba97df86a118497e9b2770e2e6e2484e872<br>---<br>M TODO-RELEASE<br>M include/osmocom/bsc/Makefile.am<br>M include/osmocom/bsc/bsc_msc_data.h<br>M include/osmocom/bsc/bsc_subscr_conn_fsm.h<br>M include/osmocom/bsc/debug.h<br>M include/osmocom/bsc/gsm_data.h<br>A include/osmocom/bsc/lb.h<br>A include/osmocom/bsc/lcs_loc_req.h<br>A include/osmocom/bsc/lcs_ta_req.h<br>M include/osmocom/bsc/paging.h<br>M include/osmocom/bsc/vty.h<br>M src/osmo-bsc/Makefile.am<br>M src/osmo-bsc/bsc_init.c<br>M src/osmo-bsc/bsc_sccp.c<br>M src/osmo-bsc/bsc_subscr_conn_fsm.c<br>M src/osmo-bsc/gsm_04_08_rr.c<br>M src/osmo-bsc/gsm_08_08.c<br>M src/osmo-bsc/gsm_data.c<br>M src/osmo-bsc/handover_fsm.c<br>A src/osmo-bsc/lb.c<br>A src/osmo-bsc/lcs_loc_req.c<br>A src/osmo-bsc/lcs_ta_req.c<br>M src/osmo-bsc/net_init.c<br>M src/osmo-bsc/osmo_bsc_bssap.c<br>M src/osmo-bsc/osmo_bsc_main.c<br>M src/osmo-bsc/osmo_bsc_msc.c<br>M src/osmo-bsc/paging.c<br>M tests/bsc/bsc_test.c<br>M tests/handover/Makefile.am<br>M tests/timer.vty<br>30 files changed, 1,858 insertions(+), 17 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/TODO-RELEASE b/TODO-RELEASE</span><br><span>index f5d70c2..6a39a21 100644</span><br><span>--- a/TODO-RELEASE</span><br><span>+++ b/TODO-RELEASE</span><br><span>@@ -9,3 +9,4 @@</span><br><span> #library      what            description / commit summary line</span><br><span> manual                             needs common chapter cs7-config.adoc, vty_cpu_sched.adoc from osmo-gsm-manuals > 0.3.0</span><br><span> osmo-bsc   Mobile Identity Coding  OsmoBSC is stricter in rejecting invalid coding of Mobile Identity IEs</span><br><span style="color: hsl(120, 100%, 40%);">+libosmocore     >1.4.0 (1.4.1?)      need BSSMAP-LE, BSSLAP, GAD coding</span><br><span>diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am</span><br><span>index 1ee96ed..8c42287 100644</span><br><span>--- a/include/osmocom/bsc/Makefile.am</span><br><span>+++ b/include/osmocom/bsc/Makefile.am</span><br><span>@@ -27,9 +27,12 @@</span><br><span>     handover_fsm.h \</span><br><span>     handover_vty.h \</span><br><span>     ipaccess.h \</span><br><span style="color: hsl(120, 100%, 40%);">+  lb.h \</span><br><span>       lchan_fsm.h \</span><br><span>        lchan_rtp_fsm.h \</span><br><span>    lchan_select.h \</span><br><span style="color: hsl(120, 100%, 40%);">+      lcs_loc_req.h \</span><br><span style="color: hsl(120, 100%, 40%);">+       lcs_ta_req.h \</span><br><span>       meas_feed.h \</span><br><span>        meas_rep.h \</span><br><span>         misdn.h \</span><br><span>diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h</span><br><span>index 43ace25..5699b77 100644</span><br><span>--- a/include/osmocom/bsc/bsc_msc_data.h</span><br><span>+++ b/include/osmocom/bsc/bsc_msc_data.h</span><br><span>@@ -68,6 +68,8 @@</span><br><span>   MSC_CTR_BSSMAP_RX_DT1_UNKNOWN,</span><br><span>       MSC_CTR_BSSMAP_RX_DT1_DTAP,</span><br><span>  MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+     MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+       MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_ABORT,</span><br><span> </span><br><span>    /* Tx message counters (per connection type) */</span><br><span>      MSC_CTR_BSSMAP_TX_BSS_MANAGEMENT,</span><br><span>@@ -97,6 +99,8 @@</span><br><span>        MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE,</span><br><span>     MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE,</span><br><span>      MSC_CTR_BSSMAP_TX_DT1_DTAP,</span><br><span style="color: hsl(120, 100%, 40%);">+   MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,</span><br><span style="color: hsl(120, 100%, 40%);">+      MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,</span><br><span> </span><br><span>         MSC_CTR_MSCPOOL_SUBSCR_NEW,</span><br><span>  MSC_CTR_MSCPOOL_SUBSCR_REATTACH,</span><br><span>diff --git a/include/osmocom/bsc/bsc_subscr_conn_fsm.h b/include/osmocom/bsc/bsc_subscr_conn_fsm.h</span><br><span>index ccac4fa..142d535 100644</span><br><span>--- a/include/osmocom/bsc/bsc_subscr_conn_fsm.h</span><br><span>+++ b/include/osmocom/bsc/bsc_subscr_conn_fsm.h</span><br><span>@@ -44,6 +44,8 @@</span><br><span> </span><br><span>    GSCON_EV_FORGET_LCHAN,</span><br><span>       GSCON_EV_FORGET_MGW_ENDPOINT,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       GSCON_EV_LCS_LOC_REQ_END,</span><br><span> };</span><br><span> </span><br><span> struct gscon_clear_cmd_data {</span><br><span>diff --git a/include/osmocom/bsc/debug.h b/include/osmocom/bsc/debug.h</span><br><span>index 82c0703..0380b74 100644</span><br><span>--- a/include/osmocom/bsc/debug.h</span><br><span>+++ b/include/osmocom/bsc/debug.h</span><br><span>@@ -27,6 +27,7 @@</span><br><span>    DTS,</span><br><span>         DAS,</span><br><span>         DCBS,</span><br><span style="color: hsl(120, 100%, 40%);">+ DLCS,</span><br><span>        Debug_LastEntry,</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index 7021fa4..050cd7a 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -52,6 +52,7 @@</span><br><span> struct gprs_ra_id;</span><br><span> struct handover;</span><br><span> struct osmo_sccp_instance;</span><br><span style="color: hsl(120, 100%, 40%);">+struct smlc_config;</span><br><span> </span><br><span> #define OBSC_LINKID_CB(__msgb)  (__msgb)->cb[3]</span><br><span> </span><br><span>@@ -304,6 +305,23 @@</span><br><span>        uint8_t ms_power_class:3;</span><br><span> </span><br><span>        bool rx_clear_command;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Location Services handling for this subscriber */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* FSM to handle Perform Location Request coming in from the MSC via A interface,</span><br><span style="color: hsl(120, 100%, 40%);">+              * and receive BSSMAP-LE responses from the SMLC. */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct lcs_loc_req *loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* FSM to handle BSSLAP requests coming in from the SMLC via Lb interface.</span><br><span style="color: hsl(120, 100%, 40%);">+             * BSSLAP APDU are encapsulated in BSSMAP-LE Connection Oriented Information messages. */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct lcs_bsslap *bsslap;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Lb interface to the SMLC: BSSMAP-LE/SCCP connection associated with this subscriber */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      int conn_id;</span><br><span style="color: hsl(120, 100%, 40%);">+                  enum subscr_sccp_state state;</span><br><span style="color: hsl(120, 100%, 40%);">+         } lb;</span><br><span style="color: hsl(120, 100%, 40%);">+ } lcs;</span><br><span> };</span><br><span> </span><br><span> </span><br><span>@@ -1200,6 +1218,8 @@</span><br><span> </span><br><span>     uint8_t nri_bitlen;</span><br><span>  struct osmo_nri_ranges *null_nri_ranges;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct smlc_config *smlc;</span><br><span> };</span><br><span> </span><br><span> struct gsm_audio_support {</span><br><span>diff --git a/include/osmocom/bsc/lb.h b/include/osmocom/bsc/lb.h</span><br><span>new file mode 100644</span><br><span>index 0000000..0649986</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/bsc/lb.h</span><br><span>@@ -0,0 +1,60 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Location Services (LCS): low level Lb/SCCP handling in OsmoBSC, API */</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sigtran/sccp_sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bssap_le_pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_subscriber_connection;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+        SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER,</span><br><span style="color: hsl(120, 100%, 40%);">+   SMLC_CTR_BSSMAP_LE_RX_UDT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+      SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+  SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG,</span><br><span style="color: hsl(120, 100%, 40%);">+    SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG,</span><br><span style="color: hsl(120, 100%, 40%);">+    SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,</span><br><span style="color: hsl(120, 100%, 40%);">+  SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+  SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        SMLC_CTR_BSSMAP_LE_TX_ERR_INVALID_MSG,</span><br><span style="color: hsl(120, 100%, 40%);">+        SMLC_CTR_BSSMAP_LE_TX_ERR_CONN_NOT_READY,</span><br><span style="color: hsl(120, 100%, 40%);">+     SMLC_CTR_BSSMAP_LE_TX_ERR_SEND,</span><br><span style="color: hsl(120, 100%, 40%);">+       SMLC_CTR_BSSMAP_LE_TX_SUCCESS,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      SMLC_CTR_BSSMAP_LE_TX_UDT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+      SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+  SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST,</span><br><span style="color: hsl(120, 100%, 40%);">+   SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+     SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+ SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT,</span><br><span style="color: hsl(120, 100%, 40%);">+      SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+       SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT,</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 smlc_config {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t cs7_instance;</span><br><span style="color: hsl(120, 100%, 40%);">+        bool cs7_instance_valid;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sccp_instance *sccp;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sccp_user *sccp_user;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_sccp_addr bsc_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *bsc_addr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sccp_addr smlc_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *smlc_addr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! True after either side has sent a BSSMAP-LE RESET-ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+  bool ready;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rate_ctr_group *ctrs;</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%);">+extern const struct rate_ctr_desc smlc_ctr_description[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct rate_ctr_group_desc smlc_ctrg_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int lb_init();</span><br><span style="color: hsl(120, 100%, 40%);">+int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+void lb_close_conn(struct gsm_subscriber_connection *conn);</span><br><span>diff --git a/include/osmocom/bsc/lcs_loc_req.h b/include/osmocom/bsc/lcs_loc_req.h</span><br><span>new file mode 100644</span><br><span>index 0000000..ba677e8</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/bsc/lcs_loc_req.h</span><br><span>@@ -0,0 +1,48 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Location Services (LCS): BSSMAP and BSSMAP-LE Perform Location Request handling in OsmoBSC, API */</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/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_LCS_LOC_REQ(LOC_REQ, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+           if (LOC_REQ) \</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGPFSML((LOC_REQ)->fi, level, fmt, ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+            else \</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLCS, level, "LCS Perf Loc Req: " fmt, ## args); \</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%);">+struct lcs_ta_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum lcs_loc_req_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+      LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+       LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+   LCS_LOC_REQ_EV_TA_REQ_START,</span><br><span style="color: hsl(120, 100%, 40%);">+  LCS_LOC_REQ_EV_TA_REQ_END,</span><br><span style="color: hsl(120, 100%, 40%);">+    LCS_LOC_REQ_EV_HANDOVER_PERFORMED,</span><br><span style="color: hsl(120, 100%, 40%);">+    LCS_LOC_REQ_EV_CONN_CLEAR,</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 lcs_loc_req {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_subscriber_connection *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct bssmap_le_location_type location_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               bool cell_id_present;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct gsm0808_cell_id cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_mobile_identity imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_mobile_identity imei;</span><br><span style="color: hsl(120, 100%, 40%);">+     } req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      bool resp_present;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bssmap_le_perform_loc_resp resp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lcs_cause_ie lcs_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct lcs_ta_req *ta_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 lcs_loc_req_start(struct gsm_subscriber_connection *conn, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int lcs_loc_req_rx_bssmap_le(struct gsm_subscriber_connection *conn, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+void lcs_loc_req_reset(struct gsm_subscriber_connection *conn);</span><br><span>diff --git a/include/osmocom/bsc/lcs_ta_req.h b/include/osmocom/bsc/lcs_ta_req.h</span><br><span>new file mode 100644</span><br><span>index 0000000..b9b7a4e</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/bsc/lcs_ta_req.h</span><br><span>@@ -0,0 +1,29 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Location Services (LCS): BSSLAP TA Request handling in OsmoBSC, API */</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/bsc/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.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/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_LCS_TA_REQ(TA_REQ, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+   if (TA_REQ) \</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPFSML((TA_REQ)->fi, level, fmt, ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+     else \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLCS, level, "LCS TA Req: " fmt, ## args); \</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%);">+enum lcs_ta_req_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+     LCS_TA_REQ_EV_GOT_TA,</span><br><span style="color: hsl(120, 100%, 40%);">+ LCS_TA_REQ_EV_ABORT,</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 lcs_ta_req {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lcs_loc_req *loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+  enum lcs_cause failure_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t failure_diagnostic_val;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+int lcs_ta_req_start(struct lcs_loc_req *lcs_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void lcs_bsslap_rx(struct gsm_subscriber_connection *conn, struct msgb *msg);</span><br><span>diff --git a/include/osmocom/bsc/paging.h b/include/osmocom/bsc/paging.h</span><br><span>index cd351cb..2d0f8da 100644</span><br><span>--- a/include/osmocom/bsc/paging.h</span><br><span>+++ b/include/osmocom/bsc/paging.h</span><br><span>@@ -94,6 +94,7 @@</span><br><span> </span><br><span> int paging_request_stop(struct bsc_msc_data **msc_p, enum bsc_paging_reason *reasons_p,</span><br><span>                         struct gsm_bts *bts, struct bsc_subscr *bsub);</span><br><span style="color: hsl(120, 100%, 40%);">+int paging_request_cancel(struct bsc_subscr *bsub, enum bsc_paging_reason reasons);</span><br><span> </span><br><span> /* update paging load */</span><br><span> void paging_update_buffer_space(struct gsm_bts *bts, uint16_t);</span><br><span>diff --git a/include/osmocom/bsc/vty.h b/include/osmocom/bsc/vty.h</span><br><span>index a5a8452..d2361b0 100644</span><br><span>--- a/include/osmocom/bsc/vty.h</span><br><span>+++ b/include/osmocom/bsc/vty.h</span><br><span>@@ -27,6 +27,7 @@</span><br><span>  CBC_NODE,</span><br><span>    CBC_SERVER_NODE,</span><br><span>     CBC_CLIENT_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+      SMLC_NODE,</span><br><span> };</span><br><span> </span><br><span> struct log_info;</span><br><span>diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am</span><br><span>index b0fc181..8d109fd 100644</span><br><span>--- a/src/osmo-bsc/Makefile.am</span><br><span>+++ b/src/osmo-bsc/Makefile.am</span><br><span>@@ -65,9 +65,12 @@</span><br><span>   handover_fsm.c \</span><br><span>     handover_logic.c \</span><br><span>   handover_vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      lb.c \</span><br><span>       lchan_fsm.c \</span><br><span>        lchan_rtp_fsm.c \</span><br><span>    lchan_select.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      lcs_loc_req.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       lcs_ta_req.c \</span><br><span>       meas_feed.c \</span><br><span>        meas_rep.c \</span><br><span>         neighbor_ident.c \</span><br><span>diff --git a/src/osmo-bsc/bsc_init.c b/src/osmo-bsc/bsc_init.c</span><br><span>index 1460af4..b959c9f 100644</span><br><span>--- a/src/osmo-bsc/bsc_init.c</span><br><span>+++ b/src/osmo-bsc/bsc_init.c</span><br><span>@@ -37,6 +37,7 @@</span><br><span> #include <osmocom/bsc/gsm_04_08_rr.h></span><br><span> #include <osmocom/bsc/neighbor_ident.h></span><br><span> #include <osmocom/bsc/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.h></span><br><span> </span><br><span> #include <osmocom/bsc/smscb.h></span><br><span> #include <osmocom/gsm/protocol/gsm_48_049.h></span><br><span>diff --git a/src/osmo-bsc/bsc_sccp.c b/src/osmo-bsc/bsc_sccp.c</span><br><span>index 9d4289f..0cd1dc9 100644</span><br><span>--- a/src/osmo-bsc/bsc_sccp.c</span><br><span>+++ b/src/osmo-bsc/bsc_sccp.c</span><br><span>@@ -23,6 +23,7 @@</span><br><span> </span><br><span> #include <osmocom/bsc/gsm_data.h></span><br><span> #include <osmocom/bsc/bsc_msc_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.h></span><br><span> </span><br><span> /* We need an unused SCCP conn_id across all SCCP users. */</span><br><span> int bsc_sccp_inst_next_conn_id(struct osmo_sccp_instance *sccp)</span><br><span>@@ -47,7 +48,13 @@</span><br><span>                          }</span><br><span>                    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   /* Future for LCS: also check Lb-interface conn IDs here */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (bsc_gsmnet->smlc->sccp == sccp</span><br><span style="color: hsl(120, 100%, 40%);">+                          && conn->lcs.lb.state != SUBSCR_SCCP_ST_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (conn_id == conn->lcs.lb.conn_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     conn_id_already_used = true;</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>            }</span><br><span> </span><br><span>                if (!conn_id_already_used)</span><br><span>diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c</span><br><span>index b127e7f..5893ea3 100644</span><br><span>--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c</span><br><span>+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c</span><br><span>@@ -46,6 +46,8 @@</span><br><span> #include <osmocom/bsc/codec_pref.h></span><br><span> #include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h></span><br><span> #include <osmocom/core/byteswap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span> </span><br><span> #define S(x)      (1 << (x))</span><br><span> </span><br><span>@@ -86,6 +88,7 @@</span><br><span>     {GSCON_EV_LCLS_FAIL, "LCLS_FAIL"},</span><br><span>         {GSCON_EV_FORGET_LCHAN, "FORGET_LCHAN"},</span><br><span>   {GSCON_EV_FORGET_MGW_ENDPOINT, "FORGET_MGW_ENDPOINT"},</span><br><span style="color: hsl(120, 100%, 40%);">+      {GSCON_EV_LCS_LOC_REQ_END, "LCS_LOC_REQ_END"},</span><br><span>     {}</span><br><span> };</span><br><span> </span><br><span>@@ -249,22 +252,41 @@</span><br><span> </span><br><span>     switch (bssmap_type) {</span><br><span>       case BSS_MAP_MSG_HANDOVER_RQST:</span><br><span style="color: hsl(0, 100%, 40%);">-         /* First off, accept the new conn. */</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_sccp_tx_conn_resp(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      &scu_prim->u.connect.called_addr, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSS_MAP_MSG_PERFORM_LOCATION_RQST:</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              /* Make sure the conn FSM will osmo_sccp_tx_disconn() on term */</span><br><span style="color: hsl(0, 100%, 40%);">-                conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPFSML(fi, LOGL_NOTICE, "No support for N-CONNECT: %s: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      gsm0808_bssap_name(bs->type), gsm0808_bssmap_name(bssmap_type));</span><br><span style="color: hsl(120, 100%, 40%);">+          goto refuse;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* First off, accept the new conn. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osmo_sccp_tx_conn_resp(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                            &scu_prim->u.connect.called_addr, NULL, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGPFSML(fi, LOGL_ERROR, "Cannot send SCCP CONN RESP\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           goto refuse;</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%);">+   /* Make sure the conn FSM will osmo_sccp_tx_disconn() on term */</span><br><span style="color: hsl(120, 100%, 40%);">+      conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (bssmap_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSS_MAP_MSG_HANDOVER_RQST:</span><br><span>              /* Inter-BSC MT Handover Request, another BSS is handovering to us. */</span><br><span>               handover_start_inter_bsc_in(conn, msg);</span><br><span>              return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSS_MAP_MSG_PERFORM_LOCATION_RQST:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Location Services: MSC asks for location of an IDLE subscriber */</span><br><span style="color: hsl(120, 100%, 40%);">+          conn_fsm_state_chg(ST_ACTIVE);</span><br><span style="color: hsl(120, 100%, 40%);">+                lcs_loc_req_start(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    default:</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(false);</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOGPFSML(fi, LOGL_NOTICE, "No support for N-CONNECT: %s: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                gsm0808_bssap_name(bs->type), gsm0808_bssmap_name(bssmap_type));</span><br><span> refuse:</span><br><span>      osmo_sccp_tx_disconn(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id,</span><br><span>                           &scu_prim->u.connect.called_addr, 0);</span><br><span>@@ -404,6 +426,14 @@</span><br><span>     case GSCON_EV_TX_SCCP:</span><br><span>               gscon_sigtran_send(conn, (struct msgb *)data);</span><br><span>               break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case GSCON_EV_LCS_LOC_REQ_END:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* On the A-interface, there is nothing to do. If there still is an lchan, the conn should stay open. If</span><br><span style="color: hsl(120, 100%, 40%);">+               * not, it is up to the MSC to send a Clear Command.</span><br><span style="color: hsl(120, 100%, 40%);">+           * On the Lb-interface, tear down the SCCP connection. */</span><br><span style="color: hsl(120, 100%, 40%);">+             lb_close_conn(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     default:</span><br><span>             OSMO_ASSERT(false);</span><br><span>  }</span><br><span>@@ -628,7 +658,8 @@</span><br><span>      [ST_ACTIVE] = {</span><br><span>              .name = "ACTIVE",</span><br><span>          .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_ASSIGNMENT_START) |</span><br><span style="color: hsl(0, 100%, 40%);">-                            S(GSCON_EV_HANDOVER_START),</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(GSCON_EV_HANDOVER_START)</span><br><span style="color: hsl(120, 100%, 40%);">+                            | S(GSCON_EV_LCS_LOC_REQ_END),</span><br><span>              .out_state_mask = S(ST_CLEARING) | S(ST_ASSIGNMENT) |</span><br><span>                                  S(ST_HANDOVER),</span><br><span>            .action = gscon_fsm_active,</span><br><span>@@ -656,6 +687,9 @@</span><br><span>    /* On release, do not receive release events that look like the primary lchan is gone. */</span><br><span>    struct gsm_lchan *old_lchan = conn->lchan;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     if (old_lchan == new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    conn->lchan = new_lchan;</span><br><span>  conn->lchan->conn = conn;</span><br><span> </span><br><span>@@ -738,7 +772,8 @@</span><br><span>    if ((conn->fi && conn->fi->state != ST_CLEARING)</span><br><span>        && !conn->lchan</span><br><span>           && !conn->ho.new_lchan</span><br><span style="color: hsl(0, 100%, 40%);">-       && !conn->assignment.new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+            && !conn->assignment.new_lchan</span><br><span style="color: hsl(120, 100%, 40%);">+     && !conn->lcs.loc_req)</span><br><span>                gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);</span><br><span> }</span><br><span> </span><br><span>@@ -777,6 +812,9 @@</span><br><span>            if (conn->ho.fi)</span><br><span>                  osmo_fsm_inst_dispatch(conn->ho.fi, HO_EV_CONN_RELEASING, NULL);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+               if (conn->lcs.loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_CONN_CLEAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>              OSMO_ASSERT(data);</span><br><span>           ccd = data;</span><br><span>          if (conn->lchan)</span><br><span>@@ -846,6 +884,8 @@</span><br><span>    lchan_forget_conn(conn->assignment.new_lchan);</span><br><span>    lchan_forget_conn(conn->ho.new_lchan);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ lb_close_conn(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       if (conn->sccp.state != SUBSCR_SCCP_ST_NONE) {</span><br><span>            LOGPFSML(fi, LOGL_DEBUG, "Disconnecting SCCP\n");</span><br><span>          struct bsc_msc_data *msc = conn->sccp.msc;</span><br><span>diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c</span><br><span>index 49ec848..a448126 100644</span><br><span>--- a/src/osmo-bsc/gsm_04_08_rr.c</span><br><span>+++ b/src/osmo-bsc/gsm_04_08_rr.c</span><br><span>@@ -1027,7 +1027,6 @@</span><br><span>                * MSC */</span><br><span>            dispatch_dtap(lchan->conn, link_id, msg);</span><br><span>         } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */</span><br><span>                return bsc_compl_l3(lchan, msg, 0);</span><br><span>  }</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c</span><br><span>index b7c7448..cd8b77f 100644</span><br><span>--- a/src/osmo-bsc/gsm_08_08.c</span><br><span>+++ b/src/osmo-bsc/gsm_08_08.c</span><br><span>@@ -30,6 +30,9 @@</span><br><span> #include <osmocom/bsc/gsm_04_08_rr.h></span><br><span> #include <osmocom/bsc/a_reset.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_ta_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <osmocom/gsm/protocol/gsm_08_08.h></span><br><span> #include <osmocom/gsm/gsm0808.h></span><br><span> #include <osmocom/gsm/mncc.h></span><br><span>@@ -495,6 +498,10 @@</span><br><span> </span><br><span>        parse_powercap(conn, msg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* If a BSSLAP TA Request from the SMLC is waiting for a TA value, we have one now. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (conn->lcs.loc_req && conn->lcs.loc_req->ta_req)</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_fsm_inst_dispatch(conn->lcs.loc_req->ta_req->fi, LCS_TA_REQ_EV_GOT_TA, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        /* If the Paging was issued only by OsmoBSC for LCS, don't bother to establish Layer 3 to the MSC. */</span><br><span>    if (paged_from_msc && !(paging_reasons & BSC_PAGING_FROM_CN)) {</span><br><span>          LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG,</span><br><span>diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c</span><br><span>index fbc2ae2..1152783 100644</span><br><span>--- a/src/osmo-bsc/gsm_data.c</span><br><span>+++ b/src/osmo-bsc/gsm_data.c</span><br><span>@@ -45,6 +45,7 @@</span><br><span> #include <osmocom/bsc/timeslot_fsm.h></span><br><span> #include <osmocom/bsc/lchan_fsm.h></span><br><span> #include <osmocom/bsc/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bsc_msc_data.h></span><br><span> </span><br><span> void *tall_bsc_ctx = NULL;</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c</span><br><span>index 8e231e0..573f249 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -44,6 +44,7 @@</span><br><span> #include <osmocom/bsc/codec_pref.h></span><br><span> #include <osmocom/bsc/gsm_08_08.h></span><br><span> #include <osmocom/bsc/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span> </span><br><span> #define LOG_FMT_BTS "bts %u lac-ci %u-%u arfcn-bsic %d-%d"</span><br><span> #define LOG_ARGS_BTS(bts) \</span><br><span>@@ -938,6 +939,10 @@</span><br><span>    if (ho->new_lchan && result == HO_RESULT_OK) {</span><br><span>            gscon_change_primary_lchan(conn, conn->ho.new_lchan);</span><br><span>             ho->new_lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* If a Perform Location Request (LCS) is busy, inform the SMLC that there is a new lchan */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (conn->lcs.loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_HANDOVER_PERFORMED, NULL);</span><br><span>        }</span><br><span> </span><br><span>        osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_HANDOVER_END, &result);</span><br><span>diff --git a/src/osmo-bsc/lb.c b/src/osmo-bsc/lb.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6ab131f</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/lb.c</span><br><span>@@ -0,0 +1,662 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Lb interface low level SCCP handling */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <osmocom/bsc/lb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sigtran/sccp_helpers.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/osmo_bsc_sigtran.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_subscriber_connection *get_bsc_conn_by_lb_conn_id(int conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_subscriber_connection *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (conn->lcs.lb.state != SUBSCR_SCCP_ST_NONE</span><br><span style="color: hsl(120, 100%, 40%);">+                  && conn->lcs.lb.conn_id == conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return conn;</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 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%);">+/* Send reset to SMLC */</span><br><span style="color: hsl(120, 100%, 40%);">+int bssmap_le_tx_reset()</span><br><span style="color: hsl(120, 100%, 40%);">+ // TODO use this -- patch coming up</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssap_le_pdu reset = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .reset = GSM0808_CAUSE_EQUIPMENT_FAILURE,</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%);">+  ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DLCS, LOGL_NOTICE, "Sending RESET to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = osmo_bssap_le_enc(&reset);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET]);</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     &bsc_gsmnet->smlc->smlc_addr, 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%);">+/* Send reset-ack to SMLC */</span><br><span style="color: hsl(120, 100%, 40%);">+int bssmap_le_tx_reset_ack()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssap_le_pdu reset_ack = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_RESET_ACK,</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%);">+  ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DLCS, LOGL_NOTICE, "Tx RESET ACK to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+    msg = osmo_bssap_le_enc(&reset_ack);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     &bsc_gsmnet->smlc->smlc_addr, 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%);">+static int bssmap_le_handle_reset(const struct bssmap_le_pdu *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_subscriber_connection *conn;</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%);">+     /* Abort all ongoing Location Requests */</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry)</span><br><span style="color: hsl(120, 100%, 40%);">+           lcs_loc_req_reset(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = bssmap_le_tx_reset_ack();</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!rc)</span><br><span style="color: hsl(120, 100%, 40%);">+              bsc_gsmnet->smlc->ready = true;</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%);">+static int bssmap_le_handle_reset_ack()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   bsc_gsmnet->smlc->ready = true;</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 int handle_unitdata_from_smlc(const struct osmo_sccp_addr *smlc_addr, struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     const struct osmo_sccp_user *scu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssap_le_pdu bssap_le;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_bssap_le_err *err;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct rate_ctr *ctr = bsc_gsmnet->smlc->ctrs->ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_sccp_addr_cmp(smlc_addr, &bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_ADDR_T_MASK)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLCS, LOGL_ERROR, "Rx BSSMAP-LE UnitData from unknown remote address: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_sccp_addr_name(ss7, smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+            rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER]);</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%);">+   if (osmo_bssap_le_dec(&bssap_le, &err, msg, msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLCS, LOGL_ERROR, "Rx BSSAP-LE UnitData with error: %s\n", err->logmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+            rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_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%);">+   if (bssap_le.discr != BSSAP_LE_MSG_DISCR_BSSMAP_LE) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLCS, LOGL_ERROR, "Rx BSSAP-LE: discr %d not implemented\n", bssap_le.discr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -ENOTSUP;</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 (bssap_le.bssmap_le.msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+            rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET]);</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLCS, LOGL_NOTICE, "RESET from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+              return bssmap_le_handle_reset(&bssap_le.bssmap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+       case BSSMAP_LE_MSGT_RESET_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+                rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK]);</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DLCS, LOGL_NOTICE, "RESET-ACK from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+          return bssmap_le_handle_reset_ack();</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG]);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLCS, LOGL_ERROR, "Rx unimplemented UDT message type %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_bssap_le_pdu_to_str_c(OTC_SELECT, &bssap_le));</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sccp_user *scu = _scu;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_subscriber_connection *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (OSMO_PRIM_HDR(&scu_prim->oph)) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Handle inbound UnitData */</span><br><span style="color: hsl(120, 100%, 40%);">+         DEBUGP(DLCS, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = handle_unitdata_from_smlc(&scu_prim->u.unitdata.calling_addr, oph->msg, scu);</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_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Handle inbound connections. A Location Request is always started on the A interface, and OsmoBSC</span><br><span style="color: hsl(120, 100%, 40%);">+            * forwards this to the SMLC by performing an N-CONNECT from BSC -> SMLC. This is the reverse</span><br><span style="color: hsl(120, 100%, 40%);">+               * direction: N-CONNECT from SMLC -> BSC, which should never happen. */</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLCS, LOGL_ERROR, "N-CONNECT.ind(X->%u): inbound connect from SMLC is not expected to happen\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 scu_prim->u.connect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0);</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_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Handle inbound confirmation of outbound connection */</span><br><span style="color: hsl(120, 100%, 40%);">+              DEBUGP(DLCS, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.connect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   conn->lcs.lb.state = SUBSCR_SCCP_ST_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (msgb_l2len(oph->msg) > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         rc = lcs_loc_req_rx_bssmap_le(conn, oph->msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DLCS, LOGL_ERROR, "N-CONNECT.cfm(%u) for unknown conn\n", scu_prim->u.connect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Handle incoming connection oriented data */</span><br><span style="color: hsl(120, 100%, 40%);">+                DEBUGP(DLCS, "N-DATA.ind(%u)\n", scu_prim->u.data.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.data.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DLCS, LOGL_ERROR, "N-DATA.ind(%u) for unknown conn_id\n", scu_prim->u.data.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                        rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         } else if (conn->lcs.lb.state != SUBSCR_SCCP_ST_CONNECTED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGP(DLCS, LOGL_ERROR, "N-DATA.ind(%u) for conn that is not confirmed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        scu_prim->u.data.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      rc = lcs_loc_req_rx_bssmap_le(conn, oph->msg);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):</span><br><span style="color: hsl(120, 100%, 40%);">+               DEBUGP(DLCS, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)),</span><br><span style="color: hsl(120, 100%, 40%);">+                  scu_prim->u.disconnect.cause);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* indication of disconnect */</span><br><span style="color: hsl(120, 100%, 40%);">+                conn = get_bsc_conn_by_lb_conn_id(scu_prim->u.disconnect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DLCS, LOGL_ERROR, "N-DISCONNECT.ind for unknown conn_id %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      scu_prim->u.disconnect.conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                      rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      conn->lcs.lb.state = SUBSCR_SCCP_ST_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (msgb_l2len(oph->msg) > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         rc = lcs_loc_req_rx_bssmap_le(conn, oph->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%);">+             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%);">+              LOGP(DLCS, LOGL_ERROR, "Unhandled SIGTRAN operation %s on primitive %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               get_value_string(osmo_prim_op_names, oph->operation), oph->primitive);</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%);">+   msgb_free(oph->msg);</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%);">+static int lb_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+        int conn_id;</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%);">+     OSMO_ASSERT(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn->lcs.lb.state != SUBSCR_SCCP_ST_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "Cannot open BSSMAP-LE conn to SMLC, another conn is still active for this subscriber\n");</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%);">+   conn_id = bsc_sccp_inst_next_conn_id(bsc_gsmnet->smlc->sccp);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_id < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Unable to allocate SCCP Connection ID for BSSMAP-LE to SMLC\n");</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%);">+     conn->lcs.lb.conn_id = conn_id;</span><br><span style="color: hsl(120, 100%, 40%);">+    ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPFSMSL(conn->fi, DLCS, LOGL_INFO, "Opening new SCCP connection (id=%i) to SMLC: %s\n", conn_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_sccp_tx_conn_req_msg(bsc_gsmnet->smlc->sccp_user, conn_id, &bsc_gsmnet->smlc->bsc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    &bsc_gsmnet->smlc->smlc_addr, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               conn->lcs.lb.state = SUBSCR_SCCP_ST_WAIT_CONN_CONF;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void lb_close_conn(struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (conn->lcs.lb.state == SUBSCR_SCCP_ST_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_sccp_tx_disconn(bsc_gsmnet->smlc->sccp_user, conn->lcs.lb.conn_id, &bsc_gsmnet->smlc->bsc_addr, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   conn->lcs.lb.state = SUBSCR_SCCP_ST_NONE;</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%);">+/* Send data to SMLC, take ownership of *msg */</span><br><span style="color: hsl(120, 100%, 40%);">+int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msg = osmo_bssap_le_enc(bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Failed to encode %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));</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%);">+   if (conn->lcs.lb.state == SUBSCR_SCCP_ST_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = lb_open_conn(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         goto count_tx;</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%);">+   LOGPFSMSL(conn->fi, DLCS, LOGL_DEBUG, "Tx %s\n", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = osmo_sccp_tx_data_msg(bsc_gsmnet->smlc->sccp_user, conn->lcs.lb.conn_id, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+count_tx:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</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%);">+  switch (bssap_le->bssmap_le.msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+          rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_PERFORM_LOC_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+                rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT]);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (bssap_le->bssmap_le.conn_oriented_info.apdu.msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+            case BSSLAP_MSGT_TA_RESPONSE:</span><br><span style="color: hsl(120, 100%, 40%);">+                 rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE]);</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case BSSLAP_MSGT_REJECT:</span><br><span style="color: hsl(120, 100%, 40%);">+                      rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT]);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case BSSLAP_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+                       rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case BSSLAP_MSGT_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+                       rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     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%);">+/* Default point-code to be used as local address (BSC) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define BSC_DEFAULT_PC "0.23.3"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Default point-code to be used as remote address (SMLC) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define SMLC_DEFAULT_PC "0.23.6"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_ASP_LOCAL_IP "localhost"</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_ASP_REMOTE_IP "localhost"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Initialize Lb interface to SMLC */</span><br><span style="color: hsl(120, 100%, 40%);">+int lb_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t default_pc;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ss7_instance *cs7_inst = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_sccp_instance *sccp;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum osmo_ss7_asp_protocol used_proto = OSMO_SS7_ASP_PROT_M3UA;</span><br><span style="color: hsl(120, 100%, 40%);">+       char inst_name[32];</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *smlc_name = "smlc";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!bsc_gsmnet->smlc) {</span><br><span style="color: hsl(120, 100%, 40%);">+           bsc_gsmnet->smlc = talloc_zero(bsc_gsmnet, struct smlc_config);</span><br><span style="color: hsl(120, 100%, 40%);">+            bsc_gsmnet->smlc->ctrs = rate_ctr_group_alloc(bsc_gsmnet, &smlc_ctrg_desc, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(bsc_gsmnet->smlc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!bsc_gsmnet->smlc->cs7_instance_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+            bsc_gsmnet->smlc->cs7_instance = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     cs7_inst = osmo_ss7_instance_find_or_create(tall_bsc_ctx, bsc_gsmnet->smlc->cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(cs7_inst);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If unset, use default SCCP address for the SMLC */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!bsc_gsmnet->smlc->smlc_addr.presence)</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_sccp_make_addr_pc_ssn(&bsc_gsmnet->smlc->smlc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_ss7_pointcode_parse(NULL, SMLC_DEFAULT_PC),</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SCCP_SSN_SMLC_BSSAP_LE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Set up SCCP user and one ASP+AS */</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(inst_name, sizeof(inst_name), "Lb-%u-%s", cs7_inst->cfg.id, osmo_ss7_asp_protocol_name(used_proto));</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGP(DLCS, LOGL_NOTICE, "Initializing SCCP connection for Lb/%s on cs7 instance %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_ss7_asp_protocol_name(used_proto), cs7_inst->cfg.id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* SS7 Protocol stack */</span><br><span style="color: hsl(120, 100%, 40%);">+      default_pc = osmo_ss7_pointcode_parse(NULL, BSC_DEFAULT_PC);</span><br><span style="color: hsl(120, 100%, 40%);">+  sccp = osmo_sccp_simple_client_on_ss7_id(tall_bsc_ctx, cs7_inst->cfg.id, inst_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 default_pc, used_proto,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               0, DEFAULT_ASP_LOCAL_IP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              0, DEFAULT_ASP_REMOTE_IP);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!sccp)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       bsc_gsmnet->smlc->sccp = sccp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* If unset, use default local SCCP address */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!bsc_gsmnet->smlc->bsc_addr.presence)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_sccp_local_addr_by_instance(&bsc_gsmnet->smlc->bsc_addr, sccp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          OSMO_SCCP_SSN_BSC_BSSAP_LE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc->bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLCS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "%s %s: invalid local (BSC) SCCP address: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->bsc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLCS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "%s %s: invalid remote (SMLC) SCCP address: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DLCS, LOGL_NOTICE, "Lb: %s %s: local (BSC) SCCP address: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->bsc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGP(DLCS, LOGL_NOTICE, "Lb: %s %s: remote (SMLC) SCCP address: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->smlc_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Bind SCCP user. */</span><br><span style="color: hsl(120, 100%, 40%);">+ bsc_gsmnet->smlc->sccp_user = osmo_sccp_user_find(sccp, bsc_gsmnet->smlc->bsc_addr.ssn, bsc_gsmnet->smlc->bsc_addr.pc);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DLCS, LOGL_NOTICE, "%s %s: %s\n", inst_name, smlc_name,</span><br><span style="color: hsl(120, 100%, 40%);">+             bsc_gsmnet->smlc->sccp_user ? "user already bound for this SCCP instance" : "binding SCCP user");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bsc_gsmnet->smlc->sccp_user)</span><br><span style="color: hsl(120, 100%, 40%);">+               bsc_gsmnet->smlc->sccp_user = osmo_sccp_user_bind(sccp, smlc_name, sccp_sap_up, bsc_gsmnet->smlc->bsc_addr.ssn);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!bsc_gsmnet->smlc->sccp_user)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*********************************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * VTY Interface (Configuration + Introspection)</span><br><span style="color: hsl(120, 100%, 40%);">+ *********************************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_smlc, cfg_smlc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+    "smlc", "Configure Lb Link to Serving Mobile Location Centre\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       vty->node = SMLC_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node smlc_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+        SMLC_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+    "%s(config-smlc)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+        1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void enforce_ssn(struct vty *vty, struct osmo_sccp_addr *addr, enum osmo_sccp_ssn want_ssn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (addr->presence & OSMO_SCCP_ADDR_T_SSN) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (addr->ssn != want_ssn)</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty,</span><br><span style="color: hsl(120, 100%, 40%);">+                          "setting an SSN (%u) different from the standard (%u) is not allowed, will use standard SSN for address: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             addr->ssn, want_ssn, osmo_sccp_addr_dump(addr), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   addr->presence |= OSMO_SCCP_ADDR_T_SSN;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr->ssn = want_ssn;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_smlc_cs7_bsc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_smlc_cs7_bsc_addr_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "bsc-addr NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Local SCCP address of this BSC towards the SMLC\n" "Name of cs7 addressbook entry\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *bsc_addr_name = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc->bsc_addr, bsc_addr_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ss7) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "Error: No such SCCP addressbook entry: '%s'%s", bsc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_ERR_INCOMPLETE;</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%);">+   /* Prevent mixing addresses from different CS7 instances */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (bsc_gsmnet->smlc->cs7_instance_valid</span><br><span style="color: hsl(120, 100%, 40%);">+            && bsc_gsmnet->smlc->cs7_instance != ss7->cfg.id) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty,</span><br><span style="color: hsl(120, 100%, 40%);">+                  "Error: SCCP addressbook entry from mismatching CS7 instance: '%s'%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      bsc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bsc_gsmnet->smlc->cs7_instance = ss7->cfg.id;</span><br><span style="color: hsl(120, 100%, 40%);">+        bsc_gsmnet->smlc->cs7_instance_valid = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    enforce_ssn(vty, &bsc_gsmnet->smlc->bsc_addr, OSMO_SCCP_SSN_BSC_BSSAP_LE);</span><br><span style="color: hsl(120, 100%, 40%);">+  bsc_gsmnet->smlc->bsc_addr_name = talloc_strdup(bsc_gsmnet, bsc_addr_name);</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_smlc_cs7_smlc_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_smlc_cs7_smlc_addr_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "smlc-addr NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Remote SCCP address of the SMLC\n" "Name of cs7 addressbook entry\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *smlc_addr_name = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc->smlc_addr, smlc_addr_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ss7) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "Error: No such SCCP addressbook entry: '%s'%s", smlc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+         return CMD_ERR_INCOMPLETE;</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%);">+   /* Prevent mixing addresses from different CS7/SS7 instances */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bsc_gsmnet->smlc->cs7_instance_valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (bsc_gsmnet->smlc->cs7_instance != ss7->cfg.id) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty,</span><br><span style="color: hsl(120, 100%, 40%);">+                          "Error: SCCP addressbook entry from mismatching CS7 instance: '%s'%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                              smlc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return CMD_ERR_INCOMPLETE;</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%);">+   bsc_gsmnet->smlc->cs7_instance = ss7->cfg.id;</span><br><span style="color: hsl(120, 100%, 40%);">+        bsc_gsmnet->smlc->cs7_instance_valid = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    enforce_ssn(vty, &bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_SSN_SMLC_BSSAP_LE);</span><br><span style="color: hsl(120, 100%, 40%);">+        bsc_gsmnet->smlc->smlc_addr_name = talloc_strdup(bsc_gsmnet, smlc_addr_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int config_write_smlc(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "smlc%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (bsc_gsmnet->smlc->bsc_addr_name) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, " bsc-addr %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      bsc_gsmnet->smlc->bsc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bsc_gsmnet->smlc->smlc_addr_name) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, " smlc-addr %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     bsc_gsmnet->smlc->smlc_addr_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 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%);">+DEFUN(show_smlc, show_smlc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "show smlc",</span><br><span style="color: hsl(120, 100%, 40%);">+        SHOW_STR "Display state of SMLC / Lb\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, "not implemented%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void smlc_vty_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element_ve(&show_smlc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(CONFIG_NODE, &cfg_smlc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_node(&smlc_node, config_write_smlc);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(SMLC_NODE, &cfg_smlc_cs7_bsc_addr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(SMLC_NODE, &cfg_smlc_cs7_smlc_addr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct rate_ctr_desc smlc_ctr_description[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      [SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              "bssmap_le:rx:unknown_peer",</span><br><span style="color: hsl(120, 100%, 40%);">+                "Number of received BSSMAP-LE messages from an unknown Calling SCCP address"</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_UDT_RESET] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         "bssmap_le:rx:udt:reset:request",</span><br><span style="color: hsl(120, 100%, 40%);">+           "Number of received BSSMAP-LE UDT RESET messages"</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "bssmap_le:rx:udt:reset:ack",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received BSSMAP-LE UDT RESET ACKNOWLEDGE messages"</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               "bssmap_le:rx:udt:err:inval",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received invalid BSSMAP-LE UDT messages"</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               "bssmap_le:rx:dt1:err:inval",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received invalid BSSMAP-LE"</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "bssmap_le:rx:dt1:location:response_success",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received BSSMAP-LE Perform Location Response messages containing a location estimate"</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "bssmap_le:rx:dt1:location:response_failure",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received BSSMAP-LE Perform Location Response messages containing a failure 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%);">+  [SMLC_CTR_BSSMAP_LE_TX_ERR_INVALID_MSG] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           "bssmap_le:tx:err:inval",</span><br><span style="color: hsl(120, 100%, 40%);">+           "Number of outgoing BSSMAP-LE messages that are invalid (a bug?)"</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_ERR_CONN_NOT_READY] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                "bssmap_le:tx:err:conn_not_ready",</span><br><span style="color: hsl(120, 100%, 40%);">+          "Number of BSSMAP-LE messages we tried to send when the connection was not ready yet"</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_ERR_SEND] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          "bssmap_le:tx:err:send",</span><br><span style="color: hsl(120, 100%, 40%);">+            "Number of socket errors while sending BSSMAP-LE messages"</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_SUCCESS] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           "bssmap_le:tx:success",</span><br><span style="color: hsl(120, 100%, 40%);">+             "Number of successfully sent BSSMAP-LE messages"</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%);">+  [SMLC_CTR_BSSMAP_LE_TX_UDT_RESET] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         "bssmap_le:tx:udt:reset:request",</span><br><span style="color: hsl(120, 100%, 40%);">+           "Number of transmitted BSSMAP-LE UDT RESET messages"</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "bssmap_le:tx:udt:reset:ack",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of transmitted BSSMAP-LE UDT RESET ACK messages"</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              "bssmap_le:tx:dt1:location:response",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of transmitted BSSMAP-LE DT1 Perform Location Request messages"</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                "bssmap_le:rx:dt1:location:abort",</span><br><span style="color: hsl(120, 100%, 40%);">+          "Number of received BSSMAP-LE Perform Location Abort messages"</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%);">+  [SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "bssmap_le:rx:dt1:bsslap:ta_request",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Number of received BSSMAP-LE Connection Oriented Information messages"</span><br><span style="color: hsl(120, 100%, 40%);">+             " with BSSLAP APDU containing TA Request"</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%);">+  [SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            "bssmap_le:tx:dt1:bsslap:ta_response",</span><br><span style="color: hsl(120, 100%, 40%);">+              "Number of sent BSSMAP-LE Connection Oriented Information messages"</span><br><span style="color: hsl(120, 100%, 40%);">+         " with BSSLAP APDU containing TA Response"</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         "bssmap_le:tx:dt1:bsslap:reject",</span><br><span style="color: hsl(120, 100%, 40%);">+           "Number of sent BSSMAP-LE Connection Oriented Information messages"</span><br><span style="color: hsl(120, 100%, 40%);">+         " with BSSLAP APDU containing Reject"</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          "bssmap_le:tx:dt1:bsslap:reset",</span><br><span style="color: hsl(120, 100%, 40%);">+            "Number of sent BSSMAP-LE Connection Oriented Information messages"</span><br><span style="color: hsl(120, 100%, 40%);">+         " with BSSLAP APDU containing Reset"</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          "bssmap_le:tx:dt1:bsslap:abort",</span><br><span style="color: hsl(120, 100%, 40%);">+            "Number of sent BSSMAP-LE Connection Oriented Information messages"</span><br><span style="color: hsl(120, 100%, 40%);">+         " with BSSLAP APDU containing Abort"</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct rate_ctr_group_desc smlc_ctrg_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+       "smlc",</span><br><span style="color: hsl(120, 100%, 40%);">+     "serving mobile location centre",</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_STATS_CLASS_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+      ARRAY_SIZE(smlc_ctr_description),</span><br><span style="color: hsl(120, 100%, 40%);">+     smlc_ctr_description,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/src/osmo-bsc/lcs_loc_req.c b/src/osmo-bsc/lcs_loc_req.c</span><br><span>new file mode 100644</span><br><span>index 0000000..ca5c7b9</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/lcs_loc_req.c</span><br><span>@@ -0,0 +1,581 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Handle LCS BSSMAP-LE Perform Location Request */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bsc_msc_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bsc_subscr_conn_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bsc_subscriber.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.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/core/tdef.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/gsm/gad.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bsslap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/bssmap_le.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808_lcs.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_ta_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/paging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bts_trx.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum lcs_loc_req_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    LCS_LOC_REQ_ST_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+  LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+        LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING,</span><br><span style="color: hsl(120, 100%, 40%);">+ LCS_LOC_REQ_ST_GOT_LOCATION_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+ LCS_LOC_REQ_ST_FAILED,</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 lcs_loc_req_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT),</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(LCS_LOC_REQ_EV_TA_REQ_START),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(LCS_LOC_REQ_EV_TA_REQ_END),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(LCS_LOC_REQ_EV_HANDOVER_PERFORMED),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(LCS_LOC_REQ_EV_CONN_CLEAR),</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 lcs_loc_req_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_tdef_state_timeout lcs_loc_req_fsm_timeouts[32] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     [LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE] = { .T = -11 },</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%);">+/* Transition to a state, using the T timer defined in lcs_loc_req_fsm_timeouts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The actual timeout value is in turn obtained from network->T_defs.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Assumes local variable fi exists. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define lcs_loc_req_fsm_state_chg(FI, STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_tdef_fsm_inst_state_chg(FI, STATE, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                  lcs_loc_req_fsm_timeouts, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                   (bsc_gsmnet)->T_defs, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                    5)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define lcs_loc_req_fail(cause, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Perform Location Request failed in state %s: " fmt "\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                              lcs_loc_req ? osmo_fsm_inst_state_name(lcs_loc_req->fi) : "NULL", ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+            lcs_loc_req->lcs_cause = (struct lcs_cause_ie){ \</span><br><span style="color: hsl(120, 100%, 40%);">+                  .present = true, \</span><br><span style="color: hsl(120, 100%, 40%);">+                    .cause_val = cause, \</span><br><span style="color: hsl(120, 100%, 40%);">+         }; \</span><br><span style="color: hsl(120, 100%, 40%);">+          lcs_loc_req_fsm_state_chg(lcs_loc_req->fi, LCS_LOC_REQ_ST_FAILED); \</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 lcs_loc_req *lcs_loc_req_alloc(struct osmo_fsm_inst *parent_fi, uint32_t parent_event_term)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct lcs_loc_req *lcs_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc_child(&lcs_loc_req_fsm, parent_fi, parent_event_term);</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%);">+    lcs_loc_req = talloc(fi, struct lcs_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(lcs_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+     fi->priv = lcs_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+    *lcs_loc_req = (struct lcs_loc_req){</span><br><span style="color: hsl(120, 100%, 40%);">+          .fi = fi,</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 lcs_loc_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%);">+static bool parse_bssmap_perf_loc_req(struct lcs_loc_req *lcs_loc_req, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct tlv_parsed tp_arr[1];</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tlv_parsed *tp = &tp_arr[0];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct tlv_p_entry *e;</span><br><span style="color: hsl(120, 100%, 40%);">+        int payload_length;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define PARSE_ERR(ERRMSG) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                       lcs_loc_req_fail(LCS_CAUSE_PROTOCOL_ERROR, "rx BSSMAP Perform Location Request: " ERRMSG); \</span><br><span style="color: hsl(120, 100%, 40%);">+                        return false; \</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%);">+  payload_length = msg->tail - msg->l4h;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (tlv_parse2(tp_arr, 1, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0) <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           PARSE_ERR("Failed to parse IEs");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(e = TLVP_GET(tp, GSM0808_IE_LOCATION_TYPE)))</span><br><span style="color: hsl(120, 100%, 40%);">+            PARSE_ERR("Missing Location Type IE");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (osmo_bssmap_le_ie_dec_location_type(&lcs_loc_req->req.location_type, -1, -1, NULL, NULL, e->val, e->len))</span><br><span style="color: hsl(120, 100%, 40%);">+            PARSE_ERR("Failed to parse Location Type IE");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((e = TLVP_GET(tp, GSM0808_IE_CELL_IDENTIFIER))) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (gsm0808_dec_cell_id(&lcs_loc_req->req.cell_id, e->val, e->len) <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                      PARSE_ERR("Failed to parse Cell Identifier IE");</span><br><span style="color: hsl(120, 100%, 40%);">+            lcs_loc_req->req.cell_id_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((e = TLVP_GET(tp, GSM0808_IE_IMSI))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (osmo_mobile_identity_decode(&lcs_loc_req->req.imsi, e->val, e->len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+               || lcs_loc_req->req.imsi.type != GSM_MI_TYPE_IMSI)</span><br><span style="color: hsl(120, 100%, 40%);">+                     PARSE_ERR("Failed to parse IMSI IE");</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 ((e = TLVP_GET(tp, GSM0808_IE_IMEI))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (osmo_mobile_identity_decode(&lcs_loc_req->req.imei, e->val, e->len, false)</span><br><span style="color: hsl(120, 100%, 40%);">+               || lcs_loc_req->req.imei.type != GSM_MI_TYPE_IMEI)</span><br><span style="color: hsl(120, 100%, 40%);">+                     PARSE_ERR("Failed to parse IMEI IE");</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%);">+   // FIXME LCS QoS IE is mandatory for requesting the location</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* A lot of IEs remain ignored... */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return true;</span><br><span style="color: hsl(120, 100%, 40%);">+#undef PARSE_ERR</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 lcs_loc_req_start(struct gsm_subscriber_connection *conn, struct msgb *loc_req_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct lcs_loc_req *lcs_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (conn->lcs.loc_req) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_LCS_LOC_REQ(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Ignoring Perform Location Request, another request is still pending\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   lcs_loc_req = lcs_loc_req_alloc(conn->fi, GSCON_EV_LCS_LOC_REQ_END);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     lcs_loc_req->conn = conn;</span><br><span style="color: hsl(120, 100%, 40%);">+  conn->lcs.loc_req = lcs_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!parse_bssmap_perf_loc_req(lcs_loc_req, loc_req_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%);">+     if (!conn->bsub) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (lcs_loc_req->req.imsi.type != GSM_MI_TYPE_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      lcs_loc_req_fail(LCS_CAUSE_DATA_MISSING_IN_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        "tx Perform Location Request: Missing identity:"</span><br><span style="color: hsl(120, 100%, 40%);">+                                    " No IMSI included in request, and also no active subscriber");</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%);">+           conn->bsub = bsc_subscr_find_or_create_by_mi(bsc_gsmnet->bsc_subscribers, &lcs_loc_req->req.imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             BSUB_USE_CONN);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!conn->bsub) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 lcs_loc_req_fail(LCS_CAUSE_SYSTEM_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "tx Perform Location Request: Cannot assign subscriber");</span><br><span style="color: hsl(120, 100%, 40%);">+                  return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* state change to start the timeout */</span><br><span style="color: hsl(120, 100%, 40%);">+       lcs_loc_req_fsm_state_chg(lcs_loc_req->fi, LCS_LOC_REQ_ST_WAIT_LOCATION_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%);">+static int handle_bssmap_le_conn_oriented_info(struct lcs_loc_req *lcs_loc_req, const struct bssmap_le_pdu *bssmap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (bssmap_le->conn_oriented_info.apdu.msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSLAP_MSGT_TA_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+          rate_ctr_inc(&bsc_gsmnet->smlc->ctrs->ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_DEBUG, "rx BSSLAP TA Request\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         /* The TA Request message contains only the message type. */</span><br><span style="color: hsl(120, 100%, 40%);">+          return lcs_ta_req_start(lcs_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "rx BSSLAP APDU with unsupported message type %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               bssmap_le->conn_oriented_info.apdu.msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int lcs_loc_req_rx_bssmap_le(struct gsm_subscriber_connection *conn, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct lcs_loc_req *lcs_loc_req = conn->lcs.loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bssap_le_pdu bssap_le;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_bssap_le_err *err;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct rate_ctr *ctr = bsc_gsmnet->smlc->ctrs->ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!lcs_loc_req) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "Rx BSSMAP-LE message, but no Location Request is ongoing\n");</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%);">+   if (osmo_bssap_le_dec(&bssap_le, &err, msg, msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Rx BSSAP-LE message with error: %s\n", err->logmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+           rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_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%);">+   if (bssap_le.discr != BSSAP_LE_MSG_DISCR_BSSMAP_LE) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Rx BSSAP-LE: discr %d not implemented\n", bssap_le.discr);</span><br><span style="color: hsl(120, 100%, 40%);">+                rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG]);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOTSUP;</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_LCS_LOC_REQ(lcs_loc_req, LOGL_DEBUG, "Rx %s\n", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, &bssap_le));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (bssap_le.bssmap_le.msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSSMAP_LE_MSGT_PERFORM_LOC_RESP:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bssap_le.bssmap_le.perform_loc_resp.location_estimate_present)</span><br><span style="color: hsl(120, 100%, 40%);">+                    rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS]);</span><br><span style="color: hsl(120, 100%, 40%);">+          else</span><br><span style="color: hsl(120, 100%, 40%);">+                  rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);</span><br><span style="color: hsl(120, 100%, 40%);">+          return osmo_fsm_inst_dispatch(lcs_loc_req->fi, LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           &bssap_le.bssmap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+               return handle_bssmap_le_conn_oriented_info(lcs_loc_req, &bssap_le.bssmap_le);</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%);">+              LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Rx BSSMAP-LE from SMLC with unsupported message type: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_bssap_le_pdu_to_str_c(OTC_SELECT, &bssap_le));</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void lcs_loc_req_reset(struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lcs_loc_req *lcs_loc_req = conn->lcs.loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!lcs_loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       lcs_loc_req_fail(LCS_CAUSE_SYSTEM_FAILURE, "Aborting Location Request due to RESET on Lb");</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 lcs_loc_req_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 lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        lcs_loc_req_fail(LCS_CAUSE_SYSTEM_FAILURE, "Timeout");</span><br><span style="color: hsl(120, 100%, 40%);">+      return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int lcs_loc_req_send(struct lcs_loc_req *lcs_loc_req, const struct bssap_le_pdu *bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc = lb_send(lcs_loc_req->conn, bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_loc_req_fail(LCS_CAUSE_SYSTEM_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Failed to send %s", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));</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%);">+static void lcs_loc_req_wait_loc_resp_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%);">+      struct lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bssap_le_pdu plr;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_lchan *lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (prev_state == LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING should halt the FSM timeout. As soon as the TA Request is</span><br><span style="color: hsl(120, 100%, 40%);">+              * served, re-entering LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE, but of course there is then no need to</span><br><span style="color: hsl(120, 100%, 40%);">+           * send a second BSSMAP-LE Perform Location Request to the SMLC. */</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 (!lcs_loc_req->req.cell_id_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+           lcs_loc_req_fail(LCS_CAUSE_PROTOCOL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Cannot encode BSSMAP-LE Perform Location Request,"</span><br><span style="color: hsl(120, 100%, 40%);">+                                 " because mandatory Cell Identity is not known");</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%);">+   plr = (struct bssap_le_pdu){</span><br><span style="color: hsl(120, 100%, 40%);">+          .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .perform_loc_req = {</span><br><span style="color: hsl(120, 100%, 40%);">+                          .location_type = lcs_loc_req->req.location_type,</span><br><span style="color: hsl(120, 100%, 40%);">+                           .cell_id = lcs_loc_req->req.cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                               .imsi = lcs_loc_req->req.imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+                             .imei = lcs_loc_req->req.imei,</span><br><span style="color: hsl(120, 100%, 40%);">+                     },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* If we already have an active lchan, send the known TA directly to the SMLC */</span><br><span style="color: hsl(120, 100%, 40%);">+      lchan = lcs_loc_req->conn->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (lchan) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Active lchan present, including BSSLAP APDU with TA Layer 3\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           plr.bssmap_le.perform_loc_req.apdu_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            plr.bssmap_le.perform_loc_req.apdu = (struct bsslap_pdu){</span><br><span style="color: hsl(120, 100%, 40%);">+                     .msg_type = BSSLAP_MSGT_TA_LAYER3,</span><br><span style="color: hsl(120, 100%, 40%);">+                    .ta_layer3 = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                .ta = lchan->rqd_ta,</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%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "No active lchan, not including BSSLAP APDU\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Establish Lb connection to SMLC and send the BSSMAP-LE Perform Location Request */</span><br><span style="color: hsl(120, 100%, 40%);">+ lcs_loc_req_send(lcs_loc_req, &plr);</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 lcs_loc_req_bssmap_le_abort(struct lcs_loc_req *lcs_loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bssap_le_pdu pla = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .perform_loc_abort = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                .present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                              .cause_val = LCS_CAUSE_REQUEST_ABORTED,</span><br><span style="color: hsl(120, 100%, 40%);">+                       },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  lcs_loc_req_send(lcs_loc_req, &pla);</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%);">+/* After a handover, send the new lchan information to the SMLC via a BSSLAP Reset message.</span><br><span style="color: hsl(120, 100%, 40%);">+ * See 3GPP TS 48.071 4.2.6 Reset. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void lcs_loc_req_handover_performed(struct lcs_loc_req *lcs_loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_lchan *lchan = lcs_loc_req->conn->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssap_le_pdu bsslap = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bsslap_pdu *apdu = &bsslap.bssmap_le.conn_oriented_info.apdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!lchan) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* The handover was out of this BSS. Abort the location procedure. */</span><br><span style="color: hsl(120, 100%, 40%);">+         *apdu = (struct bsslap_pdu){</span><br><span style="color: hsl(120, 100%, 40%);">+                  .msg_type = BSSLAP_MSGT_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .abort = BSSLAP_CAUSE_INTER_BSS_HO,</span><br><span style="color: hsl(120, 100%, 40%);">+           };</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              *apdu = (struct bsslap_pdu){</span><br><span style="color: hsl(120, 100%, 40%);">+                  .msg_type = BSSLAP_MSGT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .reset = {</span><br><span style="color: hsl(120, 100%, 40%);">+                            .cell_id = lchan->ts->trx->bts->cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+                            .ta = lchan->rqd_ta,</span><br><span style="color: hsl(120, 100%, 40%);">+                               .cause = BSSLAP_CAUSE_INTRA_BSS_HO,</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%);">+            gsm48_lchan2chan_desc(&apdu->reset.chan_desc, lchan);</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%);">+   lcs_loc_req_send(lcs_loc_req, &bsslap);</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 lcs_loc_req_wait_loc_resp_and_ta_req_ongoing_action(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 lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct bssmap_le_pdu *bssmap_le;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    case LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE:</span><br><span style="color: hsl(120, 100%, 40%);">+          bssmap_le = data;</span><br><span style="color: hsl(120, 100%, 40%);">+             OSMO_ASSERT(bssmap_le->msg_type == BSSMAP_LE_MSGT_PERFORM_LOC_RESP);</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_loc_req->resp = bssmap_le->perform_loc_resp;</span><br><span style="color: hsl(120, 100%, 40%);">+                lcs_loc_req->resp_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+          lcs_loc_req_fsm_state_chg(fi, LCS_LOC_REQ_ST_GOT_LOCATION_RESPONSE);</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 LCS_LOC_REQ_EV_TA_REQ_START:</span><br><span style="color: hsl(120, 100%, 40%);">+             if (fi->state != LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING)</span><br><span style="color: hsl(120, 100%, 40%);">+                     lcs_loc_req_fsm_state_chg(fi, LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING);</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 LCS_LOC_REQ_EV_TA_REQ_END:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (fi->state != LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    lcs_loc_req_fsm_state_chg(fi, LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE);</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 LCS_LOC_REQ_EV_HANDOVER_PERFORMED:</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_loc_req_handover_performed(lcs_loc_req);</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 LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+      case LCS_LOC_REQ_EV_CONN_CLEAR:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (lcs_loc_req->ta_req)</span><br><span style="color: hsl(120, 100%, 40%);">+                   osmo_fsm_inst_dispatch(lcs_loc_req->ta_req->fi, LCS_TA_REQ_EV_ABORT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             lcs_loc_req_bssmap_le_abort(lcs_loc_req);</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_term(lcs_loc_req->fi, OSMO_FSM_TERM_REGULAR, NULL);</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_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void lcs_loc_req_got_loc_resp_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%);">+        struct lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm0808_perform_location_response plr = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .location_estimate_present = lcs_loc_req->resp.location_estimate_present,</span><br><span style="color: hsl(120, 100%, 40%);">+          .location_estimate = lcs_loc_req->resp.location_estimate,</span><br><span style="color: hsl(120, 100%, 40%);">+          .lcs_cause = lcs_loc_req->resp.lcs_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%);">+  if (plr.location_estimate_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_gad gad;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_gad_err *err;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (osmo_gad_dec(&gad, &err, OTC_SELECT, &plr.location_estimate))</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      "Perform Location Response contains Location Estimate with error: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    err->logmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+              else</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       "Perform Location Response contains Location Estimate: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                       osmo_gad_to_str_c(OTC_SELECT, &gad));</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 (plr.lcs_cause.present) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Perform Location Response contains error cause: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             plr.lcs_cause.cause_val);</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 = gsm0808_create_perform_location_response(&plr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Failed to encode BSSMAP Perform Location Response (A-interface)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = gscon_sigtran_send(lcs_loc_req->conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      "Failed to send Perform Location Response (A-interface)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                else</span><br><span style="color: hsl(120, 100%, 40%);">+                  rate_ctr_inc(&lcs_loc_req->conn->sccp.msc->msc_ctrs->ctr[</span><br><span style="color: hsl(120, 100%, 40%);">+                             plr.location_estimate_present ? MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+                               : MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_term(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%);">+static void lcs_loc_req_failed_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%);">+   struct lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bssap_le_pdu pla = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_PERFORM_LOC_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .perform_loc_abort = lcs_loc_req->lcs_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%);">+    struct gsm0808_perform_location_response plr = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .lcs_cause = lcs_loc_req->lcs_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%);">+  /* If we're paging this subscriber for LCS, stop paging. */</span><br><span style="color: hsl(120, 100%, 40%);">+       paging_request_cancel(lcs_loc_req->conn->bsub, BSC_PAGING_FOR_LCS);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Send Perform Location Abort to SMLC, only if we got started on the Lb */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (lcs_loc_req->conn->lcs.lb.state == SUBSCR_SCCP_ST_CONNECTED)</span><br><span style="color: hsl(120, 100%, 40%);">+                lcs_loc_req_send(lcs_loc_req, &pla);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Send Perform Location Result with failure cause to MSC */</span><br><span style="color: hsl(120, 100%, 40%);">+  msg = gsm0808_create_perform_location_response(&plr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Failed to encode BSSMAP Perform Location Response (A-interface)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = gscon_sigtran_send(lcs_loc_req->conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      "Failed to send BSSMAP Perform Location Response (A-interface)\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  rate_ctr_inc(&lcs_loc_req->conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE]);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_term(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%);">+void lcs_loc_req_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 lcs_loc_req *lcs_loc_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lcs_loc_req->conn && lcs_loc_req->conn->lcs.loc_req == lcs_loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+              lcs_loc_req->conn->lcs.loc_req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FSM termination will dispatch GSCON_EV_LCS_LOC_REQ_END to the conn FSM */</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 lcs_loc_req_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [LCS_LOC_REQ_ST_INIT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "INIT",</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_LOC_REQ_ST_FAILED)</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%);">+    [LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "WAIT_LOCATION_RESPONSE",</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT)</span><br><span style="color: hsl(120, 100%, 40%);">+                       | S(LCS_LOC_REQ_EV_TA_REQ_START)</span><br><span style="color: hsl(120, 100%, 40%);">+                      | S(LCS_LOC_REQ_EV_TA_REQ_END)</span><br><span style="color: hsl(120, 100%, 40%);">+                        | S(LCS_LOC_REQ_EV_HANDOVER_PERFORMED)</span><br><span style="color: hsl(120, 100%, 40%);">+                        | S(LCS_LOC_REQ_EV_CONN_CLEAR)</span><br><span style="color: hsl(120, 100%, 40%);">+                        ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCS_LOC_REQ_ST_GOT_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCS_LOC_REQ_ST_FAILED)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .onenter = lcs_loc_req_wait_loc_resp_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+         .action = lcs_loc_req_wait_loc_resp_and_ta_req_ongoing_action,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [LCS_LOC_REQ_ST_BSSLAP_TA_REQ_ONGOING] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "BSSLAP_TA_REQ_ONGOING",</span><br><span style="color: hsl(120, 100%, 40%);">+            .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT)</span><br><span style="color: hsl(120, 100%, 40%);">+                       | S(LCS_LOC_REQ_EV_TA_REQ_END)</span><br><span style="color: hsl(120, 100%, 40%);">+                        | S(LCS_LOC_REQ_EV_HANDOVER_PERFORMED)</span><br><span style="color: hsl(120, 100%, 40%);">+                        | S(LCS_LOC_REQ_EV_CONN_CLEAR)</span><br><span style="color: hsl(120, 100%, 40%);">+                        ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_LOC_REQ_ST_WAIT_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_LOC_REQ_ST_GOT_LOCATION_RESPONSE)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCS_LOC_REQ_ST_FAILED)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .action = lcs_loc_req_wait_loc_resp_and_ta_req_ongoing_action,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [LCS_LOC_REQ_ST_GOT_LOCATION_RESPONSE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "GOT_LOCATION_RESPONSE",</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = lcs_loc_req_got_loc_resp_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [LCS_LOC_REQ_ST_FAILED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "FAILED",</span><br><span style="color: hsl(120, 100%, 40%);">+           .onenter = lcs_loc_req_failed_onenter,</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 lcs_loc_req_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .name = "lcs_loc_req",</span><br><span style="color: hsl(120, 100%, 40%);">+      .states = lcs_loc_req_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+     .num_states = ARRAY_SIZE(lcs_loc_req_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+     .log_subsys = DLCS,</span><br><span style="color: hsl(120, 100%, 40%);">+   .event_names = lcs_loc_req_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+   .timer_cb = lcs_loc_req_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ .cleanup = lcs_loc_req_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 lcs_loc_req_fsm_register(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(osmo_fsm_register(&lcs_loc_req_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bsc/lcs_ta_req.c b/src/osmo-bsc/lcs_ta_req.c</span><br><span>new file mode 100644</span><br><span>index 0000000..97d6eb5</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/lcs_ta_req.c</span><br><span>@@ -0,0 +1,305 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Handle LCS BSSLAP TA Request */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <osmocom/bsc/lcs_ta_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/paging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/bts.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/core/fsm.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/gsm/bsslap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum lcs_ta_req_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+ LCS_TA_REQ_ST_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+   LCS_TA_REQ_ST_WAIT_TA,</span><br><span style="color: hsl(120, 100%, 40%);">+        LCS_TA_REQ_ST_GOT_TA,</span><br><span style="color: hsl(120, 100%, 40%);">+ LCS_TA_REQ_ST_FAILED,</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 lcs_ta_req_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(LCS_TA_REQ_EV_GOT_TA),</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(LCS_TA_REQ_EV_ABORT),</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 const struct osmo_tdef_state_timeout lcs_ta_req_fsm_timeouts[32] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [LCS_TA_REQ_ST_WAIT_TA] = { .T = -12 },</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%);">+/* Transition to a state, using the T timer defined in lcs_ta_req_fsm_timeouts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The actual timeout value is in turn obtained from network->T_defs.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Assumes local variable fi exists. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define lcs_ta_req_fsm_state_chg(FI, STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_tdef_fsm_inst_state_chg(FI, STATE, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                  lcs_ta_req_fsm_timeouts, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                    (bsc_gsmnet)->T_defs, \</span><br><span style="color: hsl(120, 100%, 40%);">+                                    5)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define lcs_ta_req_fail(cause, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOG_LCS_TA_REQ(lcs_ta_req, LOGL_ERROR, "BSSLAP TA Request failed in state %s: " fmt "\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                              lcs_ta_req ? osmo_fsm_inst_state_name(lcs_ta_req->fi) : "NULL", ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_ta_req->failure_cause = cause; \</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_ta_req_fsm_state_chg(lcs_ta_req->fi, LCS_TA_REQ_ST_FAILED); \</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 lcs_ta_req_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct lcs_ta_req *lcs_ta_req_alloc(struct osmo_fsm_inst *parent_fi, uint32_t parent_event_term)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct lcs_ta_req *lcs_ta_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc_child(&lcs_ta_req_fsm, parent_fi, parent_event_term);</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%);">+    lcs_ta_req = talloc(fi, struct lcs_ta_req);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(lcs_ta_req);</span><br><span style="color: hsl(120, 100%, 40%);">+      fi->priv = lcs_ta_req;</span><br><span style="color: hsl(120, 100%, 40%);">+     *lcs_ta_req = (struct lcs_ta_req){</span><br><span style="color: hsl(120, 100%, 40%);">+            .fi = fi,</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 lcs_ta_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 lcs_ta_req_start(struct lcs_loc_req *lcs_loc_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lcs_ta_req *lcs_ta_req;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lcs_loc_req->ta_req) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_LCS_TA_REQ(lcs_loc_req->ta_req, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "Cannot start anoter TA Request FSM, this TA Request is still active\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     lcs_ta_req = lcs_ta_req_alloc(lcs_loc_req->fi, LCS_LOC_REQ_EV_TA_REQ_END);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!lcs_ta_req) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOG_LCS_LOC_REQ(lcs_loc_req, LOGL_ERROR, "Cannot allocate TA Request FSM");</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%);">+     lcs_ta_req->loc_req = lcs_loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ lcs_loc_req->ta_req = lcs_ta_req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return lcs_ta_req_fsm_state_chg(lcs_ta_req->fi, LCS_TA_REQ_ST_WAIT_TA);</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 lcs_ta_req_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 lcs_ta_req *lcs_ta_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  lcs_ta_req_fail(LCS_CAUSE_SYSTEM_FAILURE, "Timeout");</span><br><span style="color: hsl(120, 100%, 40%);">+       return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void lcs_ta_req_wait_ta_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%);">+     struct lcs_ta_req *lcs_ta_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct lcs_loc_req *loc_req = lcs_ta_req->loc_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_lchan *lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct bsc_paging_params paging;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_fsm_inst_dispatch(loc_req->fi, LCS_LOC_REQ_EV_TA_REQ_START, lcs_ta_req)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                lcs_ta_req_fail(LCS_CAUSE_SYSTEM_FAILURE, "Failed to dispatch LCS_LOC_REQ_EV_TA_REQ_START");</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%);">+   paging = (struct bsc_paging_params){</span><br><span style="color: hsl(120, 100%, 40%);">+          .reason = BSC_PAGING_FOR_LCS,</span><br><span style="color: hsl(120, 100%, 40%);">+         .msc = loc_req->conn->sccp.msc,</span><br><span style="color: hsl(120, 100%, 40%);">+         .bsub = loc_req->conn->bsub,</span><br><span style="color: hsl(120, 100%, 40%);">+            .tmsi = GSM_RESERVED_TMSI,</span><br><span style="color: hsl(120, 100%, 40%);">+            .imsi = loc_req->req.imsi,</span><br><span style="color: hsl(120, 100%, 40%);">+         .chan_needed = RSL_CHANNEED_ANY,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    if (paging.bsub)</span><br><span style="color: hsl(120, 100%, 40%);">+              bsc_subscr_get(paging.bsub, BSUB_USE_PAGING_START);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Do we already have an active lchan with knowledge of TA? */</span><br><span style="color: hsl(120, 100%, 40%);">+        lchan = loc_req->conn->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (lchan) {</span><br><span style="color: hsl(120, 100%, 40%);">+          lcs_ta_req_fsm_state_chg(fi, LCS_TA_REQ_ST_GOT_TA);</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%);">+   /* No lchan yet, need to start Paging */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (loc_req->req.imsi.type != GSM_MI_TYPE_IMSI) {</span><br><span style="color: hsl(120, 100%, 40%);">+          lcs_ta_req_fail(LCS_CAUSE_PROTOCOL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "No IMSI in BSSMAP Location Request and no active lchan, cannot start Paging");</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 (!loc_req->req.cell_id_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_LCS_TA_REQ(lcs_ta_req, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                               "No Cell Identity in BSSMAP Location Request, paging entire BSS\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         paging.cil = (struct gsm0808_cell_id_list2){</span><br><span style="color: hsl(120, 100%, 40%);">+                  .id_discr = CELL_IDENT_BSS,</span><br><span style="color: hsl(120, 100%, 40%);">+           };</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              paging.cil = (struct gsm0808_cell_id_list2){</span><br><span style="color: hsl(120, 100%, 40%);">+                  .id_discr = loc_req->req.cell_id.id_discr,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .id_list = { loc_req->req.cell_id.id },</span><br><span style="color: hsl(120, 100%, 40%);">+                    .id_list_len = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+             };</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bsc_paging_start(&paging);</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 lcs_ta_req_wait_ta_action(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%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    case LCS_TA_REQ_EV_GOT_TA:</span><br><span style="color: hsl(120, 100%, 40%);">+            lcs_ta_req_fsm_state_chg(fi, LCS_TA_REQ_ST_GOT_TA);</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 LCS_TA_REQ_EV_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+             lcs_ta_req_fsm_state_chg(fi, LCS_TA_REQ_ST_FAILED);</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_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int lcs_ta_req_send(struct lcs_ta_req *lcs_ta_req, const struct bssap_le_pdu *bssap_le)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = lb_send(lcs_ta_req->loc_req->conn, bssap_le);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+               lcs_ta_req_fail(LCS_CAUSE_SYSTEM_FAILURE,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Failed to send %s", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));</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%);">+void lcs_ta_req_got_ta_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%);">+     struct lcs_ta_req *lcs_ta_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bssap_le_pdu bsslap_ta_resp;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_lchan *lchan = lcs_ta_req->loc_req->conn->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!lchan) {</span><br><span style="color: hsl(120, 100%, 40%);">+         lcs_ta_req_fail(LCS_CAUSE_SYSTEM_FAILURE, "Internal error: no lchan");</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%);">+   bsslap_ta_resp = (struct bssap_le_pdu) {</span><br><span style="color: hsl(120, 100%, 40%);">+              .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .conn_oriented_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+                               .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     .msg_type = BSSLAP_MSGT_TA_RESPONSE,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  .ta_response = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                              .cell_id = lchan->ts->trx->bts->cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            .ta = lchan->rqd_ta,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       },</span><br><span style="color: hsl(120, 100%, 40%);">+                            },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  lcs_ta_req_send(lcs_ta_req, &bsslap_ta_resp);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_term(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%);">+void lcs_ta_req_failed_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%);">+   struct lcs_ta_req *lcs_ta_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bssap_le_pdu bsslap_abort;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bsslap_abort = (struct bssap_le_pdu) {</span><br><span style="color: hsl(120, 100%, 40%);">+                .discr = BSSAP_LE_MSG_DISCR_BSSMAP_LE,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bssmap_le = {</span><br><span style="color: hsl(120, 100%, 40%);">+                        .msg_type = BSSMAP_LE_MSGT_CONN_ORIENTED_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .conn_oriented_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+                               .apdu = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     .msg_type = BSSLAP_MSGT_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        .abort = BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL,</span><br><span style="color: hsl(120, 100%, 40%);">+                           },</span><br><span style="color: hsl(120, 100%, 40%);">+                    },</span><br><span style="color: hsl(120, 100%, 40%);">+            },</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%);">+  lcs_ta_req_send(lcs_ta_req, &bsslap_abort);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, 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%);">+void lcs_ta_req_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 lcs_ta_req *lcs_ta_req = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (lcs_ta_req->loc_req->ta_req == lcs_ta_req)</span><br><span style="color: hsl(120, 100%, 40%);">+          lcs_ta_req->loc_req->ta_req = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FSM termination will dispatch LCS_LOC_REQ_EV_TA_REQ_END to the lcs_loc_req FSM */</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 lcs_ta_req_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       [LCS_TA_REQ_ST_INIT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .name = "init",</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_TA_REQ_ST_WAIT_TA)</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_TA_REQ_ST_GOT_TA)</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%);">+    [LCS_TA_REQ_ST_WAIT_TA] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "wait_ta",</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(LCS_TA_REQ_EV_GOT_TA)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCS_TA_REQ_EV_ABORT)</span><br><span style="color: hsl(120, 100%, 40%);">+                      ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCS_TA_REQ_ST_GOT_TA)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCS_TA_REQ_ST_FAILED)</span><br><span style="color: hsl(120, 100%, 40%);">+                     ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .onenter = lcs_ta_req_wait_ta_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = lcs_ta_req_wait_ta_action,</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [LCS_TA_REQ_ST_GOT_TA] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "got_ta",</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .onenter = lcs_ta_req_got_ta_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [LCS_TA_REQ_ST_FAILED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "failed",</span><br><span style="color: hsl(120, 100%, 40%);">+           .onenter = lcs_ta_req_failed_onenter,</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 lcs_ta_req_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+   .name = "lcs_ta_req",</span><br><span style="color: hsl(120, 100%, 40%);">+       .states = lcs_ta_req_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+      .num_states = ARRAY_SIZE(lcs_ta_req_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+      .log_subsys = DLCS,</span><br><span style="color: hsl(120, 100%, 40%);">+   .event_names = lcs_ta_req_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+    .timer_cb = lcs_ta_req_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+  .cleanup = lcs_ta_req_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 lcs_ta_req_fsm_register(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(osmo_fsm_register(&lcs_ta_req_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bsc/net_init.c b/src/osmo-bsc/net_init.c</span><br><span>index 8b1e080..6cbb40c 100644</span><br><span>--- a/src/osmo-bsc/net_init.c</span><br><span>+++ b/src/osmo-bsc/net_init.c</span><br><span>@@ -52,6 +52,7 @@</span><br><span>    { .T=-8, .default_val=5, .desc="Timeout for RSL IPA MDCX ACK after sending RSL IPA MDCX" },</span><br><span>        { .T=-9, .default_val=5, .desc="Timeout for availability of MGW endpoint" },</span><br><span>       { .T=-10, .default_val=5, .desc="Timeout for fully configured MGW endpoint" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { .T=-11, .default_val=5, .desc="Timeout for Perform Location Response from SMLC" },</span><br><span>       { .T=-3111, .default_val=4, .desc="Wait time after lchan was released in error (should be T3111 + 2s)" },</span><br><span>  { .T=-3210, .default_val=20, .desc="After L3 Complete, wait for MSC to confirm" },</span><br><span>         {}</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>index 10f0edd..c2c05af 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>@@ -44,6 +44,7 @@</span><br><span> #include <osmocom/core/fsm.h></span><br><span> #include <osmocom/core/socket.h></span><br><span> #include <osmocom/core/sockaddr_str.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lcs_loc_req.h></span><br><span> </span><br><span> #define IP_V4_ADDR_LEN 4</span><br><span> </span><br><span>@@ -1176,6 +1177,21 @@</span><br><span>            rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_COMMON_ID]);</span><br><span>            ret = bssmap_handle_common_id(conn, msg, length);</span><br><span>            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSS_MAP_MSG_PERFORM_LOCATION_RQST:</span><br><span style="color: hsl(120, 100%, 40%);">+               rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_REQUEST]);</span><br><span style="color: hsl(120, 100%, 40%);">+              lcs_loc_req_start(conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSS_MAP_MSG_PERFORM_LOCATION_ABORT:</span><br><span style="color: hsl(120, 100%, 40%);">+              rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_ABORT]);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (conn->lcs.loc_req) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ret = osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              msg);</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DMSC, LOGL_ERROR, "Rx BSSMAP Perform Location Abort without ongoing Location Request\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                      ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       default:</span><br><span>             rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UNKNOWN]);</span><br><span>              LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c</span><br><span>index ce9df1d..26d32d1 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_main.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_main.c</span><br><span>@@ -38,6 +38,7 @@</span><br><span> #include <osmocom/bsc/assignment_fsm.h></span><br><span> #include <osmocom/bsc/handover_fsm.h></span><br><span> #include <osmocom/bsc/smscb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/lb.h></span><br><span> </span><br><span> #include <osmocom/ctrl/control_cmd.h></span><br><span> #include <osmocom/ctrl/control_if.h></span><br><span>@@ -788,8 +789,12 @@</span><br><span>                .name = "DCBS",</span><br><span>            .description = "Cell Broadcast System",</span><br><span>            .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DLCS] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "DLCS",</span><br><span style="color: hsl(120, 100%, 40%);">+             .description = "Location Services",</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> static int filter_fn(const struct log_context *ctx, struct log_target *tar)</span><br><span>@@ -947,6 +952,7 @@</span><br><span>    handover_decision_1_init();</span><br><span>  hodec2_init(bsc_gsmnet);</span><br><span>     bsc_cbc_link_restart();</span><br><span style="color: hsl(120, 100%, 40%);">+       lb_init();</span><br><span> </span><br><span>       signal(SIGINT, &signal_handler);</span><br><span>         signal(SIGTERM, &signal_handler);</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c</span><br><span>index 26d2bc8..583b6ff 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_msc.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_msc.c</span><br><span>@@ -62,6 +62,8 @@</span><br><span>   [MSC_CTR_BSSMAP_RX_DT1_UNKNOWN] =           {"bssmap:rx:dt1:err_unknown", "Number of received BSSMAP unknown DT1 messages"},</span><br><span>     [MSC_CTR_BSSMAP_RX_DT1_DTAP] =              {"bssmap:rx:dt1:dtap:good", "Number of received BSSMAP DTAP messages"},</span><br><span>      [MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR] =        {"bssmap:rx:dt1:dtap:error", "Number of received BSSMAP DTAP messages with errors"},</span><br><span style="color: hsl(120, 100%, 40%);">+  [MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_REQUEST] = {"bssmap:rx:dt1:location:request", "Number of received BSSMAP Perform Location Request messages"},</span><br><span style="color: hsl(120, 100%, 40%);">+     [MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_ABORT] = {"bssmap:tx:dt1:location:abort", "Number of received BSSMAP Perform Location Abort messages"},</span><br><span> </span><br><span>      /* Tx message counters (per message type)</span><br><span>     *</span><br><span>@@ -102,6 +104,10 @@</span><br><span>    [MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE] =         {"bssmap:tx:dt1:handover:complete", "Number of transmitted BSSMAP DT1 HANDOVER COMPLETE messages"},</span><br><span>  [MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE] =          {"bssmap:tx:dt1:handover:failure", "Number of transmitted BSSMAP DT1 HANDOVER FAILURE messages"},</span><br><span>    [MSC_CTR_BSSMAP_TX_DT1_DTAP] =                      {"bssmap:tx:dt1:dtap", "Number of transmitted BSSMAP DT1 DTAP messages"},</span><br><span style="color: hsl(120, 100%, 40%);">+     [MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS] = {"bssmap:tx:dt1:location:response_success",</span><br><span style="color: hsl(120, 100%, 40%);">+             "Number of transmitted BSSMAP Perform Location Response messages containing a location estimate"},</span><br><span style="color: hsl(120, 100%, 40%);">+  [MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE] = {"bssmap:tx:dt1:location:response_failure",</span><br><span style="color: hsl(120, 100%, 40%);">+             "Number of transmitted BSSMAP Perform Location Response messages containing a failure cause"},</span><br><span> </span><br><span>         /* Indicators for MSC pool usage */</span><br><span>  [MSC_CTR_MSCPOOL_SUBSCR_NEW] = {</span><br><span>diff --git a/src/osmo-bsc/paging.c b/src/osmo-bsc/paging.c</span><br><span>index a4a5a1e..15aca00 100644</span><br><span>--- a/src/osmo-bsc/paging.c</span><br><span>+++ b/src/osmo-bsc/paging.c</span><br><span>@@ -79,9 +79,9 @@</span><br><span> </span><br><span>    log_set_context(LOG_CTX_BSC_SUBSCR, request->bsub);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      LOG_BTS(bts, DPAG, LOGL_INFO, "Going to send paging commands: imsi: %s tmsi: "</span><br><span style="color: hsl(0, 100%, 40%);">-                "0x%08x for ch. type %d (attempt %d)\n", request->bsub->imsi,</span><br><span style="color: hsl(0, 100%, 40%);">-           request->bsub->tmsi, request->chan_type, request->attempts);</span><br><span style="color: hsl(120, 100%, 40%);">+      LOG_BTS(bts, DPAG, LOGL_INFO, "Going to send paging commands: %s"</span><br><span style="color: hsl(120, 100%, 40%);">+           " for ch. type %d (attempt %d)\n", bsc_subscr_name(request->bsub),</span><br><span style="color: hsl(120, 100%, 40%);">+               request->chan_type, request->attempts);</span><br><span> </span><br><span>    if (request->bsub->tmsi == GSM_RESERVED_TMSI) {</span><br><span>                mi = (struct osmo_mobile_identity){</span><br><span>@@ -457,6 +457,30 @@</span><br><span>   return count;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Remove all paging requests, for specific reasons only. */</span><br><span style="color: hsl(120, 100%, 40%);">+int paging_request_cancel(struct bsc_subscr *bsub, enum bsc_paging_reason reasons)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct gsm_paging_request *req, *req2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              paging_init_if_needed(bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         llist_for_each_entry_safe(req, req2, &bts->paging.pending_requests, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (req->bsub != bsub)</span><br><span style="color: hsl(120, 100%, 40%);">+                             continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!(req->reason & reasons))</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOG_BTS(bts, DPAG, LOGL_DEBUG, "Cancel paging %s\n", bsc_subscr_name(bsub));</span><br><span style="color: hsl(120, 100%, 40%);">+                        paging_remove_request(&bts->paging, req);</span><br><span style="color: hsl(120, 100%, 40%);">+                      count++;</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 count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Update the BTS paging buffer slots on given BTS */</span><br><span> void paging_update_buffer_space(struct gsm_bts *bts, uint16_t free_slots)</span><br><span> {</span><br><span>diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c</span><br><span>index 6a6ff8b..0ed504b 100644</span><br><span>--- a/tests/bsc/bsc_test.c</span><br><span>+++ b/tests/bsc/bsc_test.c</span><br><span>@@ -30,6 +30,7 @@</span><br><span> #include <osmocom/bsc/osmo_bsc.h></span><br><span> #include <osmocom/bsc/bsc_msc_data.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gad.h></span><br><span> #include <osmocom/core/application.h></span><br><span> #include <osmocom/core/backtrace.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span>diff --git a/tests/handover/Makefile.am b/tests/handover/Makefile.am</span><br><span>index 87981d9..0f7953c 100644</span><br><span>--- a/tests/handover/Makefile.am</span><br><span>+++ b/tests/handover/Makefile.am</span><br><span>@@ -93,6 +93,10 @@</span><br><span>    $(top_builddir)/src/osmo-bsc/smscb.o \</span><br><span>       $(top_builddir)/src/osmo-bsc/cbch_scheduler.o \</span><br><span>      $(top_builddir)/src/osmo-bsc/cbsp_link.o \</span><br><span style="color: hsl(120, 100%, 40%);">+    $(top_builddir)/src/osmo-bsc/lcs_loc_req.o \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(top_builddir)/src/osmo-bsc/lcs_ta_req.o \</span><br><span style="color: hsl(120, 100%, 40%);">+   $(top_builddir)/src/osmo-bsc/lb.o \</span><br><span style="color: hsl(120, 100%, 40%);">+   $(top_builddir)/src/osmo-bsc/bsc_sccp.o \</span><br><span>    $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOCTRL_LIBS) \</span><br><span>diff --git a/tests/timer.vty b/tests/timer.vty</span><br><span>index ad1d167..6c26681 100644</span><br><span>--- a/tests/timer.vty</span><br><span>+++ b/tests/timer.vty</span><br><span>@@ -25,6 +25,7 @@</span><br><span> net: X8 = 5 s     Timeout for RSL IPA MDCX ACK after sending RSL IPA MDCX (default: 5 s)</span><br><span> net: X9 = 5 s Timeout for availability of MGW endpoint (default: 5 s)</span><br><span> net: X10 = 5 s       Timeout for fully configured MGW endpoint (default: 5 s)</span><br><span style="color: hsl(120, 100%, 40%);">+net: X11 = 5 s        Timeout for Perform Location Response from SMLC (default: 5 s)</span><br><span> net: X3111 = 4 s      Wait time after lchan was released in error (should be T3111 + 2s) (default: 4 s)</span><br><span> net: X3210 = 20 s  After L3 Complete, wait for MSC to confirm (default: 20 s)</span><br><span> mgw: X2427 = 5 s  timeout for MGCP response from MGW (default: 5 s)</span><br><span>@@ -70,6 +71,7 @@</span><br><span> net: X8 = 5 s  Timeout for RSL IPA MDCX ACK after sending RSL IPA MDCX (default: 5 s)</span><br><span> net: X9 = 5 s Timeout for availability of MGW endpoint (default: 5 s)</span><br><span> net: X10 = 5 s       Timeout for fully configured MGW endpoint (default: 5 s)</span><br><span style="color: hsl(120, 100%, 40%);">+net: X11 = 5 s        Timeout for Perform Location Response from SMLC (default: 5 s)</span><br><span> net: X3111 = 4 s      Wait time after lchan was released in error (should be T3111 + 2s) (default: 4 s)</span><br><span> net: X3210 = 20 s  After L3 Complete, wait for MSC to confirm (default: 20 s)</span><br><span> mgw: X2427 = 5 s  timeout for MGCP response from MGW (default: 5 s)</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/20357">change 20357</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-bsc/+/20357"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I28314ba97df86a118497e9b2770e2e6e2484e872 </div>
<div style="display:none"> Gerrit-Change-Number: 20357 </div>
<div style="display:none"> Gerrit-PatchSet: 10 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>