diff options
author | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2015-12-21 12:34:30 +0300 |
---|---|---|
committer | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2017-02-07 18:59:55 +0300 |
commit | 32906636f16ae2d45854173acca36768699a27e2 (patch) | |
tree | 79c239ded8cdbe3120037a4e710f280ba7a04b52 /openbsc | |
parent | b314380065323f4f21edb7ec6f0cd55a21e8d1b3 (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.h | 3 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_sup.h | 4 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_11.c | 152 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_sup.c | 73 |
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); |