summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Klyuchnikov <kluchnikovi@gmail.com>2018-05-21 19:25:30 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2018-05-21 19:39:33 +0300
commitfd87ede9e9164de79c04e2fdb3a7e4a2c41cc4a4 (patch)
tree637245e9f2b5a2422cffdd058e553ae8a4f20e58
parentc2891e441cfdbbc23e302f42a986014d052b7975 (diff)
sms charging: Implement SMS online ECUR charging based on 3GPP TS 32.274
Event Charging with Unit Reservation (ECUR) principle is used for SMS online charging in osmo-nitb. Osmo-nitb generates Reserve Units information which is transferred to OCS. For this purpose, osmo-nitb utilizes the Reserve Units procedure that is specified in TS 32.274 and TS 32.299. The Reserve Units procedure employs the Reserve Units Request and Reserve Units Response messages. Change-Id: I12b681f65cdcdb281da04b49a63ceb140be7e643
-rw-r--r--openbsc/include/openbsc/gsm_04_11.h5
-rw-r--r--openbsc/include/openbsc/gsm_sup.h43
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c115
-rw-r--r--openbsc/src/libmsc/gsm_sup.c247
4 files changed, 378 insertions, 32 deletions
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 6408b7b5c..1d5acb427 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -42,4 +42,9 @@ 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);
+
+int gsm340_rx_tpdu(struct gsm_trans *trans);
+
+int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref, uint8_t cause);
+
#endif
diff --git a/openbsc/include/openbsc/gsm_sup.h b/openbsc/include/openbsc/gsm_sup.h
index 26017365d..2b2315a4d 100644
--- a/openbsc/include/openbsc/gsm_sup.h
+++ b/openbsc/include/openbsc/gsm_sup.h
@@ -11,6 +11,44 @@
(subscr) ? (subscr)->imsi : "---", \
## args)
+#define LOGGSESSIONP(level, session_id, fmt, args...) \
+ LOGP(DSUP, level, "SESSION(%d:%d) " fmt, \
+ session_id.h, session_id.l, \
+ ## args)
+
+/* TODO move libosmocore */
+enum osmo_gsup_charging_message_type {
+ OSMO_GSUP_MSGT_RESERVE_UNITS_REQUEST = 0b00100000,
+ OSMO_GSUP_MSGT_RESERVE_UNITS_RESPONSE = 0b00100010,
+};
+enum osmo_gsup_charging_request_type {
+ OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL = 0b00000001,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_UPDATE = 0b00000010,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_TERMINATION = 0b00000011,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_EVENT = 0b00000100,
+};
+enum osmo_charging_service_type {
+ OSMO_CHARGING_SERVICE_TYPE_SMS = 0b00000001,
+};
+
+enum osmo_charging_result_code {
+ OSMO_CHARGING_RESULT_CODE_SUCCESS = 2001,
+ OSMO_CHARGING_RESULT_CODE_CREDIT_LIMIT_REACHED = 4012,
+};
+
+struct osmo_gsup_reserve_units_response {
+ /* Message type: [Pres: M] [Format: V] [Length: 1] */
+ uint8_t message_type;
+ /* Session id: [Pres: M] [Format: V] [Length: 8] */
+ struct charging_session_id session_id;
+ /* Request type: [Pres: M] [Format: V] [Length: 1] */
+ uint8_t request_type;
+ /* Result code: [Pres: M] [Format: V] [Length: 4] */
+ uint32_t result_code;
+ /* Service units: [Pres: O] [Format: V] [Length: 4] */
+ uint32_t service_units;
+};
+
/* Callback for both HLR/auth and USSD SUP sockets */
int sup_read_cb(struct gsup_client *sup_client, struct msgb *msg);
@@ -26,4 +64,9 @@ int subscr_tx_sms_message(struct gsm_subscriber *subscr,
void init_charging_session_id(struct gsm_network *network);
struct charging_session_id get_charging_session_id(struct gsm_network *network);
+int tx_reserve_units_request(enum osmo_gsup_charging_message_type msg_type,
+ enum osmo_gsup_charging_request_type request_type,
+ enum osmo_charging_service_type service_type,
+ struct gsm_trans *trans, uint32_t service_units);
+
#endif /* _GSM_SUP_H */
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 25be3b456..b8523411d 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -393,12 +393,11 @@ static int gsm340_tpdu_dst_addr(struct msgb *msg, struct gsm_sms_addr* dst_addr)
return 0;
}
-/* 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)
+/* Decode an incoming TPDU (called from RP-DATA)
+ * return value > 0: RP CAUSE for ERROR; 0 = success */
+static int gsm340_decode_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg, struct gsm_sms *gsms)
{
uint8_t *smsp = msgb_sms(msg);
- struct gsm_sms *gsms;
unsigned int sms_alphabet;
uint8_t sms_mti, sms_vpf;
uint8_t *sms_vp;
@@ -406,12 +405,6 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
- rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]);
-
- gsms = sms_alloc();
- if (!gsms)
- return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
-
/* invert those fields where 0 means active/present */
sms_mti = *smsp & 0x03;
sms_vpf = (*smsp & 0x18) >> 3;
@@ -431,12 +424,10 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
da_len_bytes = 2 + *smsp/2 + *smsp%2;
if (da_len_bytes > 12) {
LOGP(DLSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
- rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
- goto out;
+ return GSM411_RP_CAUSE_SEMANT_INC_MSG;
} else if (da_len_bytes < 4) {
LOGP(DLSMS, LOGL_ERROR, "Destination Address < 4 bytes ?!?\n");
- rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
- goto out;
+ return GSM411_RP_CAUSE_SEMANT_INC_MSG;
}
memset(address_lv, 0, sizeof(address_lv));
memcpy(address_lv, smsp, da_len_bytes);
@@ -455,8 +446,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
sms_alphabet = gsm338_get_sms_alphabet(gsms->data_coding_scheme);
if (sms_alphabet == 0xffffffff) {
- rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
- goto out;
+ return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
switch (sms_vpf) {
@@ -477,8 +467,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
default:
LOGP(DLSMS, LOGL_NOTICE,
"SMS Validity period not implemented: 0x%02x\n", sms_vpf);
- rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
- goto out;
+ return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
gsms->user_data_len = *smsp++;
if (gsms->user_data_len) {
@@ -510,13 +499,6 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
- /* FIXME: This looks very wrong */
- send_signal(0, NULL, gsms, 0);
-
- rc = sms_route_mt_sms(conn, msg, gsms, sms_mti);
-out:
- sms_free(gsms);
-
return rc;
}
@@ -547,7 +529,7 @@ 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,
+int gsm411_send_rp_error(struct gsm_trans *trans,
uint8_t msg_ref, uint8_t cause)
{
struct msgb *msg = gsm411_msgb_alloc();
@@ -561,6 +543,46 @@ static int gsm411_send_rp_error(struct gsm_trans *trans,
GSM411_MT_RP_ERROR_MT, msg_ref, GSM411_SM_RL_REPORT_REQ);
}
+int gsm340_rx_tpdu(struct gsm_trans *trans)
+{
+ int rc, rc1;
+ uint32_t used_service_units = 0;
+ struct gsm_sms *gsms = trans->sms.sms;
+
+ /* FIXME: This looks very wrong */
+ send_signal(0, NULL, gsms, 0);
+
+ rc = sms_route_mt_sms(trans->conn, NULL, gsms, GSM340_SMS_SUBMIT_MS2SC);
+
+ // SMS Charging
+ if (trans->net->sms_ctf) {
+ if (rc == 0) {
+ used_service_units = 1;
+ }
+ rc1 = tx_reserve_units_request(OSMO_GSUP_MSGT_RESERVE_UNITS_REQUEST,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_TERMINATION,
+ OSMO_CHARGING_SERVICE_TYPE_SMS,
+ trans, used_service_units);
+ if (rc1 < 0) {
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+ return gsm411_send_rp_error(trans, trans->msg_ref,
+ GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER);
+ }
+ }
+
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+
+ if (rc == 0)
+ return gsm411_send_rp_ack(trans, trans->msg_ref);
+ else if (rc > 0)
+ return gsm411_send_rp_error(trans, trans->msg_ref, rc);
+ else
+ return rc;
+}
+
+
/* Receive a 04.11 TPDU inside RP-DATA / user data */
static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph,
@@ -568,6 +590,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)
{
+ struct gsm_sms *gsms;
int rc = 0;
if (src_len && src)
@@ -602,13 +625,41 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
return subscr_tx_sms_message(trans->subscr, rph);
}
- 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
+ rate_ctr_inc(&trans->conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]);
+
+ gsms = sms_alloc();
+ if (!gsms) {
+ gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER);
+ return -ENOMEM;
+ }
+
+ /* Decode an incoming TPDU (called from RP-DATA) */
+ /* return value > 0: RP CAUSE for ERROR; 0 = success */
+ rc = gsm340_decode_tpdu(trans->conn, msg, gsms);
+ if (rc > 0) {
+ sms_free(gsms);
+ gsm411_send_rp_error(trans, rph->msg_ref, rc);
+ return -EIO;
+ }
+ trans->msg_ref = rph->msg_ref;
+ trans->sms.sms = gsms;
+
+ // SMS Charging: Initial Reserve Units Request
+ if (trans->net->sms_ctf) {
+ rc = tx_reserve_units_request(OSMO_GSUP_MSGT_RESERVE_UNITS_REQUEST,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL,
+ OSMO_CHARGING_SERVICE_TYPE_SMS, trans, 1);
+ if (rc < 0) {
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+ gsm411_send_rp_error(trans, rph->msg_ref,
+ GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER);
+ }
return rc;
+ }
+
+ return gsm340_rx_tpdu(trans);
}
/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
diff --git a/openbsc/src/libmsc/gsm_sup.c b/openbsc/src/libmsc/gsm_sup.c
index 21e42adf1..72841960a 100644
--- a/openbsc/src/libmsc/gsm_sup.c
+++ b/openbsc/src/libmsc/gsm_sup.c
@@ -33,6 +33,7 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/ussd.h>
#include <openbsc/gsm_04_11.h>
+#include <openbsc/transaction.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
#include <osmocom/gsm/gsm0411_utils.h>
@@ -264,6 +265,247 @@ struct charging_session_id get_charging_session_id(struct gsm_network *network)
return id;
}
+static void encode_sms_charging_info(struct msgb *msg, struct gsm_trans *trans)
+{
+ uint8_t bcd_buf[32];
+ size_t bcd_len;
+ struct gsm_sms *gsms = trans->sms.sms;
+
+ /* SMS: destination address (MSISDN): [Pres: M] [Format: TLV] [Length: 0-9] */
+ bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0, gsms->dst.addr);
+ msgb_tlv_put(msg, OSMO_GSUP_MSISDN_IE, bcd_len - 1, &bcd_buf[1]);
+
+ /* SMS: rp msg ref: [Pres: M] [Format: V] [Length: 1] */
+ msgb_put_u8(msg, trans->msg_ref);
+
+ /* SMS: tp msg ref: [Pres: M] [Format: V] [Length: 1] */
+ msgb_put_u8(msg, gsms->msg_ref);
+}
+
+int tx_reserve_units_request(enum osmo_gsup_charging_message_type msg_type,
+ enum osmo_gsup_charging_request_type request_type,
+ enum osmo_charging_service_type service_type,
+ struct gsm_trans *trans, uint32_t service_units)
+{
+ uint8_t bcd_buf[32];
+ size_t bcd_len;
+ struct msgb *msg = gsup_client_msgb_alloc();
+
+ if (!msg)
+ return -ENOMEM;
+ if (!trans->subscr->extension)
+ return -1;
+
+ if (request_type == OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL)
+ trans->session_id = get_charging_session_id(trans->net);
+
+ /* Message type: [Pres: M] [Format: V] [Length: 1] */
+ msgb_put_u8(msg, msg_type);
+
+ /* Session id: [Pres: M] [Format: V] [Length: 8] */
+ msgb_put_u32(msg, trans->session_id.h);
+ msgb_put_u32(msg, trans->session_id.l);
+
+ /* Request type: [Pres: M] [Format: V] [Length: 1] */
+ msgb_put_u8(msg, request_type);
+
+ /* Service type: [Pres: M] [Format: V] [Length: 1] */
+ msgb_put_u8(msg, service_type);
+
+ /* Subscriber Identifier (MSISDN): [Pres: M] [Format: TLV] [Length: 0-9] */
+ bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf),
+ 0, trans->subscr->extension);
+ msgb_tlv_put(msg, OSMO_GSUP_MSISDN_IE, bcd_len - 1, &bcd_buf[1]);
+
+ /* Service units [Pres: M] [Format: V] [Length: 4] */
+ msgb_put_u32(msg, service_units);
+
+ /* Encode Service Information */
+ switch (service_type) {
+ case OSMO_CHARGING_SERVICE_TYPE_SMS:
+ encode_sms_charging_info(msg, trans);
+ break;
+ default:
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ switch (request_type) {
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL:
+ LOGGSESSIONP(LOGL_NOTICE, trans->session_id,
+ "Tx: Reserve Units Request: type = INITIAL, service = %d,"
+ " subscriber_id = %s, requested_units = %d, desr_addr = %s,"
+ " rp_msg_ref = %d, tp_msg_ref = %d\n",
+ service_type, trans->subscr->extension, service_units,
+ trans->sms.sms->dst.addr, trans->msg_ref, trans->sms.sms->msg_ref);
+ break;
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_TERMINATION:
+ LOGGSESSIONP(LOGL_NOTICE, trans->session_id,
+ "Tx: Reserve Units Request: type = TERMINATION, service = %d,"
+ " subscriber_id = %s, used_units = %d, desr_addr = %s,"
+ " rp_msg_ref = %d, tp_msg_ref = %d\n",
+ service_type, trans->subscr->extension, service_units,
+ trans->sms.sms->dst.addr, trans->msg_ref, trans->sms.sms->msg_ref);
+ break;
+ default:
+ LOGGSESSIONP(LOGL_NOTICE, trans->session_id,
+ "Tx: Reserve Units Request with unsupported type = %d\n", request_type);
+ }
+
+ return gsup_client_send(trans->net->sms_ctf, msg);
+}
+
+static int osmo_gsup_reserve_units_response_decode(const uint8_t *const_data,
+ size_t data_len, struct osmo_gsup_reserve_units_response *response)
+{
+ int rc;
+ uint8_t *data = (uint8_t *)const_data;
+ uint8_t *value;
+
+ /* Message type: [Pres: M] [Format: V] [Length: 1] */
+ rc = osmo_shift_v_fixed(&data, &data_len, 1, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->message_type = osmo_decode_big_endian(value, 1);
+
+ /* Session id: [Pres: M] [Format: V] [Length: 8] */
+ rc = osmo_shift_v_fixed(&data, &data_len, 4, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->session_id.h = osmo_decode_big_endian(value, 4);
+ rc = osmo_shift_v_fixed(&data, &data_len, 4, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->session_id.l = osmo_decode_big_endian(value, 4);
+
+ /* Request type: [Pres: M] [Format: V] [Length: 1] */
+ rc = osmo_shift_v_fixed(&data, &data_len, 1, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->request_type = osmo_decode_big_endian(value, 1);
+
+ /* Result code: [Pres: M] [Format: V] [Length: 4] */
+ rc = osmo_shift_v_fixed(&data, &data_len, 4, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->result_code = osmo_decode_big_endian(value, 4);
+
+ if (response->request_type == OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL) {
+ /* Service units: [Pres: O] [Format: V] [Length: 4] */
+ rc = osmo_shift_v_fixed(&data, &data_len, 4, &value);
+ if (rc < 0)
+ return -GMM_CAUSE_INV_MAND_INFO;
+ response->service_units = osmo_decode_big_endian(value, 4);
+ }
+
+ return 0;
+}
+
+static int rx_sms_reserve_units_response_init(struct gsm_network *net,
+ struct osmo_gsup_reserve_units_response *response)
+{
+ struct gsm_trans *trans;
+ struct gsm_sms *gsms;
+
+ trans = trans_find_by_session_id(net, GSM48_PDISC_SMS, response->session_id);
+ if (!trans) {
+ LOGGSESSIONP(LOGL_ERROR, response->session_id,
+ "Can't find transaction for Session Id from Reserve Units Response Initial\n");
+ return -EINVAL;
+ }
+
+ gsms = trans->sms.sms;
+
+ switch (response->result_code) {
+ case OSMO_CHARGING_RESULT_CODE_SUCCESS:
+ if (response->service_units == 1) {
+ return gsm340_rx_tpdu(trans);
+ } else {
+ LOGGSESSIONP(LOGL_ERROR, response->session_id,
+ "Received Service Units = %d in Reserve Units Response Initial\n",
+ response->result_code);
+ tx_reserve_units_request(OSMO_GSUP_MSGT_RESERVE_UNITS_REQUEST,
+ OSMO_GSUP_MSGT_REQUEST_TYPE_TERMINATION,
+ OSMO_CHARGING_SERVICE_TYPE_SMS,
+ trans, 0);
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+ return gsm411_send_rp_error(trans, trans->msg_ref,
+ GSM411_RP_CAUSE_MO_CALL_BARRED);
+ }
+ case OSMO_CHARGING_RESULT_CODE_CREDIT_LIMIT_REACHED:
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+ return gsm411_send_rp_error(trans, trans->msg_ref,
+ GSM411_RP_CAUSE_MO_CALL_BARRED);
+ default:
+ LOGGSESSIONP(LOGL_ERROR, response->session_id,
+ "Received Result Code %d in Reserve Units Response Initial\n",
+ response->result_code);
+ trans->sms.sms = NULL;
+ sms_free(gsms);
+ return gsm411_send_rp_error(trans, trans->msg_ref,
+ GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER);
+ }
+}
+
+static int rx_sms_reserve_units_response_term(struct gsm_network *net,
+ struct osmo_gsup_reserve_units_response *response)
+{
+ switch (response->result_code) {
+ case OSMO_CHARGING_RESULT_CODE_SUCCESS:
+ break;
+ default:
+ LOGGSESSIONP(LOGL_ERROR, response->session_id,
+ "Received Result Code %d in Reserve Units Response Termination\n",
+ response->result_code);
+ }
+ return 0;
+}
+
+static int rx_sms_reserve_units_response(struct gsm_network *net,
+ struct osmo_gsup_reserve_units_response *response)
+{
+ switch (response->request_type) {
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_INITIAL:
+ LOGGSESSIONP(LOGL_NOTICE, response->session_id,
+ "Rx: Reserve Units Response: type = INITIAL, result_code = %d, granted_units = %d\n",
+ response->result_code, response->service_units);
+ return rx_sms_reserve_units_response_init(net, response);
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_TERMINATION:
+ LOGGSESSIONP(LOGL_NOTICE, response->session_id,
+ "Rx: Reserve Units Response: type = TERMINATION, result_code = %d\n",
+ response->result_code);
+ return rx_sms_reserve_units_response_term(net, response);
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_UPDATE:
+ case OSMO_GSUP_MSGT_REQUEST_TYPE_EVENT:
+ default:
+ LOGGSESSIONP(LOGL_NOTICE, response->session_id,
+ "Received unsupported Request Type %d in Reserve Units Response message\n",
+ response->request_type);
+ return -EINVAL;
+ }
+}
+
+static int rx_reserve_units_response(struct gsup_client *sup_client,
+ const uint8_t* const_data, size_t data_len)
+{
+ int rc;
+ struct gsm_network *net = sup_client->net;
+ struct osmo_gsup_reserve_units_response response = {0};
+
+ rc = osmo_gsup_reserve_units_response_decode(const_data, data_len, &response);
+ if (rc < 0) {
+ LOGGSESSIONP(LOGL_ERROR, response.session_id,
+ "decoding Reserve Units Response message fails with error '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, -rc), -rc);
+ return rc;
+ }
+
+ return rx_sms_reserve_units_response(net, &response);
+}
+
+
static int subscr_tx_sup_message(struct gsup_client *sup_client,
struct gsm_subscriber *subscr,
struct osmo_gsup_message *gsup_msg)
@@ -551,6 +793,11 @@ static int subscr_rx_sup_message(struct gsup_client *sup_client, struct msgb *ms
if (*data == OSMO_GSUP_MSGT_SMS) {
return rx_sms_message(sup_client, data, data_len);
}
+
+ if (*data == OSMO_GSUP_MSGT_RESERVE_UNITS_RESPONSE) {
+ return rx_reserve_units_response(sup_client, data, data_len);
+ }
+
rc = osmo_gsup_decode(data, data_len, &gsup_msg);
if (rc < 0) {
LOGP(DSUP, LOGL_ERROR,