LCS: implement the bulk of Location Services

Depends: I4d7302a4853518916b6b425e710c10568eb2ffe5 (libosmocore)
Change-Id: I28314ba97df86a118497e9b2770e2e6e2484e872
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 1ee96ed..8c42287 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -27,9 +27,12 @@
 	handover_fsm.h \
 	handover_vty.h \
 	ipaccess.h \
+	lb.h \
 	lchan_fsm.h \
 	lchan_rtp_fsm.h \
 	lchan_select.h \
+	lcs_loc_req.h \
+	lcs_ta_req.h \
 	meas_feed.h \
 	meas_rep.h \
 	misdn.h \
diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h
index 43ace25..5699b77 100644
--- a/include/osmocom/bsc/bsc_msc_data.h
+++ b/include/osmocom/bsc/bsc_msc_data.h
@@ -68,6 +68,8 @@
 	MSC_CTR_BSSMAP_RX_DT1_UNKNOWN,
 	MSC_CTR_BSSMAP_RX_DT1_DTAP,
 	MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR,
+	MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_REQUEST,
+	MSC_CTR_BSSMAP_RX_DT1_PERFORM_LOCATION_ABORT,
 
 	/* Tx message counters (per connection type) */
 	MSC_CTR_BSSMAP_TX_BSS_MANAGEMENT,
@@ -97,6 +99,8 @@
 	MSC_CTR_BSSMAP_TX_DT1_HANDOVER_COMPLETE,
 	MSC_CTR_BSSMAP_TX_DT1_HANDOVER_FAILURE,
 	MSC_CTR_BSSMAP_TX_DT1_DTAP,
+	MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,
+	MSC_CTR_BSSMAP_TX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,
 
 	MSC_CTR_MSCPOOL_SUBSCR_NEW,
 	MSC_CTR_MSCPOOL_SUBSCR_REATTACH,
diff --git a/include/osmocom/bsc/bsc_subscr_conn_fsm.h b/include/osmocom/bsc/bsc_subscr_conn_fsm.h
index ccac4fa..142d535 100644
--- a/include/osmocom/bsc/bsc_subscr_conn_fsm.h
+++ b/include/osmocom/bsc/bsc_subscr_conn_fsm.h
@@ -44,6 +44,8 @@
 
 	GSCON_EV_FORGET_LCHAN,
 	GSCON_EV_FORGET_MGW_ENDPOINT,
+
+	GSCON_EV_LCS_LOC_REQ_END,
 };
 
 struct gscon_clear_cmd_data {
diff --git a/include/osmocom/bsc/debug.h b/include/osmocom/bsc/debug.h
index 82c0703..0380b74 100644
--- a/include/osmocom/bsc/debug.h
+++ b/include/osmocom/bsc/debug.h
@@ -27,6 +27,7 @@
 	DTS,
 	DAS,
 	DCBS,
+	DLCS,
 	Debug_LastEntry,
 };
 
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 7021fa4..050cd7a 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -52,6 +52,7 @@
 struct gprs_ra_id;
 struct handover;
 struct osmo_sccp_instance;
+struct smlc_config;
 
 #define OBSC_LINKID_CB(__msgb)	(__msgb)->cb[3]
 
@@ -304,6 +305,23 @@
 	uint8_t ms_power_class:3;
 
 	bool rx_clear_command;
+
+	/* Location Services handling for this subscriber */
+	struct {
+		/* FSM to handle Perform Location Request coming in from the MSC via A interface,
+		 * and receive BSSMAP-LE responses from the SMLC. */
+		struct lcs_loc_req *loc_req;
+
+		/* FSM to handle BSSLAP requests coming in from the SMLC via Lb interface.
+		 * BSSLAP APDU are encapsulated in BSSMAP-LE Connection Oriented Information messages. */
+		struct lcs_bsslap *bsslap;
+
+		/* Lb interface to the SMLC: BSSMAP-LE/SCCP connection associated with this subscriber */
+		struct {
+			int conn_id;
+			enum subscr_sccp_state state;
+		} lb;
+	} lcs;
 };
 
 
@@ -1200,6 +1218,8 @@
 
 	uint8_t nri_bitlen;
 	struct osmo_nri_ranges *null_nri_ranges;
