SMPP: Implement ALERT NOTIFICATION on attach/detach of subscribers
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index ff61bab..c2e4c28 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -238,6 +238,40 @@
 	return rc;
 }
 
+/*! \brief signal handler for subscriber related signals */
+static int smpp_subscr_cb(unsigned int subsys, unsigned int signal,
+			  void *handler_data, void *signal_data)
+{
+	struct gsm_subscriber *subscr = signal_data;
+	struct smsc *smsc = handler_data;
+	struct osmo_esme *esme;
+	uint8_t smpp_avail_status;
+
+	/* determine the smpp_avail_status depending on attach/detach */
+	switch (signal) {
+	case S_SUBSCR_ATTACHED:
+		smpp_avail_status = 0;
+		break;
+	case S_SUBSCR_DETACHED:
+		smpp_avail_status = 2;
+		break;
+	default:
+		return 0;
+	}
+
+	llist_for_each_entry(esme, &smsc->esme_list, list) {
+		/* we currently send an alert notification to each ESME that is
+		 * connected, and do not require a (non-existant) delivery
+		 * pending flag to be set before,  FIXME: make this VTY
+		 * configurable */
+		smpp_tx_alert(esme, TON_Subscriber_Number,
+				NPI_Land_Mobile_E212, subscr->imsi,
+				smpp_avail_status);
+	}
+
+	return 0;
+}
+
 /*! \brief Initialize the OpenBSC SMPP interface */
 int smpp_openbsc_init(struct gsm_network *net, uint16_t port)
 {
@@ -251,7 +285,7 @@
 		talloc_free(smsc);
 
 	osmo_signal_register_handler(SS_SMS, smpp_sms_cb, net);
+	osmo_signal_register_handler(SS_SUBSCR, smpp_subscr_cb, smsc);
 
 	return rc;
 }
-
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index 765cb51..6bfd0c9 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -341,11 +341,47 @@
 	submit_r.command_id	= SUBMIT_SM_RESP;
 	submit_r.command_status	= command_status;
 	submit_r.sequence_number= sequence_nr;
-	snprintf(submit_r.message_id, sizeof(submit_r.message_id), "%s", msg_id);
+	snprintf((char *) submit_r.message_id, sizeof(submit_r.message_id), "%s", msg_id);
 
 	return PACK_AND_SEND(esme, &submit_r);
 }
 
+static const struct value_string smpp_avail_strs[] = {
+	{ 0,	"Available" },
+	{ 1,	"Denied" },
+	{ 2,	"Unavailable" },
+	{ 0,	NULL }
+};
+
+/*! \brief send an ALERT_NOTIFICATION to a remote ESME */
+int smpp_tx_alert(struct osmo_esme *esme, uint8_t ton, uint8_t npi,
+		  const char *addr, uint8_t avail_status)
+{
+	struct alert_notification_t alert;
+	struct tlv_t tlv;
+
+	memset(&alert, 0, sizeof(alert));
+	alert.command_length	= 0;
+	alert.command_id	= ALERT_NOTIFICATION;
+	alert.command_status	= ESME_ROK;
+	alert.sequence_number	= esme->own_seq_nr++;
+	alert.source_addr_ton 	= ton;
+	alert.source_addr_npi	= npi;
+	snprintf(alert.source_addr, sizeof(alert.source_addr), "%s", addr);
+
+	tlv.tag = TLVID_ms_availability_status;
+	tlv.length = sizeof(uint8_t);
+	tlv.value.val08 = avail_status;
+	build_tlv(&alert.tlv, &tlv);
+
+	LOGP(DSMPP, LOGL_DEBUG, "[%s] Tx ALERT_NOTIFICATION (%s/%u/%u): %s\n",
+		esme->system_id, alert.source_addr, alert.source_addr_ton,
+		alert.source_addr_npi,
+		get_value_string(smpp_avail_strs, avail_status));
+
+	return PACK_AND_SEND(esme, &alert);
+}
+
 /*! \brief handle an incoming SMPP SUBMIT-SM */
 static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg)
 {
@@ -524,6 +560,7 @@
 		return -ENOMEM;
 
 	smpp_esme_get(esme);
+	esme->own_seq_nr = rand();
 	esme->smsc = smsc;
 	osmo_wqueue_init(&esme->wqueue, 10);
 	esme->wqueue.bfd.fd = fd;
diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h
index e93ae30..b1617e6 100644
--- a/openbsc/src/libmsc/smpp_smsc.h
+++ b/openbsc/src/libmsc/smpp_smsc.h
@@ -23,6 +23,8 @@
 
 	int use;
 
+	uint32_t own_seq_nr;
+
 	struct osmo_wqueue wqueue;
 	struct sockaddr_storage sa;
 	socklen_t sa_len;
@@ -54,6 +56,9 @@
 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 handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
 			struct submit_sm_resp_t *submit_r);