SMPP: VTY configuration of SMPP code, authentication support
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
index e3f3182..183fc25 100644
--- a/openbsc/include/openbsc/vty.h
+++ b/openbsc/include/openbsc/vty.h
@@ -35,6 +35,8 @@
 	PGROUP_NODE,
 	MNCC_INT_NODE,
 	BSC_NODE,
+	SMPP_NODE,
+	SMPP_ESME_NODE,
 };
 
 extern int bsc_vty_is_config_node(struct vty *vty, int node);
diff --git a/openbsc/src/libcommon/common_vty.c b/openbsc/src/libcommon/common_vty.c
index 0fd4f43..7342f14 100644
--- a/openbsc/src/libcommon/common_vty.c
+++ b/openbsc/src/libcommon/common_vty.c
@@ -89,6 +89,11 @@
 	case TRUNK_NODE:
 		vty->node = MGCP_NODE;
 		break;
+	case SMPP_ESME_NODE:
+		vty->node = SMPP_NODE;
+		vty->index = NULL;
+		break;
+	case SMPP_NODE:
 	case MSC_NODE:
 	case MNCC_INT_NODE:
 	default:
@@ -144,6 +149,11 @@
 	case PGROUP_NODE:
 		vty->node = NAT_NODE;
 		break;
+	case SMPP_ESME_NODE:
+		vty->node = SMPP_NODE;
+		vty->index = NULL;
+		break;
+	case SMPP_NODE:
 	case MGCP_NODE:
 	case GBPROXY_NODE:
 	case SGSN_NODE:
@@ -196,6 +206,8 @@
 	case PGROUP_NODE:
 	case MSC_NODE:
 	case MNCC_INT_NODE:
+	case SMPP_NODE:
+	case SMPP_ESME_NODE:
 	case BSC_NODE:
 		vty_config_unlock(vty);
 		vty->node = ENABLE_NODE;
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am
index 89fee91..64afedb 100644
--- a/openbsc/src/libmsc/Makefile.am
+++ b/openbsc/src/libmsc/Makefile.am
@@ -19,5 +19,5 @@
 			osmo_msc.c
 
 if BUILD_SMPP
-libmsc_a_SOURCES += smpp_smsc.c smpp_openbsc.c
+libmsc_a_SOURCES += smpp_smsc.c smpp_openbsc.c smpp_vty.c
 endif
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index 4a54e47..d8dde29 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -288,6 +288,14 @@
 	return 0;
 }
 
+static struct smsc *g_smsc;
+
+struct smsc *smsc_from_vty(struct vty *v)
+{
+	/* FIXME: this is ugly */
+	return g_smsc;
+}
+
 /*! \brief Initialize the OpenBSC SMPP interface */
 int smpp_openbsc_init(struct gsm_network *net, uint16_t port)
 {
@@ -303,5 +311,9 @@
 	osmo_signal_register_handler(SS_SMS, smpp_sms_cb, net);
 	osmo_signal_register_handler(SS_SUBSCR, smpp_subscr_cb, smsc);
 
+	g_smsc = smsc;
+
+	smpp_vty_init();
+
 	return rc;
 }
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index 8957c8e..493d079 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -51,6 +51,58 @@
 	ESME_BIND_TX = 0x02,
 };
 