+
+	struct smlc_config *smlc;
 };
 
 struct gsm_audio_support {
diff --git a/include/osmocom/bsc/lb.h b/include/osmocom/bsc/lb.h
new file mode 100644
index 0000000..0649986
--- /dev/null
+++ b/include/osmocom/bsc/lb.h
@@ -0,0 +1,60 @@
+/* Location Services (LCS): low level Lb/SCCP handling in OsmoBSC, API */
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/sigtran/sccp_sap.h>
+
+struct bssap_le_pdu;
+struct gsm_subscriber_connection;
+
+enum {
+	SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER,
+	SMLC_CTR_BSSMAP_LE_RX_UDT_RESET,
+	SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK,
+	SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG,
+	SMLC_CTR_BSSMAP_LE_RX_DT1_ERR_INVALID_MSG,
+	SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_SUCCESS,
+	SMLC_CTR_BSSMAP_LE_RX_DT1_PERFORM_LOCATION_RESPONSE_FAILURE,
+	SMLC_CTR_BSSMAP_LE_RX_DT1_BSSLAP_TA_REQUEST,
+
+	SMLC_CTR_BSSMAP_LE_TX_ERR_INVALID_MSG,
+	SMLC_CTR_BSSMAP_LE_TX_ERR_CONN_NOT_READY,
+	SMLC_CTR_BSSMAP_LE_TX_ERR_SEND,
+	SMLC_CTR_BSSMAP_LE_TX_SUCCESS,
+
+	SMLC_CTR_BSSMAP_LE_TX_UDT_RESET,
+	SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET,
+	SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT,
+};
+
+struct smlc_config {
+	uint32_t cs7_instance;
+	bool cs7_instance_valid;
+	struct osmo_sccp_instance *sccp;
+	struct osmo_sccp_user *sccp_user;
+
+	struct osmo_sccp_addr bsc_addr;
+	char *bsc_addr_name;
+
+	struct osmo_sccp_addr smlc_addr;
+	char *smlc_addr_name;
+
+	/*! True after either side has sent a BSSMAP-LE RESET-ACK */
+	bool ready;
+
+	struct rate_ctr_group *ctrs;
+};
+
+extern const struct rate_ctr_desc smlc_ctr_description[];
+extern const struct rate_ctr_group_desc smlc_ctrg_desc;
+
+int lb_init();
+int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *bssap_le);
+void lb_close_conn(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/lcs_loc_req.h b/include/osmocom/bsc/lcs_loc_req.h
new file mode 100644
index 0000000..ba677e8
--- /dev/null
+++ b/include/osmocom/bsc/lcs_loc_req.h
@@ -0,0 +1,48 @@
+/* Location Services (LCS): BSSMAP and BSSMAP-LE Perform Location Request handling in OsmoBSC, API */
+#pragma once
+
+#include <osmocom/gsm/bssmap_le.h>
+
+#define LOG_LCS_LOC_REQ(LOC_REQ, level, fmt, args...) do { \
+		if (LOC_REQ) \
+			LOGPFSML((LOC_REQ)->fi, level, fmt, ## args); \
+		else \
+			LOGP(DLCS, level, "LCS Perf Loc Req: " fmt, ## args); \
+	} while(0)
+
+struct lcs_ta_req;
+
+enum lcs_loc_req_fsm_event {
+	LCS_LOC_REQ_EV_RX_LB_PERFORM_LOCATION_RESPONSE,
+	LCS_LOC_REQ_EV_RX_A_PERFORM_LOCATION_ABORT,
+	LCS_LOC_REQ_EV_TA_REQ_START,
+	LCS_LOC_REQ_EV_TA_REQ_END,
+	LCS_LOC_REQ_EV_HANDOVER_PERFORMED,
+	LCS_LOC_REQ_EV_CONN_CLEAR,
+};
+
+struct lcs_loc_req {
+	struct osmo_fsm_inst *fi;
+	struct gsm_subscriber_connection *conn;
+
+	struct {
+		struct bssmap_le_location_type location_type;
+
+		bool cell_id_present;
+		struct gsm0808_cell_id cell_id;
+
+		struct osmo_mobile_identity imsi;
+		struct osmo_mobile_identity imei;
+	} req;
+
+	bool resp_present;
+	struct bssmap_le_perform_loc_resp resp;
+
+	struct lcs_cause_ie lcs_cause;
+
+	struct lcs_ta_req *ta_req;
+};
+
+void lcs_loc_req_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+int lcs_loc_req_rx_bssmap_le(struct gsm_subscriber_connection *conn, struct msgb *msg);
+void lcs_loc_req_reset(struct gsm_subscriber_connection *conn);
diff --git a/include/osmocom/bsc/lcs_ta_req.h b/include/osmocom/bsc/lcs_ta_req.h
new file mode 100644
index 0000000..b9b7a4e
--- /dev/null
+++ b/include/osmocom/bsc/lcs_ta_req.h
@@ -0,0 +1,29 @@
+/* Location Services (LCS): BSSLAP TA Request handling in OsmoBSC, API */
+#pragma once
+
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/gsm/bssmap_le.h>
+
+#define LOG_LCS_TA_REQ(TA_REQ, level, fmt, args...) do { \
+	if (TA_REQ) \
+		LOGPFSML((TA_REQ)->fi, level, fmt, ## args); \
+	else \
+		LOGP(DLCS, level, "LCS TA Req: " fmt, ## args); \
+	} while(0)
+
+enum lcs_ta_req_fsm_event {
+	LCS_TA_REQ_EV_GOT_TA,
+	LCS_TA_REQ_EV_ABORT,
+};
+
+struct lcs_ta_req {
+	struct osmo_fsm_inst *fi;
+	struct lcs_loc_req *loc_req;
+	enum lcs_cause failure_cause;
+	uint8_t failure_diagnostic_val;
+};
+int lcs_ta_req_start(struct lcs_loc_req *lcs_loc_req);
+
+void lcs_bsslap_rx(struct gsm_subscriber_connection *conn, struct msgb *msg);
diff --git a/include/osmocom/bsc/paging.h b/include/osmocom/bsc/paging.h
index cd351cb..2d0f8da 100644
--- a/include/osmocom/bsc/paging.h
+++ b/include/osmocom/bsc/paging.h
@@ -94,6 +94,7 @@
 
 int paging_request_stop(struct bsc_msc_data **msc_p, enum bsc_paging_reason *reasons_p,
 			struct gsm_bts *bts, struct bsc_subscr *bsub);
+int paging_request_cancel(struct bsc_subscr *bsub, enum bsc_paging_reason reasons);
 
 /* update paging load */
 void paging_update_buffer_space(struct gsm_bts *bts, uint16_t);
diff --git a/include/osmocom/bsc/vty.h b/include/osmocom/bsc/vty.h
index a5a8452..d2361b0 100644
--- a/include/osmocom/bsc/vty.h
+++ b/include/osmocom/bsc/vty.h
@@ -27,6 +27,7 @@
 	CBC_NODE,
 	CBC_SERVER_NODE,
 	CBC_CLIENT_NODE,
+	SMLC_NODE,
 };
 
 struct log_info;