diff options
author | Vadim Yanitskiy <axilirator@gmail.com> | 2018-06-17 21:09:28 +0700 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2018-07-30 21:28:01 +0200 |
commit | f2f83b07f36d9676e02f90320d69b3f63f55d8e8 (patch) | |
tree | af8155e492ba1cb0c9127432873a8047de9f21bd /src/libmsc | |
parent | 8a6ef55ec5838bdac3b5780bfc404c9b732d944f (diff) |
libmsc/gsm_09_11.c: implement network-initiated sessions
This change introduces a possibility to establish network-initiated
SS/USSD transactions with a subscriber in either IDLE, or DEDICATED
state. In the first case, a new transaction is established using
Paging procedure. If a subscriber already has an active connection,
a separate new transaction is established.
TTCN-3 test case: I073893c6e11be27e9e36f98f11c1491d0c173985
Change-Id: Ief14f8914ef013bd6efd7be842f81fbf053f02e2
Diffstat (limited to 'src/libmsc')
-rw-r--r-- | src/libmsc/gsm_09_11.c | 172 | ||||
-rw-r--r-- | src/libmsc/transaction.c | 2 |
2 files changed, 170 insertions, 4 deletions
diff --git a/src/libmsc/gsm_09_11.c b/src/libmsc/gsm_09_11.c index 219325ed1..9423ec732 100644 --- a/src/libmsc/gsm_09_11.c +++ b/src/libmsc/gsm_09_11.c @@ -30,6 +30,7 @@ #include <errno.h> #include <stdbool.h> +#include <osmocom/core/linuxlist.h> #include <osmocom/core/utils.h> #include <osmocom/core/msgb.h> #include <osmocom/gsm/tlv.h> @@ -195,6 +196,163 @@ error: return rc; } +/* Call-back from paging the B-end of the connection */ +static int handle_paging_event(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *_conn, void *_transt) +{ + struct gsm_subscriber_connection *conn = _conn; + enum gsm_paging_event paging_event = event; + struct gsm_trans *transt = _transt; + struct gsm48_hdr *gh; + struct msgb *ss_msg; + + OSMO_ASSERT(!transt->conn); + OSMO_ASSERT(transt->ss.msg); + + switch (paging_event) { + case GSM_PAGING_SUCCEEDED: + DEBUGP(DMM, "Paging subscr %s succeeded!\n", + vlr_subscr_msisdn_or_name(transt->vsub)); + + /* Assign connection */ + transt->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_NC_SS); + transt->paging_request = NULL; + + /* Send stored message */ + ss_msg = transt->ss.msg; + OSMO_ASSERT(ss_msg); + + gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS; + gh->proto_discr |= transt->transaction_id << 4; + gh->msg_type = GSM0480_MTYPE_REGISTER; + + /* Sent to the MS, give ownership of ss_msg */ + msc_tx_dtap(transt->conn, ss_msg); + transt->ss.msg = NULL; + break; + case GSM_PAGING_EXPIRED: + case GSM_PAGING_BUSY: + DEBUGP(DMM, "Paging subscr %s %s!\n", + vlr_subscr_msisdn_or_name(transt->vsub), + paging_event == GSM_PAGING_EXPIRED ? "expired" : "busy"); + + /* TODO: inform HLR about this failure */ + + msgb_free(transt->ss.msg); + transt->ss.msg = NULL; + + transt->callref = 0; + transt->paging_request = NULL; + trans_free(transt); + break; + } + + return 0; +} + +static struct gsm_trans *establish_nc_ss_trans(struct gsm_network *net, + struct vlr_subscr *vsub, struct osmo_gsup_message *gsup_msg) +{ + struct gsm_subscriber_connection *conn; + struct gsm_trans *trans, *transt; + int tid; + + if (gsup_msg->session_state != OSMO_GSUP_SESSION_STATE_BEGIN) { + LOGP(DMM, LOGL_ERROR, "Received non-BEGIN message " + "for non-existing transaction\n"); + return NULL; + } + + if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) { + LOGP(DMM, LOGL_ERROR, "Missing mandatory Facility IE\n"); + return NULL; + } + + /* If subscriber is not "attached" */ + if (!vsub->lac) { + LOGP(DMM, LOGL_ERROR, "Network-originated session " + "rejected - subscriber is not attached\n"); + return NULL; + } + + DEBUGP(DMM, "Establishing network-originated session\n"); + + /* Allocate a new transaction */ + trans = trans_alloc(net, vsub, GSM48_PDISC_NC_SS, + 0xff, gsup_msg->session_id); + if (!trans) { + DEBUGP(DMM, " -> No memory for trans\n"); + return NULL; + } + + /* Assign transaction ID */ + tid = trans_assign_trans_id(trans->net, + trans->vsub, GSM48_PDISC_NC_SS, 0); + if (tid < 0) { + LOGP(DMM, LOGL_ERROR, "No free transaction ID\n"); + /* TODO: inform HLR about this */ + /* TODO: release connection with subscriber */ + trans->callref = 0; + trans_free(trans); + return NULL; + } + trans->transaction_id = tid; + + /* Attempt to find connection */ + conn = connection_for_subscr(vsub); + if (conn) { + /* Assign connection */ + trans->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_NC_SS); + trans->dlci = 0x00; /* SAPI=0, not SACCH */ + return trans; + } + + DEBUGP(DMM, "Triggering Paging Request\n"); + + /* Find transaction with this subscriber already paging */ + llist_for_each_entry(transt, &net->trans_list, entry) { + /* Transaction of our conn? */ + if (transt == trans || transt->vsub != vsub) + continue; + + LOGP(DMM, LOGL_ERROR, "Paging already started, " + "rejecting message...\n"); + trans_free(trans); + return NULL; + } + + /* Trigger Paging Request */ + trans->paging_request = subscr_request_conn(vsub, + &handle_paging_event, trans, "GSM 09.11 SS/USSD"); + if (!trans->paging_request) { + LOGP(DMM, LOGL_ERROR, "Failed to allocate paging token\n"); + trans_free(trans); + return NULL; + } + + /* Store the Facility IE to be sent */ + OSMO_ASSERT(trans->ss.msg == NULL); + trans->ss.msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD"); + msgb_tlv_put(trans->ss.msg, GSM0480_IE_FACILITY, + gsup_msg->ss_info_len, gsup_msg->ss_info); + + return NULL; +} + +/* NC SS specific transaction release. + * Gets called by trans_free, DO NOT CALL YOURSELF! */ +void _gsm911_nc_ss_trans_free(struct gsm_trans *trans) +{ + /** + * TODO: if transaction wasn't properly terminated, + * we need to do it here by releasing the subscriber + * connection and sending notification via GSUP... + */ + if (trans->ss.msg != NULL) + msgb_free(trans->ss.msg); +} + int gsm0911_gsup_handler(struct vlr_subscr *vsub, struct osmo_gsup_message *gsup_msg) { @@ -225,10 +383,16 @@ int gsm0911_gsup_handler(struct vlr_subscr *vsub, /* Attempt to find DTAP-transaction */ trans = trans_find_by_callref(net, gsup_msg->session_id); if (!trans) { - /* FIXME: network-originated sessions are not supported yet */ - LOGP(DMM, LOGL_ERROR, "Network-originated sessions " - "are not supported, dropping request...\n"); - return -ENOTSUP; + /* Attempt to establish a new transaction */ + trans = establish_nc_ss_trans(net, vsub, gsup_msg); + if (!trans) { + /* FIXME: send ERROR back to the HLR */ + return -EINVAL; + } + + /* Wait for Paging Response */ + if (trans->paging_request) + return 0; } /* Allocate and prepare a new MT message */ diff --git a/src/libmsc/transaction.c b/src/libmsc/transaction.c index f2c80d744..4c351d3b8 100644 --- a/src/libmsc/transaction.c +++ b/src/libmsc/transaction.c @@ -31,6 +31,7 @@ void *tall_trans_ctx; void _gsm48_cc_trans_free(struct gsm_trans *trans); +void _gsm911_nc_ss_trans_free(struct gsm_trans *trans); /*! Find a transaction in connection for given protocol + transaction ID * \param[in] conn Connection in whihc we want to find transaction @@ -129,6 +130,7 @@ void trans_free(struct gsm_trans *trans) conn_usage_token = MSC_CONN_USE_TRANS_SMS; break; case GSM48_PDISC_NC_SS: + _gsm911_nc_ss_trans_free(trans); conn_usage_token = MSC_CONN_USE_TRANS_NC_SS; break; } |