+struct osmo_smpp_acl *smpp_acl_by_system_id(struct smsc *smsc,
+					    const char *sys_id)
+{
+	struct osmo_smpp_acl *acl;
+
+	llist_for_each_entry(acl, &smsc->acl_list, list) {
+		if (!strcmp(acl->system_id, sys_id))
+			return acl;
+	}
+
+	return NULL;
+}
+
+struct osmo_smpp_acl *smpp_acl_alloc(struct smsc *smsc, const char *sys_id)
+{
+	struct osmo_smpp_acl *acl;
+
+	if (strlen(sys_id) > SMPP_SYS_ID_LEN)
+		return NULL;
+
+	if (smpp_acl_by_system_id(smsc, sys_id))
+		return NULL;
+
+	acl = talloc_zero(smsc, struct osmo_smpp_acl);
+	if (!acl)
+		return NULL;
+
+	acl->smsc = smsc;
+	strcpy(acl->system_id, sys_id);
+
+	llist_add(&acl->list, &smsc->acl_list);
+
+	return acl;
+}
+
+void smpp_acl_delete(struct osmo_smpp_acl *acl)
+{
+	struct osmo_esme *esme, *e2;
+	struct smsc *smsc = acl->smsc;
+
+	llist_del(&acl->list);
+
+	llist_for_each_entry_safe(esme, e2, &smsc->esme_list, list) {
+		if (!strcmp(acl->system_id, esme->system_id)) {
+			/* FIXME: drop connection */
+		}
+	}
+
+	talloc_free(acl);
+}
+
+
 /*! \brief increaes the use/reference count */
 void smpp_esme_get(struct osmo_esme *esme)
 {
@@ -176,6 +228,7 @@
 {
 	struct bind_receiver_t bind;
 	struct bind_receiver_resp_t bind_r;
+	struct osmo_smpp_acl *acl;
 	int rc;
 
 	SMPP34_UNPACK(rc, BIND_RECEIVER, &bind, msgb_data(msg),
@@ -204,9 +257,26 @@
 	esme->smpp_version = bind.interface_version;
 	snprintf(esme->system_id, sizeof(esme->system_id), "%s",
 		 bind.system_id);
-	esme->bind_flags = ESME_BIND_RX;
 
-	/* FIXME */
+	acl = smpp_acl_by_system_id(esme->smsc, esme->system_id);
+	if (!esme->smsc->accept_all) {
+		if (!acl) {
+			/* This system is unknown */
+			bind_r.command_status = ESME_RINVSYSID;
+			goto err;
+		} else {
+			if (strlen(acl->passwd) &&
+			    strcmp(acl->passwd, (char *)bind.password)) {
+				bind_r.command_status = ESME_RINVPASWD;
+				goto err;
+			}
+			esme->acl = acl;
+			if (acl->default_route)
+				esme->smsc->def_route = esme;
+		}
+	}
+
+	esme->bind_flags = ESME_BIND_RX;
 err:
 	return 0;
 }
@@ -216,6 +286,7 @@
 {
 	struct bind_transmitter_t bind;
 	struct bind_transmitter_resp_t bind_r;
+	struct osmo_smpp_acl *acl;
 	struct tlv_t tlv;
 	int rc;
 
@@ -244,6 +315,23 @@
 
 	esme->smpp_version = bind.interface_version;
 	snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
+
+	acl = smpp_acl_by_system_id(esme->smsc, esme->system_id);
+	if (!esme->smsc->accept_all) {
+		if (!acl) {
+			/* This system is unknown */
+			bind_r.command_status = ESME_RINVSYSID;
+			goto err;
+		} else {
+			if (strlen(acl->passwd) &&
+			    strcmp(acl->passwd, (char *)bind.password)) {
+				bind_r.command_status = ESME_RINVPASWD;
+				goto err;
+			}
+			esme->acl = acl;
+		}
+	}
+
 	esme->bind_flags = ESME_BIND_TX;
 
 	/* build response */
@@ -265,6 +353,7 @@
 {
 	struct bind_transceiver_t bind;
 	struct bind_transceiver_resp_t bind_r;
+	struct osmo_smpp_acl *acl;
 	int rc;
 
 	SMPP34_UNPACK(rc, BIND_TRANSCEIVER, &bind, msgb_data(msg),
@@ -292,9 +381,27 @@
 
 	esme->smpp_version = bind.interface_version;
 	snprintf(esme->system_id, sizeof(esme->system_id), "%s", bind.system_id);
+
+	acl = smpp_acl_by_system_id(esme->smsc, esme->system_id);
+	if (!esme->smsc->accept_all) {
+		if (!acl) {
+			/* This system is unknown */
+			bind_r.command_status = ESME_RINVSYSID;
+			goto err;
+		} else {
+			if (strlen(acl->passwd) &&
+			    strcmp(acl->passwd, (char *)bind.password)) {
+				bind_r.command_status = ESME_RINVPASWD;
+				goto err;
+			}
+			esme->acl = acl;
+			if (acl->default_route)
+				esme->smsc->def_route = esme;
+		}
+	}
+
 	esme->bind_flags |= ESME_BIND_TX | ESME_BIND_RX;
 
-	/* FIXME */
 err:
 	return 0;
 }
@@ -324,6 +431,8 @@
 	}
 
 	esme->bind_flags = 0;
+	if (esme->smsc->def_route == esme)
+		esme->smsc->def_route = NULL;
 err:
 	return PACK_AND_SEND(esme, &unbind_r);
 }
@@ -628,11 +737,33 @@
 {
 	int rc;
 
-	INIT_LLIST_HEAD(&smsc->esme_list);
-	smsc->listen_ofd.data = smsc;
-	smsc->listen_ofd.cb = smsc_fd_cb;
+	/* default port for SMPP */
+	if (port == 0)
+		port = 2775;
+
+	/* This will not work if we were to actually ever use FD 0
+	 * (stdin) for this ... */
+	if (smsc->listen_ofd.fd <= 0) {
+		INIT_LLIST_HEAD(&smsc->esme_list);
+		INIT_LLIST_HEAD(&smsc->acl_list);
+		smsc->listen_ofd.data = smsc;
+		smsc->listen_ofd.cb = smsc_fd_cb;
+	} else {
+		close(smsc->listen_ofd.fd);
+		osmo_fd_unregister(&smsc->listen_ofd);
+	}
+
 	rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, SOCK_STREAM,
-				IPPROTO_TCP, NULL, port, OSMO_SOCK_F_BIND);
+				IPPROTO_TCP, NULL, port,
+				OSMO_SOCK_F_BIND);
+
+	/* if there is an error, try to re-bind to the old port */
+	if (rc < 0) {
+		rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC,
+					SOCK_STREAM, IPPROTO_TCP, NULL,
+					smsc->listen_port, OSMO_SOCK_F_BIND);
+	} else
+		smsc->listen_port = port;
 
 	return rc;
 }
diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h
index b1617e6..4b5bd85 100644
--- a/openbsc/src/libmsc/smpp_smsc.h
+++ b/openbsc/src/libmsc/smpp_smsc.h
@@ -12,15 +12,20 @@
 #include <smpp34_structs.h>
 #include <smpp34_params.h>
 
+#define SMPP_SYS_ID_LEN	16
+#define SMPP_PASSWD_LEN	16
+
 enum esme_read_state {
 	READ_ST_IN_LEN = 0,
 	READ_ST_IN_MSG = 1,
 };
 
+struct osmo_smpp_acl;
+
 struct osmo_esme {
 	struct llist_head list;
 	struct smsc *smsc;
-
+	struct osmo_smpp_acl *acl;
 	int use;
 
 	uint32_t own_seq_nr;
@@ -35,15 +40,28 @@
 	struct msgb *read_msg;
 
 	uint8_t smpp_version;
-	char system_id[16+1];
+	char system_id[SMPP_SYS_ID_LEN+1];
 
 	uint8_t bind_flags;
 };
 
+struct osmo_smpp_acl {
+	struct llist_head list;
+	struct smsc *smsc;
+	char *description;
+	char system_id[SMPP_SYS_ID_LEN+1];
+	char passwd[SMPP_PASSWD_LEN+1];
+	int default_route;
+};
+
 struct smsc {
 	struct osmo_fd listen_ofd;
 	struct llist_head esme_list;
-	char system_id[16+1];
+	struct llist_head acl_list;
+	uint16_t listen_port;
+	char system_id[SMPP_SYS_ID_LEN+1];
+	int accept_all;
+	struct osmo_esme *def_route;
 	void *priv;
 };
 
@@ -53,6 +71,11 @@
 void smpp_esme_get(struct osmo_esme *esme);
 void smpp_esme_put(struct osmo_esme *esme);
 
+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);
 
