diff options
-rw-r--r-- | openbsc/include/openbsc/gsm_04_11.h | 5 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 5 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_11.c | 29 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_openbsc.c | 127 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_smsc.c | 17 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_smsc.h | 18 |
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 |