aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gsm_04_11.h5
-rw-r--r--openbsc/include/openbsc/gsm_data.h5
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c29
-rw-r--r--openbsc/src/libmsc/smpp_openbsc.c127
-rw-r--r--openbsc/src/libmsc/smpp_smsc.c17
-rw-r--r--openbsc/src/libmsc/smpp_smsc.h18
6 files changed, 184 insertions, 17 deletions
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 149de9083..017c88765 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -39,4 +39,9 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn,
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
+
+int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref);
+int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref,
+ uint8_t cause);
+
#endif
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 1d90eee59..6d814c8e7 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -429,6 +429,11 @@ struct gsm_sms {
enum gsm_sms_source_id source;
struct {
+ uint8_t transaction_id;
+ uint32_t msg_ref;
+ } gsm411;
+
+ struct {
struct osmo_esme *esme;
uint32_t sequence_nr;
int transaction_mode;
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index a94b9717b..aa2030f80 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -278,7 +278,7 @@ static int gsm340_gen_sms_deliver_tpdu(struct msgb *msg, struct gsm_sms *sms)
}
int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg,
- struct gsm_sms *gsms, uint8_t sms_mti)
+ struct gsm_sms *gsms, uint8_t sms_mti, bool *deferred)
{
int rc;
@@ -292,7 +292,7 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg,
* delivery of the SMS.
*/
if (smpp_first) {
- rc = smpp_try_deliver(gsms, conn);
+ rc = smpp_try_deliver(gsms, conn, deferred);
if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED)
goto try_local;
if (rc < 0) {
@@ -320,7 +320,7 @@ try_local:
return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
}
- rc = smpp_try_deliver(gsms, conn);
+ rc = smpp_try_deliver(gsms, conn, deferred);
if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED) {
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
} else if (rc < 0) {
@@ -363,8 +363,10 @@ try_local:
/* process an incoming TPDU (called from RP-DATA)
* return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
-static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
+static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg,
+ uint32_t gsm411_msg_ref, bool *deferred)
{
+ struct gsm_subscriber_connection *conn = trans->conn;
uint8_t *smsp = msgb_sms(msg);
struct gsm_sms *gsms;
unsigned int sms_alphabet;
@@ -395,6 +397,9 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
smsp++;
gsms->msg_ref = *smsp++;
+ gsms->gsm411.transaction_id = trans->transaction_id;
+ gsms->gsm411.msg_ref = gsm411_msg_ref;
+
/* length in bytes of the destination address */
da_len_bytes = 2 + *smsp/2 + *smsp%2;
if (da_len_bytes > 12) {
@@ -481,9 +486,10 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
/* FIXME: This looks very wrong */
send_signal(0, NULL, gsms, 0);
- rc = sms_route_mt_sms(conn, msg, gsms, sms_mti);
+ rc = sms_route_mt_sms(conn, msg, gsms, sms_mti, deferred);
out:
- sms_free(gsms);
+ if (!deferred)
+ sms_free(gsms);
return rc;
}
@@ -505,7 +511,7 @@ static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg,
return gsm411_smr_send(inst, rl_msg_type, msg);
}
-static int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
+int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
{
struct msgb *msg = gsm411_msgb_alloc();
@@ -515,8 +521,8 @@ static int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref)
msg_ref, GSM411_SM_RL_REPORT_REQ);
}
-static int gsm411_send_rp_error(struct gsm_trans *trans,
- uint8_t msg_ref, uint8_t cause)
+int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref,
+ uint8_t cause)
{
struct msgb *msg = gsm411_msgb_alloc();
@@ -536,6 +542,7 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
uint8_t dst_len, uint8_t *dst,
uint8_t tpdu_len, uint8_t *tpdu)
{
+ bool deferred = false;
int rc = 0;
if (src_len && src)
@@ -552,8 +559,8 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len));
- rc = gsm340_rx_tpdu(trans->conn, msg);
- if (rc == 0)
+ rc = gsm340_rx_tpdu(trans, msg, rph->msg_ref, &deferred);
+ if (rc == 0 && !deferred)
return gsm411_send_rp_ack(trans, rph->msg_ref);
else if (rc > 0)
return gsm411_send_rp_error(trans, rph->msg_ref, rc);
diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c
index ec9dda3c1..8f1a96c5c 100644
--- a/openbsc/src/libmsc/smpp_openbsc.c
+++ b/openbsc/src/libmsc/smpp_openbsc.c
@@ -44,6 +44,7 @@
#include <openbsc/signal.h>
#include <openbsc/transaction.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/chan_alloc.h>
#include "smpp_smsc.h"
@@ -460,12 +461,122 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
}
}
+static void smpp_cmd_free(struct osmo_smpp_cmd *cmd)
+{
+ osmo_timer_del(&cmd->response_timer);
+ llist_del(&cmd->list);
+ subscr_put(cmd->subscr);
+ sms_free(cmd->sms);
+ talloc_free(cmd);
+}
+
+void smpp_cmd_flush_pending(struct osmo_esme *esme)
+{
+ struct osmo_smpp_cmd *cmd, *next;
+
+ llist_for_each_entry_safe(cmd, next, &esme->smpp_cmd_list, list)
+ smpp_cmd_free(cmd);
+}
+
+void smpp_cmd_ack(struct osmo_smpp_cmd *cmd)
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm_trans *trans;
+
+ conn = connection_for_subscr(cmd->subscr);
+ if (!conn) {
+ LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n");
+ return;
+ }
+
+ trans = trans_find_by_id(conn, GSM48_PDISC_SMS,
+ cmd->sms->gsm411.transaction_id);
+ if (!trans) {
+ LOGP(DSMPP, LOGL_ERROR, "GSM transaction %u is gone\n",
+ cmd->sms->gsm411.transaction_id);
+ return;
+ }
+
+ gsm411_send_rp_ack(trans, cmd->sms->gsm411.msg_ref);
+ smpp_cmd_free(cmd);
+}
+
+void smpp_cmd_err(struct osmo_smpp_cmd *cmd)
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm_trans *trans;
+
+ conn = connection_for_subscr(cmd->subscr);
+ if (!conn) {
+ LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n");
+ return;
+ }
+
+ trans = trans_find_by_id(conn, GSM48_PDISC_SMS,
+ cmd->sms->gsm411.transaction_id);
+ if (!trans) {
+ LOGP(DSMPP, LOGL_ERROR, "GSM transaction %u is gone\n",
+ cmd->sms->gsm411.transaction_id);
+ return;
+ }
+
+ gsm411_send_rp_error(trans, cmd->sms->gsm411.msg_ref,
+ GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER);
+ smpp_cmd_free(cmd);
+}
+
+static void smpp_deliver_sm_cb(void *data)
+{
+ smpp_cmd_err(data);
+}
+
+static int smpp_cmd_enqueue(struct osmo_esme *esme,
+ struct gsm_subscriber *subscr, struct gsm_sms *sms,
+ uint32_t sequence_number, bool *deferred)
+{
+ struct osmo_smpp_cmd *cmd;
+
+ cmd = talloc_zero(esme, struct osmo_smpp_cmd);
+ if (!cmd)
+ return -1;
+
+ cmd->sequence_nr = sequence_number;
+ cmd->sms = sms;
+ cmd->subscr = subscr_get(subscr);
+
+ /* FIXME: No predefined value for this response_timer as specified by
+ * SMPP 3.4 specs, section 7.2. Make this configurable? Don't forget
+ * lchan keeps busy until we get a reply to this SMPP command. Too high
+ * value may exhaust resources.
+ */
+ cmd->response_timer.cb = smpp_deliver_sm_cb;
+ cmd->response_timer.data = cmd;
+ osmo_timer_schedule(&cmd->response_timer, 5, 0);
+ llist_add_tail(&cmd->list, &esme->smpp_cmd_list);
+ *deferred = true;
+
+ return 0;
+}
+
+struct osmo_smpp_cmd *smpp_cmd_find_by_seqnum(struct osmo_esme *esme,
+ uint32_t sequence_nr)
+{
+ struct osmo_smpp_cmd *cmd;
+
+ llist_for_each_entry(cmd, &esme->smpp_cmd_list, list) {
+ if (cmd->sequence_nr == sequence_nr)
+ return cmd;
+ }
+ return NULL;
+}
+
static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
- struct gsm_subscriber_connection *conn)
+ struct gsm_subscriber_connection *conn,
+ bool *deferred)
{
struct deliver_sm_t deliver;
+ int mode, ret;
uint8_t dcs;
- int mode;
memset(&deliver, 0, sizeof(deliver));
deliver.command_length = 0;
@@ -537,7 +648,12 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
if (esme->acl && esme->acl->osmocom_ext && conn->lchan)
append_osmo_tlvs(&deliver.tlv, conn->lchan);
- return smpp_tx_deliver(esme, &deliver);
+ ret = smpp_tx_deliver(esme, &deliver);
+ if (ret < 0)
+ return ret;
+
+ return smpp_cmd_enqueue(esme, conn->subscr, sms,
+ deliver.sequence_number, deferred);
}
static struct smsc *g_smsc;
@@ -547,7 +663,8 @@ int smpp_route_smpp_first(struct gsm_sms *sms, struct gsm_subscriber_connection
return g_smsc->smpp_first;
}
-int smpp_try_deliver(struct gsm_sms *sms, struct gsm_subscriber_connection *conn)
+int smpp_try_deliver(struct gsm_sms *sms,
+ struct gsm_subscriber_connection *conn, bool *deferred)
{
struct osmo_esme *esme;
struct osmo_smpp_addr dst;
@@ -561,7 +678,7 @@ int smpp_try_deliver(struct gsm_sms *sms, struct gsm_subscriber_connection *conn
if (!esme)
return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED;
- return deliver_to_esme(esme, sms, conn);
+ return deliver_to_esme(esme, sms, conn, deferred);
}
struct smsc *smsc_from_vty(struct vty *v)
diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c
index e53749023..bd259186f 100644
--- a/openbsc/src/libmsc/smpp_smsc.c
+++ b/openbsc/src/libmsc/smpp_smsc.c
@@ -247,6 +247,7 @@ static void esme_destroy(struct osmo_esme *esme)
osmo_fd_unregister(&esme->wqueue.bfd);
close(esme->wqueue.bfd.fd);
}
+ smpp_cmd_flush_pending(esme);
llist_del(&esme->list);
talloc_free(esme);
}
@@ -660,6 +661,7 @@ int smpp_tx_deliver(struct osmo_esme *esme, struct deliver_sm_t *deliver)
static int smpp_handle_deliver_resp(struct osmo_esme *esme, struct msgb *msg)
{
struct deliver_sm_resp_t deliver_r;
+ struct osmo_smpp_cmd *cmd;
int rc;
memset(&deliver_r, 0, sizeof(deliver_r));
@@ -671,6 +673,20 @@ static int smpp_handle_deliver_resp(struct osmo_esme *esme, struct msgb *msg)
return rc;
}
+ cmd = smpp_cmd_find_by_seqnum(esme, deliver_r.sequence_number);
+ if (!cmd) {
+ LOGP(DSMPP, LOGL_ERROR, "[%s] Rx DELIVER-SM RESP !? (%s)\n",
+ esme->system_id, get_value_string(smpp_status_strs,
+ deliver_r.command_status));
+ return -1;
+ }
+
+ /* Map SMPP command status to GSM 04.11 cause? */
+ if (deliver_r.command_status == ESME_ROK)
+ smpp_cmd_ack(cmd);
+ else
+ smpp_cmd_err(cmd);
+
LOGP(DSMPP, LOGL_INFO, "[%s] Rx DELIVER-SM RESP (%s)\n",
esme->system_id, get_value_string(smpp_status_strs,
deliver_r.command_status));
@@ -889,6 +905,7 @@ static int link_accept_cb(struct smsc *smsc, int fd,
return -ENOMEM;
}
+ INIT_LLIST_HEAD(&esme->smpp_cmd_list);
smpp_esme_get(esme);
esme->own_seq_nr = rand();
esme_inc_seq_nr(esme);
diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h
index bd20137ef..b95a1f509 100644
--- a/openbsc/src/libmsc/smpp_smsc.h
+++ b/openbsc/src/libmsc/smpp_smsc.h
@@ -7,6 +7,7 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/write_queue.h>
+#include <osmocom/core/timer.h>
#include <smpp34.h>
#include <smpp34_structs.h>
@@ -37,6 +38,8 @@ struct osmo_esme {
struct osmo_smpp_acl *acl;
int use;
+ struct llist_head smpp_cmd_list;
+
uint32_t own_seq_nr;
struct osmo_wqueue wqueue;
@@ -83,6 +86,19 @@ struct osmo_smpp_route {
} u;
};
+struct osmo_smpp_cmd {
+ struct llist_head list;
+ struct gsm_subscriber *subscr;
+ struct gsm_sms *sms;
+ uint32_t sequence_nr;
+ 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);
+void smpp_cmd_flush_pending(struct osmo_esme *esme);
struct smsc {
struct osmo_fd listen_ofd;
@@ -146,5 +162,5 @@ struct gsm_subscriber_connection;
int smpp_route_smpp_first(struct gsm_sms *sms,
struct gsm_subscriber_connection *conn);
int smpp_try_deliver(struct gsm_sms *sms,
- struct gsm_subscriber_connection *conn);
+ struct gsm_subscriber_connection *conn, bool *deferred);
#endif