blob: ab40f02bf13a413aebc0de8a3e9529a893db76f8 [file] [log] [blame]
Harald Welte6eafe912009-10-16 08:32:58 +02001/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
2 * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2009 by Mike Haben <michael.haben@btinternet.com>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +07004 * (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com>
Harald Welte6eafe912009-10-16 08:32:58 +02005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte6eafe912009-10-16 08:32:58 +020011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte6eafe912009-10-16 08:32:58 +020017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte6eafe912009-10-16 08:32:58 +020020 *
21 */
22
Vadim Yanitskiy5b860fa2018-06-12 05:24:52 +070023/**
24 * MSC-specific handling of call independent Supplementary
25 * Services messages (NC_SS) according to GSM TS 09.11
26 * "Signalling interworking for supplementary services".
27 */
Harald Welte6eafe912009-10-16 08:32:58 +020028
29#include <stdio.h>
Harald Welte6eafe912009-10-16 08:32:58 +020030#include <errno.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070031#include <stdbool.h>
32
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +070033#include <osmocom/core/linuxlist.h>
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +070034#include <osmocom/core/rate_ctr.h>
Alexander Couzensefa7b972019-04-27 23:45:37 +020035#include <osmocom/core/stat_item.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070036#include <osmocom/core/utils.h>
37#include <osmocom/core/msgb.h>
Vadim Yanitskiy0622ef52018-08-03 04:39:04 +070038
39#include <osmocom/gsm/protocol/gsm_04_80.h>
40#include <osmocom/gsm/gsm0480.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070041#include <osmocom/gsm/tlv.h>
Harald Welte6eafe912009-10-16 08:32:58 +020042
Neels Hofmeyr90843962017-09-04 15:04:35 +020043#include <osmocom/msc/gsm_04_80.h>
44#include <osmocom/msc/gsm_subscriber.h>
45#include <osmocom/msc/debug.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020046#include <osmocom/msc/vlr.h>
Max43b01b02017-09-15 11:22:30 +020047#include <osmocom/msc/gsm_04_08.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070048#include <osmocom/msc/transaction.h>
Harald Welte1ea6baf2018-07-31 19:40:52 +020049#include <osmocom/gsupclient/gsup_client.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010050#include <osmocom/msc/msc_a.h>
51#include <osmocom/msc/msub.h>
52#include <osmocom/msc/paging.h>
53#include <osmocom/msc/gsup_client_mux.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070054
55/* FIXME: choose a proper range */
56static uint32_t new_callref = 0x20000001;
Harald Welte6eafe912009-10-16 08:32:58 +020057
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070058static void ncss_session_timeout_handler(void *_trans)
59{
60 struct gsm_trans *trans = (struct gsm_trans *) _trans;
Vadim Yanitskiy944d6a22019-06-17 21:57:08 +070061 struct osmo_gsup_message gsup_msg;
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070062
63 /* The timeout might be disabled from the VTY */
64 if (trans->net->ncss_guard_timeout == 0)
65 return;
66
Neels Hofmeyrff7074a2019-02-28 05:50:06 +010067 LOG_TRANS(trans, LOGL_NOTICE, "SS/USSD session timeout, releasing\n");
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070068
69 /* Indicate connection release to subscriber (if active) */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010070 if (trans->msc_a != NULL) {
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070071 /* This pair of cause location and value is used by commercial networks */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010072 msc_send_ussd_release_complete_cause(trans->msc_a, trans->transaction_id,
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070073 GSM48_CAUSE_LOC_PUN_S_LU, GSM48_CC_CAUSE_NORMAL_UNSPEC);
74 }
75
76 /* Terminate GSUP session with EUSE */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010077 gsup_msg = (struct osmo_gsup_message){
78 .message_type = OSMO_GSUP_MSGT_PROC_SS_ERROR,
79
80 .session_state = OSMO_GSUP_SESSION_STATE_END,
81 .session_id = trans->callref,
82 .cause = GMM_CAUSE_NET_FAIL,
83
84 .message_class = OSMO_GSUP_MESSAGE_CLASS_USSD,
85 };
86
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070087 OSMO_STRLCPY_ARRAY(gsup_msg.imsi, trans->vsub->imsi);
88
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010089 gsup_client_mux_tx(trans->net->gcm, &gsup_msg);
Vadim Yanitskiy64623e12018-11-28 23:05:51 +070090
91 /* Finally, release this transaction */
92 trans_free(trans);
93}
94
Vadim Yanitskiy5b860fa2018-06-12 05:24:52 +070095/* Entry point for call independent MO SS messages */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010096int gsm0911_rcv_nc_ss(struct msc_a *msc_a, struct msgb *msg)
Harald Welte6eafe912009-10-16 08:32:58 +020097{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010098 struct gsm_network *net;
99 struct vlr_subscr *vsub;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700100 struct gsm48_hdr *gh = msgb_l3(msg);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700101 struct osmo_gsup_message gsup_msg;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700102 struct gsm_trans *trans;
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700103 uint16_t facility_ie_len;
104 uint8_t *facility_ie;
Max4a5cfa52019-01-10 17:41:05 +0100105 uint8_t tid;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700106 uint8_t msg_type;
107 int rc;
Harald Welte6eafe912009-10-16 08:32:58 +0200108
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100109 net = msc_a_net(msc_a);
110 OSMO_ASSERT(net);
111
112 vsub = msc_a_vsub(msc_a);
113 if (!vsub) {
114 LOG_MSC_A(msc_a, LOGL_ERROR, "No vlr_subscr set for this conn\n");
115 return -EINVAL;
116 }
117
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700118 msg_type = gsm48_hdr_msg_type(gh);
119 tid = gsm48_hdr_trans_id_flip_ti(gh);
Harald Welte2483f1b2016-06-19 18:06:02 +0200120
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700121 /* Associate logging messages with this subscriber */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100122 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700123
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700124 /* Reuse existing transaction, or create a new one */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100125 trans = trans_find_by_id(msc_a, TRANS_USSD, tid);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700126 if (!trans) {
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700127 /* Count MS-initiated attempts to establish a NC SS/USSD session */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200128 rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_NC_SS_MO_REQUESTS));
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700129
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700130 /**
131 * According to GSM TS 04.80, section 2.4.2 "Register
132 * (mobile station to network direction)", the REGISTER
133 * message is sent by the mobile station to the network
134 * to assign a new transaction identifier for call independent
135 * supplementary service control and to request or acknowledge
136 * a supplementary service.
137 */
138 if (msg_type != GSM0480_MTYPE_REGISTER) {
Vadim Yanitskiy66322512019-06-17 22:12:54 +0700139 LOGP(DSS, LOGL_ERROR, "Rx %s message for non-existing transaction (tid-%u)\n",
140 gsm48_pdisc_msgtype_name(GSM48_PDISC_NC_SS, msg_type),
141 gsm48_hdr_trans_id(gh));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100142 gsm48_tx_simple(msc_a,
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +0700143 GSM48_PDISC_NC_SS | (tid << 4),
144 GSM0480_MTYPE_RELEASE_COMPLETE);
Andreas Eversberg5fb4a9e2024-09-27 11:22:48 +0200145 /* Decrement use counter that has been incremented by CM Service Request (SS).
146 * If there is no other service request, the BSS connection will be released. */
147 msc_a_put(msc_a, MSC_A_USE_CM_SERVICE_SS);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700148 return -EINVAL;
149 }
150
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100151 trans = trans_alloc(net, vsub, TRANS_USSD, tid, new_callref++);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700152 if (!trans) {
Vadim Yanitskiy66322512019-06-17 22:12:54 +0700153 LOGP(DSS, LOGL_ERROR, " -> No memory for trans\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100154 gsm48_tx_simple(msc_a,
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +0700155 GSM48_PDISC_NC_SS | (tid << 4),
156 GSM0480_MTYPE_RELEASE_COMPLETE);
Andreas Eversberg5fb4a9e2024-09-27 11:22:48 +0200157 /* Decrement use counter that has been incremented by CM Service Request (SS).
158 * If there is no other service request, the BSS connection will be released. */
159 msc_a_put(msc_a, MSC_A_USE_CM_SERVICE_SS);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700160 return -ENOMEM;
161 }
162
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700163 /* Init inactivity timer */
164 osmo_timer_setup(&trans->ss.timer_guard,
165 ncss_session_timeout_handler, trans);
166
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700167 /* Count active NC SS/USSD sessions */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200168 osmo_stat_item_inc(osmo_stat_item_group_get_item(net->statg, MSC_STAT_ACTIVE_NC_SS), 1);
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700169
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700170 trans->dlci = OMSC_LINKID_CB(msg);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100171 trans->msc_a = msc_a;
172 msc_a_get(msc_a, MSC_A_USE_NC_SS);
173
174 osmo_fsm_inst_dispatch(msc_a->c.fi, MSC_A_EV_TRANSACTION_ACCEPTED, trans);
175
176 /* An earlier CM Service Request for this SS message now has concluded */
177 if (!osmo_use_count_by(&msc_a->use_count, MSC_A_USE_CM_SERVICE_SS))
178 LOG_MSC_A(msc_a, LOGL_ERROR,
179 "Creating new MO SS transaction without prior CM Service Request\n");
180 else
181 msc_a_put(msc_a, MSC_A_USE_CM_SERVICE_SS);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700182 }
Harald Welte2483f1b2016-06-19 18:06:02 +0200183
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100184 LOG_TRANS(trans, LOGL_DEBUG, "Received SS/USSD msg %s\n",
185 gsm48_pdisc_msgtype_name(GSM48_PDISC_NC_SS, msg_type));
186
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700187 /* (Re)schedule the inactivity timer */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100188 if (net->ncss_guard_timeout > 0) {
189 osmo_timer_schedule(&trans->ss.timer_guard, net->ncss_guard_timeout, 0);
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700190 }
191
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700192 /* Attempt to extract Facility IE */
193 rc = gsm0480_extract_ie_by_tag(gh, msgb_l3len(msg),
194 &facility_ie, &facility_ie_len, GSM0480_IE_FACILITY);
195 if (rc) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100196 LOG_TRANS(trans, LOGL_ERROR, "GSM 04.80 message parsing error, couldn't extract Facility IE\n");
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700197 goto error;
Tobias Engelea730322013-12-28 17:03:14 +0100198 }
199
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700200 /* Facility IE is optional for RELEASE COMPLETE */
201 if (msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
202 if (!facility_ie || facility_ie_len < 2) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100203 LOG_TRANS(trans, LOGL_ERROR, "GSM 04.80 message parsing error,"
204 " missing mandatory Facility IE\n");
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700205 rc = -EINVAL;
206 goto error;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200207 }
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700208 }
209
210 /* Compose a mew GSUP message */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100211 gsup_msg = (struct osmo_gsup_message){
212 .message_type = OSMO_GSUP_MSGT_PROC_SS_REQUEST,
213 .session_id = trans->callref,
214 .message_class = OSMO_GSUP_MESSAGE_CLASS_USSD,
215 };
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700216
217 /**
218 * Perform A-interface to GSUP-interface mapping,
219 * according to GSM TS 09.11, table 4.2.
220 */
221 switch (msg_type) {
222 case GSM0480_MTYPE_REGISTER:
223 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_BEGIN;
224 break;
225 case GSM0480_MTYPE_FACILITY:
226 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
227 break;
228 case GSM0480_MTYPE_RELEASE_COMPLETE:
229 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_END;
230 break;
231 }
232
233 /* Fill in the (optional) message payload */
234 if (facility_ie) {
235 gsup_msg.ss_info_len = facility_ie_len;
236 gsup_msg.ss_info = facility_ie;
237 }
238
239 /* Fill in subscriber's IMSI */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100240 OSMO_STRLCPY_ARRAY(gsup_msg.imsi, vsub->imsi);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700241
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100242 rc = gsup_client_mux_tx(trans->net->gcm, &gsup_msg);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700243
Vadim Yanitskiyfcc24ed2018-06-21 17:55:56 +0700244 /* Should we release connection? Or wait for response? */
245 if (msg_type == GSM0480_MTYPE_RELEASE_COMPLETE)
246 trans_free(trans);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700247
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700248 /* Count established MS-initiated NC SS/USSD sessions */
249 if (msg_type == GSM0480_MTYPE_REGISTER)
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200250 rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_NC_SS_MO_ESTABLISHED));
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700251
Vadim Yanitskiyb3bdc762019-06-17 22:23:09 +0700252 return rc;
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700253
254error:
255 /* Abort transaction on DTAP-interface */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100256 msc_send_ussd_reject(msc_a, tid, -1,
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700257 GSM_0480_PROBLEM_CODE_TAG_GENERAL,
258 GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
259 if (trans)
260 trans_free(trans);
261
262 /* TODO: abort transaction on GSUP interface if any */
263 return rc;
264}
265
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700266/* Call-back from paging the B-end of the connection */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100267static void ss_paging_cb(struct msc_a *msc_a, struct gsm_trans *trans)
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700268{
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700269 struct gsm48_hdr *gh;
270 struct msgb *ss_msg;
271
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100272 if (trans->msc_a) {
273 LOG_MSC_A_CAT(msc_a, DPAG, LOGL_ERROR,
Martin Hauke3f07dac2019-11-14 17:49:08 +0100274 "Handle paging error: transaction already associated with subscriber,"
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100275 " apparently it was already handled. Skip.\n");
276 return;
277 }
278 OSMO_ASSERT(trans->ss.msg);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700279
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100280 if (msc_a) {
281 struct gsm_network *net = msc_a_net(msc_a);
Neels Hofmeyr979b0572019-05-09 15:24:49 +0200282 LOG_MSC_A_CAT(msc_a, DSS, LOGL_DEBUG, "Paging succeeded\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700283
284 /* Assign connection */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100285 msc_a_get(msc_a, MSC_A_USE_NC_SS);
286 trans->msc_a = msc_a;
287 trans->paging_request = NULL;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700288
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700289 /* (Re)schedule the inactivity timer */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100290 if (net->ncss_guard_timeout > 0) {
291 osmo_timer_schedule(&trans->ss.timer_guard, net->ncss_guard_timeout, 0);
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700292 }
293
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700294 /* Send stored message */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100295 ss_msg = trans->ss.msg;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700296 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
297 gh->proto_discr = GSM48_PDISC_NC_SS;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100298 gh->proto_discr |= trans->transaction_id << 4;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700299 gh->msg_type = GSM0480_MTYPE_REGISTER;
300
301 /* Sent to the MS, give ownership of ss_msg */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100302 msc_a_tx_dtap_to_i(msc_a, ss_msg);
303 trans->ss.msg = NULL;
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700304
305 /* Count established network-initiated NC SS/USSD sessions */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200306 rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_NC_SS_MT_ESTABLISHED));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100307 } else {
Vadim Yanitskiy74808522019-06-16 02:35:28 +0700308 struct osmo_gsup_message gsup_msg;
309
Neels Hofmeyr979b0572019-05-09 15:24:49 +0200310 LOG_MSC_A_CAT(msc_a, DSS, LOGL_DEBUG, "Paging expired\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700311
Vadim Yanitskiy74808522019-06-16 02:35:28 +0700312 gsup_msg = (struct osmo_gsup_message){
313 .message_class = OSMO_GSUP_MESSAGE_CLASS_USSD,
314 .message_type = OSMO_GSUP_MSGT_PROC_SS_ERROR,
315
316 .session_state = OSMO_GSUP_SESSION_STATE_END,
317 .session_id = trans->callref,
318 /* FIXME: we need message class specific cause values */
319 .cause = GMM_CAUSE_IMPL_DETACHED,
320 };
321
322 /* Fill in subscriber's IMSI */
323 OSMO_STRLCPY_ARRAY(gsup_msg.imsi, trans->vsub->imsi);
324
325 /* Inform HLR/EUSE about the failure */
326 gsup_client_mux_tx(trans->net->gcm, &gsup_msg);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700327
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100328 msgb_free(trans->ss.msg);
329 trans->ss.msg = NULL;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700330
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100331 trans->callref = 0;
332 trans->paging_request = NULL;
333 trans_free(trans);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700334 }
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700335}
336
337static struct gsm_trans *establish_nc_ss_trans(struct gsm_network *net,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100338 struct vlr_subscr *vsub, const struct osmo_gsup_message *gsup_msg)
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700339{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100340 struct msc_a *msc_a;
Vadim Yanitskiy95b040c2019-06-15 16:56:20 +0700341 struct gsm_trans *trans;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700342 int tid;
343
344 if (gsup_msg->session_state != OSMO_GSUP_SESSION_STATE_BEGIN) {
Vadim Yanitskiy10c3ce52019-06-15 15:52:23 +0700345 LOGP(DSS, LOGL_ERROR, "Received non-BEGIN message for non-existing transaction\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700346 return NULL;
347 }
348
Vadim Yanitskiy10c3ce52019-06-15 15:52:23 +0700349 LOGP(DSS, LOGL_DEBUG, "(%s) Establishing a network-originated session (id=0x%x)\n",
350 vlr_subscr_name(vsub), gsup_msg->session_id);
351
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700352 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
Vadim Yanitskiy10c3ce52019-06-15 15:52:23 +0700353 LOGP(DSS, LOGL_ERROR, "Missing mandatory Facility IE\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700354 return NULL;
355 }
356
Vadim Yanitskiy10c3ce52019-06-15 15:52:23 +0700357 /* Obtain an unused transaction ID */
358 tid = trans_assign_trans_id(net, vsub, TRANS_USSD);
359 if (tid < 0) {
360 LOGP(DSS, LOGL_ERROR, "No free transaction ID\n");
361 return NULL;
362 }
363
364 /* Allocate a new NCSS transaction */
365 trans = trans_alloc(net, vsub, TRANS_USSD, tid, gsup_msg->session_id);
366 if (!trans) {
367 LOGP(DSS, LOGL_ERROR, " -> No memory for trans\n");
368 return NULL;
369 }
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700370
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700371 /* Count active NC SS/USSD sessions */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200372 osmo_stat_item_inc(osmo_stat_item_group_get_item(net->statg, MSC_STAT_ACTIVE_NC_SS), 1);
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700373
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700374 /* Init inactivity timer */
375 osmo_timer_setup(&trans->ss.timer_guard,
376 ncss_session_timeout_handler, trans);
377
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700378 /* Attempt to find connection */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100379 msc_a = msc_a_for_vsub(vsub, true);
380 if (msc_a) {
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700381 /* Assign connection */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100382 msc_a_get(msc_a, MSC_A_USE_NC_SS);
383 trans->msc_a = msc_a;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700384 trans->dlci = 0x00; /* SAPI=0, not SACCH */
385 return trans;
386 }
387
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100388 LOG_TRANS(trans, LOGL_DEBUG, "Triggering Paging Request\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700389
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700390 /* Trigger Paging Request */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100391 trans->paging_request = paging_request_start(vsub, PAGING_CAUSE_SIGNALLING_HIGH_PRIO,
392 ss_paging_cb, trans, "GSM 09.11 SS/USSD");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700393 if (!trans->paging_request) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100394 LOG_TRANS(trans, LOGL_ERROR, "Failed to allocate paging token\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700395 trans_free(trans);
396 return NULL;
397 }
398
399 /* Store the Facility IE to be sent */
400 OSMO_ASSERT(trans->ss.msg == NULL);
401 trans->ss.msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
402 msgb_tlv_put(trans->ss.msg, GSM0480_IE_FACILITY,
403 gsup_msg->ss_info_len, gsup_msg->ss_info);
404
Vadim Yanitskiy04bbfb82019-06-15 15:15:55 +0700405 return trans;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700406}
407
408/* NC SS specific transaction release.
409 * Gets called by trans_free, DO NOT CALL YOURSELF! */
410void _gsm911_nc_ss_trans_free(struct gsm_trans *trans)
411{
412 /**
413 * TODO: if transaction wasn't properly terminated,
414 * we need to do it here by releasing the subscriber
415 * connection and sending notification via GSUP...
416 */
417 if (trans->ss.msg != NULL)
418 msgb_free(trans->ss.msg);
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700419
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700420 /* Stop inactivity timer */
421 osmo_timer_del(&trans->ss.timer_guard);
422
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700423 /* One session less */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200424 osmo_stat_item_dec(osmo_stat_item_group_get_item(trans->net->statg, MSC_STAT_ACTIVE_NC_SS),
425 1);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700426}
427
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100428int gsm0911_gsup_rx(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *gsup_msg)
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700429{
Vadim Yanitskiy805eca22019-06-15 17:30:23 +0700430 struct gsm_network *net = (struct gsm_network *) data;
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700431 struct gsm_trans *trans;
432 struct gsm48_hdr *gh;
433 struct msgb *ss_msg;
434 bool trans_end;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100435 struct msc_a *msc_a;
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700436 struct vlr_subscr *vsub;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100437
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700438 vsub = vlr_subscr_find_by_imsi(net->vlr, gsup_msg->imsi, __func__);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100439 if (!vsub) {
Vadim Yanitskiy3d603032019-06-15 00:54:30 +0700440 LOGP(DSS, LOGL_ERROR, "Rx %s for unknown subscriber, rejecting\n",
441 osmo_gsup_message_type_name(gsup_msg->message_type));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100442 gsup_client_mux_tx_error_reply(gcm, gsup_msg, GMM_CAUSE_IMSI_UNKNOWN);
443 return -GMM_CAUSE_IMSI_UNKNOWN;
444 }
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700445
446 /* Associate logging messages with this subscriber */
447 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
448
Vadim Yanitskiyf1775902019-06-16 15:34:28 +0700449 /* Attempt to find DTAP-transaction */
Andreas Eversberg7e4b0322023-04-23 11:43:13 +0200450 trans = trans_find_by_callref(net, TRANS_USSD, gsup_msg->session_id);
Vadim Yanitskiyf1775902019-06-16 15:34:28 +0700451
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700452 /* Handle errors */
453 if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
Vadim Yanitskiyf1775902019-06-16 15:34:28 +0700454 LOGP(DSS, LOGL_NOTICE, "Rx %s from HLR/EUSE (cause=0x%02x, sid=0x%x)\n",
455 osmo_gsup_message_type_name(gsup_msg->message_type),
456 gsup_msg->cause, gsup_msg->session_id);
457
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700458 /* We don't need subscriber info anymore */
459 vlr_subscr_put(vsub, __func__);
460
Vadim Yanitskiyf1775902019-06-16 15:34:28 +0700461 if (!trans) {
462 LOGP(DSS, LOGL_ERROR, "No transaction found for "
463 "sid=0x%x, nothing to abort\n", gsup_msg->session_id);
464 return -ENODEV;
465 }
466
467 LOG_TRANS(trans, LOGL_NOTICE, "Aborting the session: sending RELEASE COMPLETE\n");
468
469 /* Indicate connection release to subscriber (if active) */
470 if (trans->msc_a != NULL) {
471 /* TODO: implement GSUP - GSM 04.80 cause mapping */
472 msc_send_ussd_release_complete_cause(trans->msc_a, trans->transaction_id,
473 GSM48_CAUSE_LOC_PUN_S_LU, GSM48_CC_CAUSE_TEMP_FAILURE);
474 }
475
476 /* Terminate transaction */
477 trans_free(trans);
478
Harald Welte6307b852009-10-16 08:41:51 +0200479 return 0;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200480 }
Harald Welte6eafe912009-10-16 08:32:58 +0200481
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700482 if (!trans) {
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700483 /* Count network-initiated attempts to establish a NC SS/USSD session */
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200484 rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_NC_SS_MT_REQUESTS));
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700485
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700486 /* Attempt to establish a new transaction */
487 trans = establish_nc_ss_trans(net, vsub, gsup_msg);
488 if (!trans) {
Vadim Yanitskiydb5bc702019-06-15 16:13:08 +0700489 LOGP(DSS, LOGL_ERROR, "Failed to establish a network-originated "
490 "SS/USSD transaction, rejecting %s\n",
491 osmo_gsup_message_type_name(gsup_msg->message_type));
Vadim Yanitskiyefb1f602019-06-15 14:44:46 +0700492 gsup_client_mux_tx_error_reply(gcm, gsup_msg, GMM_CAUSE_NET_FAIL);
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700493 vlr_subscr_put(vsub, __func__);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700494 return -EINVAL;
495 }
496
497 /* Wait for Paging Response */
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700498 if (trans->paging_request) {
499 vlr_subscr_put(vsub, __func__);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700500 return 0;
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700501 }
Harald Welte6eafe912009-10-16 08:32:58 +0200502 }
Holger Hans Peter Freyther24866632010-06-30 12:15:19 +0800503
Vadim Yanitskiye0da4462019-06-17 21:51:12 +0700504 /* We don't need subscriber info anymore */
505 vlr_subscr_put(vsub, __func__);
506
Vadim Yanitskiy64623e12018-11-28 23:05:51 +0700507 /* (Re)schedule the inactivity timer */
508 if (net->ncss_guard_timeout > 0) {
509 osmo_timer_schedule(&trans->ss.timer_guard,
510 net->ncss_guard_timeout, 0);
511 }
512
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700513 /* Allocate and prepare a new MT message */
514 ss_msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
515 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
516 gh->proto_discr = GSM48_PDISC_NC_SS;
517 gh->proto_discr |= trans->transaction_id << 4;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700518
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700519 /**
520 * Perform GSUP-interface to A-interface mapping,
521 * according to GSM TS 09.11, table 4.1.
522 *
523 * TODO: see (note 3), both CONTINUE and END may
524 * be also mapped to REGISTER if a new transaction
525 * has to be established.
526 */
527 switch (gsup_msg->session_state) {
528 case OSMO_GSUP_SESSION_STATE_BEGIN:
529 gh->msg_type = GSM0480_MTYPE_REGISTER;
530 break;
531 case OSMO_GSUP_SESSION_STATE_CONTINUE:
532 gh->msg_type = GSM0480_MTYPE_FACILITY;
533 break;
534 case OSMO_GSUP_SESSION_STATE_END:
535 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
536 break;
537
538 /* Missing or incorrect session state */
539 case OSMO_GSUP_SESSION_STATE_NONE:
540 default:
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100541 LOG_TRANS(trans, LOGL_ERROR, "Unexpected session state %d\n",
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700542 gsup_msg->session_state);
Vadim Yanitskiyefb1f602019-06-15 14:44:46 +0700543 gsup_client_mux_tx_error_reply(gcm, gsup_msg, GMM_CAUSE_MSGT_INCOMP_P_STATE);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700544 msgb_free(ss_msg);
545 return -EINVAL;
546 }
547
548 /* Facility IE is optional only for RELEASE COMPLETE */
549 if (gh->msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
550 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
Neels Hofmeyrff7074a2019-02-28 05:50:06 +0100551 LOG_TRANS(trans, LOGL_ERROR, "Missing mandatory Facility IE "
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700552 "for mapped 0x%02x message\n", gh->msg_type);
Vadim Yanitskiyefb1f602019-06-15 14:44:46 +0700553 gsup_client_mux_tx_error_reply(gcm, gsup_msg, GMM_CAUSE_INV_MAND_INFO);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700554 msgb_free(ss_msg);
555 return -EINVAL;
556 }
557 }
558
559 /* Append Facility IE if preset */
560 if (gsup_msg->ss_info && gsup_msg->ss_info_len > 2) {
561 /* Facility IE carries LV, others carry TLV */
562 if (gh->msg_type == GSM0480_MTYPE_FACILITY)
563 msgb_lv_put(ss_msg, gsup_msg->ss_info_len, gsup_msg->ss_info);
564 else
565 msgb_tlv_put(ss_msg, GSM0480_IE_FACILITY,
566 gsup_msg->ss_info_len, gsup_msg->ss_info);
567 }
568
569 /* Should we release the transaction? */
570 trans_end = (gh->msg_type == GSM0480_MTYPE_RELEASE_COMPLETE);
571
572 /* Sent to the MS, give ownership of ss_msg */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100573 msc_a = trans->msc_a;
574 if (!msc_a) {
575 LOG_TRANS(trans, LOGL_ERROR, "Cannot send SS message, no local MSC-A role defined for subscriber\n");
Vadim Yanitskiyefb1f602019-06-15 14:44:46 +0700576 gsup_client_mux_tx_error_reply(gcm, gsup_msg, GMM_CAUSE_NET_FAIL);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100577 msgb_free(ss_msg);
578 return -EINVAL;
579 }
580 msc_a_tx_dtap_to_i(msc_a, ss_msg);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700581
582 /* Release transaction if required */
583 if (trans_end)
584 trans_free(trans);
585
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700586 /* Count established network-initiated NC SS/USSD sessions */
587 if (gsup_msg->session_state == OSMO_GSUP_SESSION_STATE_BEGIN)
Pau Espin Pedrol2e21a682021-06-04 16:45:44 +0200588 rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_NC_SS_MT_ESTABLISHED));
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700589
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700590 return 0;
Harald Welte6eafe912009-10-16 08:32:58 +0200591}