Introduce libsmpputil

As part of preparation for libosmo-netif migration let's move common SMPP code
into separate build-time library and use it for both smpp_mirror and OsmoMSC
renaming the files if necessary.

While at it we also fix id/password legth limits in smpp_mirror and drop unused
fields from ESME struct.

Related: OS#5568
Change-Id: I61910651bc7c188dc2fb67d96189a66a47e7e8fb
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
index 4d80637..b07a004 100644
--- a/include/osmocom/Makefile.am
+++ b/include/osmocom/Makefile.am
@@ -1,3 +1,4 @@
 SUBDIRS = \
 	msc \
+	smpp \
 	$(NULL)
diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am
index faf1048..adda44c 100644
--- a/include/osmocom/msc/Makefile.am
+++ b/include/osmocom/msc/Makefile.am
@@ -45,7 +45,6 @@
 	sgs_vty.h \
 	signal.h \
 	silent_call.h \
-	smpp.h \
 	sms_queue.h \
 	transaction.h \
 	vlr.h \
diff --git a/include/osmocom/msc/smpp.h b/include/osmocom/msc/smpp.h
deleted file mode 100644
index bcdac8f..0000000
--- a/include/osmocom/msc/smpp.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-int smpp_openbsc_alloc_init(void *ctx);
-int smpp_openbsc_start(struct gsm_network *net);
diff --git a/include/osmocom/smpp/Makefile.am b/include/osmocom/smpp/Makefile.am
new file mode 100644
index 0000000..5ad34ad
--- /dev/null
+++ b/include/osmocom/smpp/Makefile.am
@@ -0,0 +1,4 @@
+noinst_HEADERS = \
+	smpp.h \
+	smpp_smsc.h \
+	$(NULL)
diff --git a/include/osmocom/smpp/smpp.h b/include/osmocom/smpp/smpp.h
new file mode 100644
index 0000000..cc0e800
--- /dev/null
+++ b/include/osmocom/smpp/smpp.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <osmocom/msc/gsm_data.h>
+
+/* Length limits according to SMPP 3.4 spec including NUL-byte: */
+#define SMPP_SYS_ID_LEN	15
+#define SMPP_PASSWD_LEN	8
+
+enum esme_read_state {
+	READ_ST_IN_LEN = 0,
+	READ_ST_IN_MSG = 1,
+};
+
+/*! \brief Ugly wrapper. libsmpp34 should do this itself! */
+#define SMPP34_UNPACK(rc, type, str, data, len) {	\
+		memset(str, 0, sizeof(*str));				\
+		rc = smpp34_unpack(type, str, data, len); }
+
+#define PACK_AND_SEND(esme, ptr)	pack_and_send(esme, (ptr)->command_id, ptr)
+
+/*! \brief initialize the libsmpp34 data structure for a response */
+#define INIT_RESP(type, resp, req) {						\
+		memset((resp), 0, sizeof(*(resp)));                 \
+		(resp)->command_length	= 0;						\
+		(resp)->command_id	= type;							\
+		(resp)->command_status	= ESME_ROK;					\
+		(resp)->sequence_number	= (req)->sequence_number; }
+
+uint32_t smpp_msgb_cmdid(struct msgb *msg);
+int smpp_openbsc_alloc_init(void *ctx);
+int smpp_openbsc_start(struct gsm_network *net);
diff --git a/include/osmocom/smpp/smpp_smsc.h b/include/osmocom/smpp/smpp_smsc.h
new file mode 100644
index 0000000..fb5164f
--- /dev/null
+++ b/include/osmocom/smpp/smpp_smsc.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/write_queue.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/smpp/smpp.h>
+
+#include <smpp34.h>
+#include <smpp34_structs.h>
+#include <smpp34_params.h>
+
+#define MODE_7BIT	7
+#define MODE_8BIT	8
+
+struct msc_a;
+
+struct osmo_smpp_acl;
+
+struct osmo_smpp_addr {
+	uint8_t ton;
+	uint8_t npi;
+	char addr[21+1];
+};
+
+struct osmo_esme {
+	struct llist_head list;
+	struct smsc *smsc;
+	struct osmo_smpp_acl *acl;
+	int use;
+
+	struct llist_head smpp_cmd_list;
+
+	uint32_t own_seq_nr;
+
+	struct osmo_wqueue wqueue;
+
+	enum esme_read_state read_state;
+	uint32_t read_len;
+	uint32_t read_idx;
+	struct msgb *read_msg;
+
+	uint8_t smpp_version;
+	char system_id[SMPP_SYS_ID_LEN+1];
+
+	uint8_t bind_flags;
+};
+
+struct osmo_smpp_acl {
+	struct llist_head list;
+	struct smsc *smsc;
+	struct osmo_esme *esme;
+	char *description;
+	char system_id[SMPP_SYS_ID_LEN+1];
+	char passwd[SMPP_PASSWD_LEN+1];
+	int default_route;
+	int deliver_src_imsi;
+	int osmocom_ext;
+	int dcs_transparent;
+	int alert_notifications;
+	struct llist_head route_list;
+};
+
+enum osmo_smpp_rtype {
+	SMPP_ROUTE_NONE,
+	SMPP_ROUTE_PREFIX,
+};
+
+struct osmo_smpp_route {
+	struct llist_head list;	/*!< in acl.route_list */
+	struct llist_head global_list; /*!< in smsc->route_list */
+	struct osmo_smpp_acl *acl;
+	enum osmo_smpp_rtype type;
+	union {
+		struct osmo_smpp_addr prefix;
+	} u;
+};
+
+struct osmo_smpp_cmd {
+	struct llist_head	list;
+	struct vlr_subscr	*vsub;
+	uint32_t		sequence_nr;
+	uint32_t		gsm411_msg_ref;
+	uint8_t			gsm411_trans_id;
+	bool			is_report;
+	struct osmo_timer_list	response_timer;
+};
+
+struct osmo_smpp_cmd *smpp_cmd_find_by_seqnum(struct osmo_esme *esme,
+					      uint32_t sequence_number);
+void smpp_cmd_ack(struct osmo_smpp_cmd *cmd);
+void smpp_cmd_err(struct osmo_smpp_cmd *cmd, uint32_t status);
+void smpp_cmd_flush_pending(struct osmo_esme *esme);
+
+struct smsc {
+	struct osmo_fd listen_ofd;
+	struct llist_head esme_list;
+	struct llist_head acl_list;
+	struct llist_head route_list;
+	char *bind_addr;
+	uint16_t listen_port;
+	char system_id[SMPP_SYS_ID_LEN+1];
+	int accept_all;
+	int smpp_first;
+	struct osmo_smpp_acl *def_route;
+	void *priv;
+};
+
+int smpp_addr_eq(const struct osmo_smpp_addr *a,
+		 const struct osmo_smpp_addr *b);
+
+struct smsc *smpp_smsc_alloc_init(void *ctx);
+int smpp_smsc_conf(struct smsc *smsc, const char *bind_addr, uint16_t port);
+int smpp_smsc_start(struct smsc *smsc, const char *bind_addr, uint16_t port);
+int smpp_smsc_restart(struct smsc *smsc, const char *bind_addr, uint16_t port);
+void smpp_smsc_stop(struct smsc *smsc);
+
+void smpp_esme_get(struct osmo_esme *esme);
+void smpp_esme_put(struct osmo_esme *esme);
+
+int smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest, struct osmo_esme **emse);
+
+struct osmo_smpp_acl *smpp_acl_alloc(struct smsc *smsc, const char *sys_id);
+struct osmo_smpp_acl *smpp_acl_by_system_id(struct smsc *smsc,
+					    const char *sys_id);
+void smpp_acl_delete(struct osmo_smpp_acl *acl);
+
+int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr,
+		     uint32_t command_status, char *msg_id);
+
+int smpp_tx_alert(struct osmo_esme *esme, uint8_t ton, uint8_t npi,
+		  const char *addr, uint8_t avail_status);
+
+int smpp_tx_deliver(struct osmo_esme *esme, struct deliver_sm_t *deliver);
+
+int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
+			struct submit_sm_resp_t *submit_r);
+
+int smpp_route_pfx_add(struct osmo_smpp_acl *acl,
+		       const struct osmo_smpp_addr *pfx);
+int smpp_route_pfx_del(struct osmo_smpp_acl *acl,
+		       const struct osmo_smpp_addr *pfx);
+
+int smpp_vty_init(void);
+
+int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode);
+
+time_t smpp_parse_time_format(const char *vp, time_t *t_now);
+
+
+struct gsm_sms;
+struct ran_conn;
+
+bool smpp_route_smpp_first();
+int smpp_try_deliver(struct gsm_sms *sms, struct msc_a *msc_a);