diff --git a/openbsc/src/libmsc/smpp_vty.c b/openbsc/src/libmsc/smpp_vty.c
new file mode 100644
index 0000000..ad496da
--- /dev/null
+++ b/openbsc/src/libmsc/smpp_vty.c
@@ -0,0 +1,308 @@
+/* SMPP vty interface */
+
+/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
+
+#include <openbsc/vty.h>
+
+#include "smpp_smsc.h"
+
+struct smsc *smsc_from_vty(struct vty *v);
+
+static struct cmd_node smpp_node = {
+	SMPP_NODE,
+	"%s(config-smpp)# ",
+	1,
+};
+
+static struct cmd_node esme_node = {
+	SMPP_ESME_NODE,
+	"%s(config-smpp-esme)# ",
+	1,
+};
+
+DEFUN(cfg_smpp, cfg_smpp_cmd,
+	"smpp", "Configure SMPP SMS Interface")
+{
+	vty->node = SMPP_NODE;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_smpp_port, cfg_smpp_port_cmd,
+	"local-tcp-port <1-65535>",
+	"Set the local TCP port on which we listen for SMPP\n"
+	"TCP port number")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+	uint16_t port = atoi(argv[0]);
+	int rc;
+
+	rc = smpp_smsc_init(smsc, port);
+	if (rc < 0) {
+		vty_out(vty, "%% Cannot bind to new port %u nor to "
+			"old port %u%s", port, smsc->listen_port, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (port != smsc->listen_port) {
+		vty_out(vty, "%% Cannot bind to new port %u, staying on old"
+			"port %u%s", port, smsc->listen_port, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_smpp_sys_id, cfg_smpp_sys_id_cmd,
+	"system-id ID", "Set the System ID of this SMSC")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+
+	if (strlen(argv[0])+1 > sizeof(smsc->system_id))
+		return CMD_WARNING;
+
+	strcpy(smsc->system_id, argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_smpp_policy, cfg_smpp_policy_cmd,
+	"policy (accept-all|closed)",
+	"Set the authentication policy of this SMSC\n"
+	"Accept all SMPP connections independeint of system ID / passwd\n"
+	"Accept only SMPP connections from ESMEs explicitly configured")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+
+	if (!strcmp(argv[0], "accept-all"))
+		smsc->accept_all = 1;
+	else
+		smsc->accept_all = 0;
+
+	return CMD_SUCCESS;
+}
+
+
+static int config_write_smpp(struct vty *vty)
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+
+	vty_out(vty, "smpp%s", VTY_NEWLINE);
+	vty_out(vty, " local-tcp-port %u%s", smsc->listen_port, VTY_NEWLINE);
+	vty_out(vty, " system-id %s%s", smsc->system_id, VTY_NEWLINE);
+	vty_out(vty, " policy %s%s",
+		smsc->accept_all ? "accept-all" : "closed", VTY_NEWLINE);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_esme, cfg_esme_cmd,
+	"esme NAME", "Configure a particular ESME")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+	struct osmo_smpp_acl *acl;
+	const char *id = argv[0];
+
+	if (strlen(id) > 16) {
+		vty_out(vty, "%% System ID cannot be more than 16 "
+			"characters long%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	acl = smpp_acl_by_system_id(smsc, id);
+	if (!acl) {
+		acl = smpp_acl_alloc(smsc, id);
+		if (!acl)
+			return CMD_WARNING;
+	}
+
+	vty->index = acl;
+	vty->index_sub = &acl->description;
+	vty->node = SMPP_ESME_NODE;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_esme, cfg_no_esme_cmd,
+	"no esme NAME", NO_STR "Remove ESME configuration")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+	struct osmo_smpp_acl *acl;
+	const char *id = argv[0];
+
+	acl = smpp_acl_by_system_id(smsc, id);
+	if (!acl) {
+		vty_out(vty, "%% ESME with system id '%s' unknown%s",
+			id, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	/* FIXME: close the connection, free data structure, etc. */
+
+	smpp_acl_delete(acl);
+
+	return CMD_SUCCESS;
+}
+
+
+DEFUN(cfg_esme_passwd, cfg_esme_passwd_cmd,
+	"password PASSWORD", "Set the password for this ESME")
+{
+	struct osmo_smpp_acl *acl = vty->index;
+
+	if (strlen(argv[0])+1 > sizeof(acl->passwd))
+		return CMD_WARNING;
+
+	strcpy(acl->passwd, argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_esme_no_passwd, cfg_esme_no_passwd_cmd,
+	"no password", NO_STR "Set the password for this ESME")
+{
+	struct osmo_smpp_acl *acl = vty->index;
+
+	memset(acl->passwd, 0, sizeof(acl->passwd));
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_esme_route, cfg_esme_route_cmd,
+	"route DESTINATION",
+	"Configure a route for MO-SMS to be sent to this ESME\n"
+	"Destination phone number")
+{
+	struct osmo_smpp_acl *acl = vty->index;
+
+	/* FIXME: check if DESTINATION is all-digits */
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_esme_defaultroute, cfg_esme_defaultroute_cmd,
+	"default-route",
+	"Set this ESME as default-route for all SMS to unknown destinations")
+{
+	struct osmo_smpp_acl *acl = vty->index;
+
+	acl->default_route = 1;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_esme_defaultroute, cfg_esme_no_defaultroute_cmd,
+	"no default-route", NO_STR
+	"Set this ESME as default-route for all SMS to unknown destinations")
+{
+	struct osmo_smpp_acl *acl = vty->index;
+
+	acl->default_route = 0;
+
+	/* remove currently active default route, if it was created by
+	 * this ACL */
+	if (acl->smsc->def_route && acl->smsc->def_route->acl == acl)
+		acl->smsc->def_route = NULL;
+
+	return CMD_SUCCESS;
+}
+
+static void dump_one_esme(struct vty *vty, struct osmo_esme *esme)
+{
+	char host[128], serv[128];
+
+	host[0] = 0;
+	serv[0] = 0;
+	getnameinfo((const struct sockaddr *) &esme->sa, esme->sa_len,
+		    host, sizeof(host), serv, sizeof(serv), NI_NUMERICSERV);
+
+	vty_out(vty, "ESME System ID: %s, Password: %s, SMPP Version %02x%s",
+		esme->system_id, esme->acl->passwd, esme->smpp_version, VTY_NEWLINE);
+	vty_out(vty, "  Connected from: %s:%s%s", host, serv, VTY_NEWLINE);
+}
+
+DEFUN(show_esme, show_esme_cmd,
+	"show smpp esme",
+	SHOW_STR "SMPP Interface\n" "SMPP Extrenal SMS Entity\n")
+{
+	struct smsc *smsc = smsc_from_vty(vty);
+	struct osmo_esme *esme;
+
+	llist_for_each_entry(esme, &smsc->esme_list, list)
+		dump_one_esme(vty, esme);
+
+	return CMD_SUCCESS;
+}
+
+static void config_write_esme_single(struct vty *vty, struct osmo_smpp_acl *acl)
+{
+	vty_out(vty, " esme %s%s", acl->system_id, VTY_NEWLINE);
+	if (strlen(acl->passwd))
+		vty_out(vty, "  password %s%s", acl->passwd, VTY_NEWLINE);
+	if (acl->default_route)
+		vty_out(vty, "  default-route%s", VTY_NEWLINE);
+}
+
+static int config_write_esme(struct vty *v)
+{
+	struct smsc *smsc = smsc_from_vty(v);
+	struct osmo_smpp_acl *acl;
+
+	llist_for_each_entry(acl, &smsc->acl_list, list)
+		config_write_esme_single(v, acl);
+
+	return CMD_SUCCESS;
+}
+
+int smpp_vty_init(void)
+{
+	install_node(&smpp_node, config_write_smpp);
+	install_default(SMPP_NODE);
+	install_element(CONFIG_NODE, &cfg_smpp_cmd);
+
+	install_element(SMPP_NODE, &cfg_smpp_port_cmd);
+	install_element(SMPP_NODE, &cfg_smpp_sys_id_cmd);
+	install_element(SMPP_NODE, &cfg_smpp_policy_cmd);
+	install_element(SMPP_NODE, &cfg_esme_cmd);
+	install_element(SMPP_NODE, &cfg_no_esme_cmd);
+
+	install_node(&esme_node, config_write_esme);
+	install_default(SMPP_ESME_NODE);
+	install_element(SMPP_ESME_NODE, &cfg_esme_passwd_cmd);
+	install_element(SMPP_ESME_NODE, &cfg_esme_no_passwd_cmd);
+	install_element(SMPP_ESME_NODE, &cfg_esme_route_cmd);
+	install_element(SMPP_ESME_NODE, &cfg_esme_defaultroute_cmd);
+	install_element(SMPP_ESME_NODE, &cfg_esme_no_defaultroute_cmd);
+	install_element(SMPP_ESME_NODE, &ournode_exit_cmd);
+
+	install_element_ve(&show_esme_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c
index b82a026..40c6f43 100644
--- a/openbsc/src/osmo-nitb/bsc_hack.c
+++ b/openbsc/src/osmo-nitb/bsc_hack.c
@@ -254,6 +254,11 @@
 	vty_init(&vty_info);
 	bsc_vty_init(&log_info);
 
+#ifdef BUILD_SMPP
+	if (smpp_openbsc_init(bsc_gsmnet, 0) < 0)
+		return -1;
+#endif
+
 	/* parse options */
 	handle_options(argc, argv);
 
@@ -312,10 +317,7 @@
 	/* start the SMS queue */
 	if (sms_queue_start(bsc_gsmnet, 20) != 0)
 		return -1;
-#ifdef BUILD_SMPP
-	if (smpp_openbsc_init(bsc_gsmnet, 6040) < 0)
-		return -1;
-#endif
+
 	if (daemonize) {
 		rc = osmo_daemonize();
 		if (rc < 0) {