blob: 608d4ff99f91c6400e4818b981e10e6d8770a413 [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>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070035#include <osmocom/core/utils.h>
36#include <osmocom/core/msgb.h>
Vadim Yanitskiy0622ef52018-08-03 04:39:04 +070037
38#include <osmocom/gsm/protocol/gsm_04_80.h>
39#include <osmocom/gsm/gsm0480.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070040#include <osmocom/gsm/tlv.h>
Harald Welte6eafe912009-10-16 08:32:58 +020041
Neels Hofmeyr90843962017-09-04 15:04:35 +020042#include <osmocom/msc/gsm_04_80.h>
43#include <osmocom/msc/gsm_subscriber.h>
44#include <osmocom/msc/debug.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020045#include <osmocom/msc/vlr.h>
Max43b01b02017-09-15 11:22:30 +020046#include <osmocom/msc/gsm_04_08.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070047#include <osmocom/msc/transaction.h>
Harald Welte1ea6baf2018-07-31 19:40:52 +020048#include <osmocom/gsupclient/gsup_client.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070049#include <osmocom/msc/msc_ifaces.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070050
51/* FIXME: choose a proper range */
52static uint32_t new_callref = 0x20000001;
Harald Welte6eafe912009-10-16 08:32:58 +020053
Vadim Yanitskiy5b860fa2018-06-12 05:24:52 +070054/* Entry point for call independent MO SS messages */
Neels Hofmeyrc036b792018-11-29 22:37:51 +010055int gsm0911_rcv_nc_ss(struct ran_conn *conn, struct msgb *msg)
Harald Welte6eafe912009-10-16 08:32:58 +020056{
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070057 struct gsm48_hdr *gh = msgb_l3(msg);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070058 struct osmo_gsup_message gsup_msg;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070059 struct gsm_trans *trans;
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070060 struct msgb *gsup_msgb;
61 uint16_t facility_ie_len;
62 uint8_t *facility_ie;
Max4a5cfa52019-01-10 17:41:05 +010063 uint8_t tid;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070064 uint8_t msg_type;
65 int rc;
Harald Welte6eafe912009-10-16 08:32:58 +020066
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070067 msg_type = gsm48_hdr_msg_type(gh);
68 tid = gsm48_hdr_trans_id_flip_ti(gh);
Harald Welte2483f1b2016-06-19 18:06:02 +020069
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070070 /* Associate logging messages with this subscriber */
71 log_set_context(LOG_CTX_VLR_SUBSCR, conn->vsub);
72
73 DEBUGP(DMM, "Received SS/USSD data (trans_id=%x, msg_type=%s)\n",
Max4a5cfa52019-01-10 17:41:05 +010074 tid, gsm48_pdisc_msgtype_name(GSM48_PDISC_NC_SS, msg_type));
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070075
76 /* Reuse existing transaction, or create a new one */
Max4a5cfa52019-01-10 17:41:05 +010077 trans = trans_find_by_id(conn, GSM48_PDISC_NC_SS, tid);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070078 if (!trans) {
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +070079 /* Count MS-initiated attempts to establish a NC SS/USSD session */
80 rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_NC_SS_MO_REQUESTS]);
81
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070082 /**
83 * According to GSM TS 04.80, section 2.4.2 "Register
84 * (mobile station to network direction)", the REGISTER
85 * message is sent by the mobile station to the network
86 * to assign a new transaction identifier for call independent
87 * supplementary service control and to request or acknowledge
88 * a supplementary service.
89 */
90 if (msg_type != GSM0480_MTYPE_REGISTER) {
91 LOGP(DMM, LOGL_ERROR, "Unexpected message (msg_type=%s), "
92 "transaction is not allocated yet\n",
Max4a5cfa52019-01-10 17:41:05 +010093 gsm48_pdisc_msgtype_name(GSM48_PDISC_NC_SS, msg_type));
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +070094 gsm48_tx_simple(conn,
95 GSM48_PDISC_NC_SS | (tid << 4),
96 GSM0480_MTYPE_RELEASE_COMPLETE);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070097 return -EINVAL;
98 }
99
100 DEBUGP(DMM, " -> (new transaction)\n");
101 trans = trans_alloc(conn->network, conn->vsub,
Max4a5cfa52019-01-10 17:41:05 +0100102 GSM48_PDISC_NC_SS, tid, new_callref++);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700103 if (!trans) {
Max3614fd62019-01-17 13:38:10 +0100104 LOGP(DMM, LOGL_ERROR, " -> No memory for trans\n");
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +0700105 gsm48_tx_simple(conn,
106 GSM48_PDISC_NC_SS | (tid << 4),
107 GSM0480_MTYPE_RELEASE_COMPLETE);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700108 return -ENOMEM;
109 }
110
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700111 /* Count active NC SS/USSD sessions */
112 osmo_counter_inc(conn->network->active_nc_ss);
113
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100114 trans->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_NC_SS);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700115 trans->dlci = OMSC_LINKID_CB(msg);
116 cm_service_request_concludes(conn, msg);
117 }
Harald Welte2483f1b2016-06-19 18:06:02 +0200118
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700119 /* Attempt to extract Facility IE */
120 rc = gsm0480_extract_ie_by_tag(gh, msgb_l3len(msg),
121 &facility_ie, &facility_ie_len, GSM0480_IE_FACILITY);
122 if (rc) {
123 LOGP(DMM, LOGL_ERROR, "GSM 04.80 message parsing error, "
124 "couldn't extract Facility IE\n");
125 goto error;
Tobias Engelea730322013-12-28 17:03:14 +0100126 }
127
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700128 /* Facility IE is optional for RELEASE COMPLETE */
129 if (msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
130 if (!facility_ie || facility_ie_len < 2) {
131 LOGP(DMM, LOGL_ERROR, "GSM 04.80 message parsing error, "
132 "missing mandatory Facility IE\n");
133 rc = -EINVAL;
134 goto error;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200135 }
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700136 }
137
138 /* Compose a mew GSUP message */
139 memset(&gsup_msg, 0x00, sizeof(gsup_msg));
140 gsup_msg.message_type = OSMO_GSUP_MSGT_PROC_SS_REQUEST;
141 gsup_msg.session_id = trans->callref;
142
143 /**
144 * Perform A-interface to GSUP-interface mapping,
145 * according to GSM TS 09.11, table 4.2.
146 */
147 switch (msg_type) {
148 case GSM0480_MTYPE_REGISTER:
149 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_BEGIN;
150 break;
151 case GSM0480_MTYPE_FACILITY:
152 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
153 break;
154 case GSM0480_MTYPE_RELEASE_COMPLETE:
155 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_END;
156 break;
157 }
158
159 /* Fill in the (optional) message payload */
160 if (facility_ie) {
161 gsup_msg.ss_info_len = facility_ie_len;
162 gsup_msg.ss_info = facility_ie;
163 }
164
165 /* Fill in subscriber's IMSI */
166 OSMO_STRLCPY_ARRAY(gsup_msg.imsi, conn->vsub->imsi);
167
168 /* Allocate GSUP message buffer */
Harald Welte1ea6baf2018-07-31 19:40:52 +0200169 gsup_msgb = osmo_gsup_client_msgb_alloc();
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700170 if (!gsup_msgb) {
171 LOGP(DMM, LOGL_ERROR, "Couldn't allocate GSUP message\n");
172 rc = -ENOMEM;
173 goto error;
174 }
175
176 /* Encode GSUP message */
177 rc = osmo_gsup_encode(gsup_msgb, &gsup_msg);
178 if (rc) {
179 LOGP(DMM, LOGL_ERROR, "Couldn't encode GSUP message\n");
180 goto error;
181 }
182
183 /* Finally send */
Harald Welte1ea6baf2018-07-31 19:40:52 +0200184 rc = osmo_gsup_client_send(conn->network->vlr->gsup_client, gsup_msgb);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700185 if (rc) {
186 LOGP(DMM, LOGL_ERROR, "Couldn't send GSUP message\n");
187 goto error;
188 }
189
Vadim Yanitskiyfcc24ed2018-06-21 17:55:56 +0700190 /* Should we release connection? Or wait for response? */
191 if (msg_type == GSM0480_MTYPE_RELEASE_COMPLETE)
192 trans_free(trans);
193 else
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100194 ran_conn_communicating(conn);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700195
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700196 /* Count established MS-initiated NC SS/USSD sessions */
197 if (msg_type == GSM0480_MTYPE_REGISTER)
198 rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_NC_SS_MO_ESTABLISHED]);
199
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700200 return 0;
201
202error:
203 /* Abort transaction on DTAP-interface */
Vadim Yanitskiy0622ef52018-08-03 04:39:04 +0700204 msc_send_ussd_reject(conn, tid, -1,
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700205 GSM_0480_PROBLEM_CODE_TAG_GENERAL,
206 GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
207 if (trans)
208 trans_free(trans);
209
210 /* TODO: abort transaction on GSUP interface if any */
211 return rc;
212}
213
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700214/* Call-back from paging the B-end of the connection */
215static int handle_paging_event(unsigned int hooknum, unsigned int event,
216 struct msgb *msg, void *_conn, void *_transt)
217{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100218 struct ran_conn *conn = _conn;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700219 enum gsm_paging_event paging_event = event;
220 struct gsm_trans *transt = _transt;
221 struct gsm48_hdr *gh;
222 struct msgb *ss_msg;
223
224 OSMO_ASSERT(!transt->conn);
225 OSMO_ASSERT(transt->ss.msg);
226
227 switch (paging_event) {
228 case GSM_PAGING_SUCCEEDED:
229 DEBUGP(DMM, "Paging subscr %s succeeded!\n",
230 vlr_subscr_msisdn_or_name(transt->vsub));
231
232 /* Assign connection */
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100233 transt->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_NC_SS);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700234 transt->paging_request = NULL;
235
236 /* Send stored message */
237 ss_msg = transt->ss.msg;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700238 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
239 gh->proto_discr = GSM48_PDISC_NC_SS;
240 gh->proto_discr |= transt->transaction_id << 4;
241 gh->msg_type = GSM0480_MTYPE_REGISTER;
242
243 /* Sent to the MS, give ownership of ss_msg */
244 msc_tx_dtap(transt->conn, ss_msg);
245 transt->ss.msg = NULL;
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700246
247 /* Count established network-initiated NC SS/USSD sessions */
248 rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_NC_SS_MT_ESTABLISHED]);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700249 break;
250 case GSM_PAGING_EXPIRED:
251 case GSM_PAGING_BUSY:
252 DEBUGP(DMM, "Paging subscr %s %s!\n",
253 vlr_subscr_msisdn_or_name(transt->vsub),
254 paging_event == GSM_PAGING_EXPIRED ? "expired" : "busy");
255
256 /* TODO: inform HLR about this failure */
257
258 msgb_free(transt->ss.msg);
259 transt->ss.msg = NULL;
260
261 transt->callref = 0;
262 transt->paging_request = NULL;
263 trans_free(transt);
264 break;
265 }
266
267 return 0;
268}
269
270static struct gsm_trans *establish_nc_ss_trans(struct gsm_network *net,
271 struct vlr_subscr *vsub, struct osmo_gsup_message *gsup_msg)
272{
Neels Hofmeyrc036b792018-11-29 22:37:51 +0100273 struct ran_conn *conn;
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700274 struct gsm_trans *trans, *transt;
275 int tid;
276
277 if (gsup_msg->session_state != OSMO_GSUP_SESSION_STATE_BEGIN) {
278 LOGP(DMM, LOGL_ERROR, "Received non-BEGIN message "
279 "for non-existing transaction\n");
280 return NULL;
281 }
282
283 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
284 LOGP(DMM, LOGL_ERROR, "Missing mandatory Facility IE\n");
285 return NULL;
286 }
287
288 /* If subscriber is not "attached" */
Max7d41d872018-12-19 11:48:33 +0100289 if (!vsub->cgi.lai.lac) {
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700290 LOGP(DMM, LOGL_ERROR, "Network-originated session "
291 "rejected - subscriber is not attached\n");
292 return NULL;
293 }
294
295 DEBUGP(DMM, "Establishing network-originated session\n");
296
297 /* Allocate a new transaction */
298 trans = trans_alloc(net, vsub, GSM48_PDISC_NC_SS,
299 0xff, gsup_msg->session_id);
300 if (!trans) {
Max3614fd62019-01-17 13:38:10 +0100301 LOGP(DMM, LOGL_ERROR, " -> No memory for trans\n");
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700302 return NULL;
303 }
304
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700305 /* Count active NC SS/USSD sessions */
306 osmo_counter_inc(net->active_nc_ss);
307
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700308 /* Assign transaction ID */
309 tid = trans_assign_trans_id(trans->net,
310 trans->vsub, GSM48_PDISC_NC_SS, 0);
311 if (tid < 0) {
312 LOGP(DMM, LOGL_ERROR, "No free transaction ID\n");
313 /* TODO: inform HLR about this */
314 /* TODO: release connection with subscriber */
315 trans->callref = 0;
316 trans_free(trans);
317 return NULL;
318 }
319 trans->transaction_id = tid;
320
321 /* Attempt to find connection */
322 conn = connection_for_subscr(vsub);
323 if (conn) {
324 /* Assign connection */
Neels Hofmeyr3c20a5e2018-11-30 01:08:36 +0100325 trans->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_NC_SS);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700326 trans->dlci = 0x00; /* SAPI=0, not SACCH */
327 return trans;
328 }
329
330 DEBUGP(DMM, "Triggering Paging Request\n");
331
332 /* Find transaction with this subscriber already paging */
333 llist_for_each_entry(transt, &net->trans_list, entry) {
334 /* Transaction of our conn? */
335 if (transt == trans || transt->vsub != vsub)
336 continue;
337
338 LOGP(DMM, LOGL_ERROR, "Paging already started, "
339 "rejecting message...\n");
340 trans_free(trans);
341 return NULL;
342 }
343
344 /* Trigger Paging Request */
345 trans->paging_request = subscr_request_conn(vsub,
346 &handle_paging_event, trans, "GSM 09.11 SS/USSD");
347 if (!trans->paging_request) {
348 LOGP(DMM, LOGL_ERROR, "Failed to allocate paging token\n");
349 trans_free(trans);
350 return NULL;
351 }
352
353 /* Store the Facility IE to be sent */
354 OSMO_ASSERT(trans->ss.msg == NULL);
355 trans->ss.msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
356 msgb_tlv_put(trans->ss.msg, GSM0480_IE_FACILITY,
357 gsup_msg->ss_info_len, gsup_msg->ss_info);
358
359 return NULL;
360}
361
362/* NC SS specific transaction release.
363 * Gets called by trans_free, DO NOT CALL YOURSELF! */
364void _gsm911_nc_ss_trans_free(struct gsm_trans *trans)
365{
366 /**
367 * TODO: if transaction wasn't properly terminated,
368 * we need to do it here by releasing the subscriber
369 * connection and sending notification via GSUP...
370 */
371 if (trans->ss.msg != NULL)
372 msgb_free(trans->ss.msg);
Vadim Yanitskiyad64e2a2018-06-26 18:27:25 +0700373
374 /* One session less */
375 osmo_counter_dec(trans->net->active_nc_ss);
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700376}
377
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700378int gsm0911_gsup_handler(struct vlr_subscr *vsub,
379 struct osmo_gsup_message *gsup_msg)
380{
381 struct vlr_instance *vlr;
382 struct gsm_network *net;
383 struct gsm_trans *trans;
384 struct gsm48_hdr *gh;
385 struct msgb *ss_msg;
386 bool trans_end;
387
388 /* Associate logging messages with this subscriber */
389 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
390
391 /* Obtain pointer to vlr_instance */
392 vlr = vsub->vlr;
393 OSMO_ASSERT(vlr);
394
395 /* Obtain pointer to gsm_network */
396 net = (struct gsm_network *) vlr->user_ctx;
397 OSMO_ASSERT(net);
398
399 /* Handle errors */
400 if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
401 /* FIXME: handle this error somehow! */
Harald Welte6307b852009-10-16 08:41:51 +0200402 return 0;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200403 }
Harald Welte6eafe912009-10-16 08:32:58 +0200404
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700405 /* Attempt to find DTAP-transaction */
406 trans = trans_find_by_callref(net, gsup_msg->session_id);
407 if (!trans) {
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700408 /* Count network-initiated attempts to establish a NC SS/USSD session */
409 rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_NC_SS_MT_REQUESTS]);
410
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700411 /* Attempt to establish a new transaction */
412 trans = establish_nc_ss_trans(net, vsub, gsup_msg);
413 if (!trans) {
414 /* FIXME: send ERROR back to the HLR */
415 return -EINVAL;
416 }
417
418 /* Wait for Paging Response */
419 if (trans->paging_request)
420 return 0;
Harald Welte6eafe912009-10-16 08:32:58 +0200421 }
Holger Hans Peter Freyther24866632010-06-30 12:15:19 +0800422
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700423 /* Allocate and prepare a new MT message */
424 ss_msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
425 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
426 gh->proto_discr = GSM48_PDISC_NC_SS;
427 gh->proto_discr |= trans->transaction_id << 4;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700428
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700429 /**
430 * Perform GSUP-interface to A-interface mapping,
431 * according to GSM TS 09.11, table 4.1.
432 *
433 * TODO: see (note 3), both CONTINUE and END may
434 * be also mapped to REGISTER if a new transaction
435 * has to be established.
436 */
437 switch (gsup_msg->session_state) {
438 case OSMO_GSUP_SESSION_STATE_BEGIN:
439 gh->msg_type = GSM0480_MTYPE_REGISTER;
440 break;
441 case OSMO_GSUP_SESSION_STATE_CONTINUE:
442 gh->msg_type = GSM0480_MTYPE_FACILITY;
443 break;
444 case OSMO_GSUP_SESSION_STATE_END:
445 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
446 break;
447
448 /* Missing or incorrect session state */
449 case OSMO_GSUP_SESSION_STATE_NONE:
450 default:
451 LOGP(DMM, LOGL_ERROR, "Unexpected session state %d\n",
452 gsup_msg->session_state);
453 /* FIXME: send ERROR back to the HLR */
454 msgb_free(ss_msg);
455 return -EINVAL;
456 }
457
458 /* Facility IE is optional only for RELEASE COMPLETE */
459 if (gh->msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
460 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
461 LOGP(DMM, LOGL_ERROR, "Missing mandatory Facility IE "
462 "for mapped 0x%02x message\n", gh->msg_type);
463 /* FIXME: send ERROR back to the HLR */
464 msgb_free(ss_msg);
465 return -EINVAL;
466 }
467 }
468
469 /* Append Facility IE if preset */
470 if (gsup_msg->ss_info && gsup_msg->ss_info_len > 2) {
471 /* Facility IE carries LV, others carry TLV */
472 if (gh->msg_type == GSM0480_MTYPE_FACILITY)
473 msgb_lv_put(ss_msg, gsup_msg->ss_info_len, gsup_msg->ss_info);
474 else
475 msgb_tlv_put(ss_msg, GSM0480_IE_FACILITY,
476 gsup_msg->ss_info_len, gsup_msg->ss_info);
477 }
478
479 /* Should we release the transaction? */
480 trans_end = (gh->msg_type == GSM0480_MTYPE_RELEASE_COMPLETE);
481
482 /* Sent to the MS, give ownership of ss_msg */
483 msc_tx_dtap(trans->conn, ss_msg);
484
485 /* Release transaction if required */
486 if (trans_end)
487 trans_free(trans);
488
Vadim Yanitskiy8e25cc52018-06-23 03:32:20 +0700489 /* Count established network-initiated NC SS/USSD sessions */
490 if (gsup_msg->session_state == OSMO_GSUP_SESSION_STATE_BEGIN)
491 rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_NC_SS_MT_ESTABLISHED]);
492
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700493 return 0;
Harald Welte6eafe912009-10-16 08:32:58 +0200494}