aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorIvan Kluchnikov <kluchnikovi@gmail.com>2015-12-21 12:34:30 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2017-02-07 18:59:55 +0300
commit32906636f16ae2d45854173acca36768699a27e2 (patch)
tree79c239ded8cdbe3120037a4e710f280ba7a04b52 /openbsc
parentb314380065323f4f21edb7ec6f0cd55a21e8d1b3 (diff)
sms: Add functions for forwarding/handling SMS in RP format to/from external application
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gsm_04_11.h3
-rw-r--r--openbsc/include/openbsc/gsm_sup.h4
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c152
-rw-r--r--openbsc/src/libmsc/gsm_sup.c73
4 files changed, 225 insertions, 7 deletions
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 149de9083..6408b7b5c 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -38,5 +38,8 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn,
struct gsm_sms *sms);
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
+int gsm411_send_rp_msg_subscr(struct gsm_subscriber *subscr,
+ struct msgb *rp);
+
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
#endif
diff --git a/openbsc/include/openbsc/gsm_sup.h b/openbsc/include/openbsc/gsm_sup.h
index 09d2f9989..8dd15a2f7 100644
--- a/openbsc/include/openbsc/gsm_sup.h
+++ b/openbsc/include/openbsc/gsm_sup.h
@@ -4,6 +4,7 @@
#include <openbsc/debug.h>
#include <openbsc/gsm_subscriber.h>
#include <osmocom/gsm/gsm0480.h>
+#include <osmocom/gsm/protocol/gsm_04_11.h>
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
LOGP(DSUP, level, "SUBSCR(%s) " fmt, \
@@ -19,4 +20,7 @@ int subscr_location_update(struct gsm_subscriber *subscr);
int subscr_tx_uss_message(struct ss_request *req,
struct gsm_subscriber *subscr);
+int subscr_tx_sms_message(struct gsm_subscriber *subscr,
+ struct gsm411_rp_hdr *rph);
+
#endif /* _GSM_SUP_H */
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 6164a0887..2dd487132 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -553,13 +553,18 @@ 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)
- return gsm411_send_rp_ack(trans, rph->msg_ref);
- else if (rc > 0)
- return gsm411_send_rp_error(trans, rph->msg_ref, rc);
- else
- return rc;
+ if (trans->net->sms_client) {
+ osmo_counter_inc(trans->conn->bts->network->stats.sms.submitted);
+ return subscr_tx_sms_message(trans->subscr, rph);
+ } else {
+ rc = gsm340_rx_tpdu(trans->conn, msg);
+ if (rc == 0)
+ return gsm411_send_rp_ack(trans, rph->msg_ref);
+ else if (rc > 0)
+ return gsm411_send_rp_error(trans, rph->msg_ref, rc);
+ else
+ return rc;
+ }
}
/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
@@ -1062,3 +1067,136 @@ void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
}
}
+
+static int gsm411_send_rp_data(struct gsm_subscriber_connection *conn,
+ struct msgb *rp)
+{
+ struct gsm_trans *trans;
+ uint8_t *rp_msg = msgb_data(rp);
+ uint8_t rp_msg_ref;
+ rp_msg_ref = *(rp_msg + 1);
+
+ int transaction_id;
+
+ transaction_id =
+ trans_assign_trans_id(conn->bts->network, conn->subscr,
+ GSM48_PDISC_SMS, 0);
+ if (transaction_id == -1) {
+ LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
+ msgb_free(rp);
+ return -EBUSY;
+ }
+
+ /* FIXME: allocate transaction with message reference */
+ trans = trans_alloc(conn->bts->network, conn->subscr,
+ GSM48_PDISC_SMS,
+ transaction_id, new_callref++);
+ if (!trans) {
+ LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n");
+ msgb_free(rp);
+ /* FIXME: send some error message */
+ return -ENOMEM;
+ }
+ gsm411_smc_init(&trans->sms.smc_inst, 0, 1,
+ gsm411_mn_recv, gsm411_mm_send);
+ gsm411_smr_init(&trans->sms.smr_inst, 0, 1,
+ gsm411_rl_recv, gsm411_mn_send);
+ trans->msg_ref = rp_msg_ref;
+ trans->conn = conn;
+
+ osmo_counter_inc(conn->bts->network->stats.sms.delivered);
+ return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_DATA_REQ, rp);
+}
+
+static int gsm411_send_rp_resp(struct gsm_subscriber *subscr,
+ struct msgb *rp)
+{
+ struct gsm_subscriber_connection *conn;
+ struct gsm_trans *trans;
+ uint8_t *rp_msg = msgb_data(rp);
+ uint8_t rp_msg_ref;
+ rp_msg_ref = *(rp_msg + 1);
+ conn = connection_for_subscr(subscr);
+ if (!conn) {
+ msgb_free(rp);
+ return -1;
+ }
+
+ trans = trans_find_by_msgref(conn, rp_msg_ref);
+ if (!trans) {
+ msgb_free(rp);
+ return -1;
+ }
+
+ return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ, rp);
+}
+
+/* paging callback. Here we get called if paging a subscriber has
+ * succeeded or failed. */
+static int paging_cb_send_rp_data(unsigned int hooknum, unsigned int event,
+ struct msgb *msg, void *_conn, void *_rp)
+{
+ struct gsm_subscriber_connection *conn = _conn;
+ struct msgb *rp = _rp;
+ int rc = 0;
+
+ DEBUGP(DLSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
+ "conn=%p, rp=%p)\n", hooknum, event, msg, conn, rp);
+
+ if (hooknum != GSM_HOOK_RR_PAGING)
+ return -EINVAL;
+
+ switch (event) {
+ case GSM_PAGING_SUCCEEDED:
+ gsm411_send_rp_data(conn, rp);
+ break;
+ case GSM_PAGING_EXPIRED:
+ case GSM_PAGING_OOM:
+ case GSM_PAGING_BUSY:
+ msgb_free(rp);
+ rc = -ETIMEDOUT;
+ break;
+ default:
+ LOGP(DLSMS, LOGL_ERROR, "Unhandled paging event: %d\n", event);
+ }
+
+ return rc;
+}
+
+static int gsm411_send_rp_req(struct gsm_subscriber *subscr,
+ struct msgb *rp)
+{
+ struct gsm_subscriber_connection *conn;
+ conn = connection_for_subscr(subscr);
+
+ if (conn) {
+ return gsm411_send_rp_data(conn, rp);
+ }
+
+ void *res;
+ res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
+ paging_cb_send_rp_data, rp);
+ if (!res) {
+ msgb_free(rp);
+ }
+ return 0;
+}
+
+int gsm411_send_rp_msg_subscr(struct gsm_subscriber *subscr,
+ struct msgb *rp)
+{
+ uint8_t *rp_msg = msgb_data(rp);
+ uint8_t rp_msg_type;
+ rp_msg_type = *rp_msg;
+
+ switch (rp_msg_type) {
+ case GSM411_MT_RP_ACK_MT:
+ case GSM411_MT_RP_ERROR_MT:
+ return gsm411_send_rp_resp(subscr, rp);
+ case GSM411_MT_RP_DATA_MT:
+ return gsm411_send_rp_req(subscr, rp);
+ default:
+ msgb_free(rp);
+ return -1;
+ }
+}
diff --git a/openbsc/src/libmsc/gsm_sup.c b/openbsc/src/libmsc/gsm_sup.c
index 9dc8f191e..2e0fe7201 100644
--- a/openbsc/src/libmsc/gsm_sup.c
+++ b/openbsc/src/libmsc/gsm_sup.c
@@ -31,6 +31,9 @@
#include <openbsc/osmo_msc.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/ussd.h>
+#include <openbsc/gsm_04_11.h>
+#include <osmocom/gsm/protocol/gsm_04_11.h>
+#include <osmocom/gsm/gsm0411_utils.h>
#if 0
enum {
@@ -174,6 +177,74 @@ static int rx_uss_message(const uint8_t* data, size_t len)
}
#endif
+int subscr_tx_sms_message(struct gsm_subscriber *subscr,
+ struct gsm411_rp_hdr *rph)
+{
+ uint8_t *data;
+ struct msgb *msg = gprs_gsup_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ msgb_put_u8(msg, GPRS_GSUP_MSGT_SMS);
+
+ if (subscr->extension) {
+ uint8_t bcd_buf[32];
+ int bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf),
+ 0, subscr->extension);
+ msgb_tlv_put(msg, 0x82, bcd_len - 1, &bcd_buf[1]);
+ }
+ msgb_put_u8(msg, rph->msg_type);
+ msgb_put_u8(msg, rph->msg_ref);
+
+ data = msgb_put(msg, rph->len - 2);
+ memcpy(data, rph->data, rph->len - 2);
+
+ return gprs_gsup_client_send(subscr->group->net->sms_client, msg);
+}
+
+static int rx_sms_message(const uint8_t* data, size_t data_len)
+{
+
+ int rc;
+ char extension[15];
+ uint8_t *value;
+ size_t value_len;
+ int offset = 0;
+ uint8_t *rp_hdr = (uint8_t*)data + offset;
+
+ offset++;
+ rc = gprs_match_tlv(&rp_hdr, &data_len, 0x82, &value, &value_len);
+
+ if (rc <= 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+
+ if (value_len * 2 + 1 > ARRAY_SIZE(extension))
+ return -GMM_CAUSE_INV_MAND_INFO;
+
+ /* Note that gsm48_decode_bcd_number expects the number of encoded MSISDN
+ * octets in the first octet. By coincidence (the TLV encoding) the byte
+ * before the value part already contains this length so we can use it
+ * here.
+ */
+ OSMO_ASSERT(value[-1] == value_len);
+ gsm48_decode_bcd_number(extension, ARRAY_SIZE(extension), value - 1, 0);
+ offset += 2 + value_len;
+
+ struct msgb *msg = gsm411_msgb_alloc();
+ uint8_t *rp_msg;
+ rp_msg = (uint8_t *)msgb_put(msg, data_len - offset);
+ memcpy(rp_msg, data + offset, data_len - offset);
+
+ struct gsm_subscriber *subscr;
+ subscr = subscr_get_by_extension(NULL, extension);
+ if (!subscr) {
+ msgb_free(msg);
+ return -GMM_CAUSE_IMSI_UNKNOWN;
+ }
+
+ return gsm411_send_rp_msg_subscr(subscr, msg);
+}
+
static int subscr_tx_sup_message(struct gprs_gsup_client *sup_client,
struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
@@ -442,6 +513,8 @@ static int subscr_rx_sup_message(struct gprs_gsup_client *sup_client, struct msg
#if 0
if (*data == GPRS_GSUP_MSGT_MAP) {
return rx_uss_message(data, data_len);
+ } else if (*data == GPRS_GSUP_MSGT_SMS) {
+ return rx_sms_message(data, data_len);
}
#endif
rc = gprs_gsup_decode(data, data_len, &gsup_msg);