blob: 96acd8c4a813e20595857425292f6cf08badfc40 [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 Yanitskiy8a6ef552018-06-12 08:21:20 +070034#include <osmocom/core/utils.h>
35#include <osmocom/core/msgb.h>
36#include <osmocom/gsm/tlv.h>
Harald Welte6eafe912009-10-16 08:32:58 +020037
Neels Hofmeyr90843962017-09-04 15:04:35 +020038#include <osmocom/msc/gsm_04_80.h>
39#include <osmocom/msc/gsm_subscriber.h>
40#include <osmocom/msc/debug.h>
41#include <osmocom/msc/osmo_msc.h>
42#include <osmocom/msc/vlr.h>
Max43b01b02017-09-15 11:22:30 +020043#include <osmocom/msc/gsm_04_08.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070044#include <osmocom/msc/transaction.h>
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070045#include <osmocom/msc/gsup_client.h>
46#include <osmocom/msc/msc_ifaces.h>
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070047
48/* FIXME: choose a proper range */
49static uint32_t new_callref = 0x20000001;
Harald Welte6eafe912009-10-16 08:32:58 +020050
Vadim Yanitskiy5b860fa2018-06-12 05:24:52 +070051/* Entry point for call independent MO SS messages */
52int gsm0911_rcv_nc_ss(struct gsm_subscriber_connection *conn, struct msgb *msg)
Harald Welte6eafe912009-10-16 08:32:58 +020053{
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070054 struct gsm48_hdr *gh = msgb_l3(msg);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070055 struct osmo_gsup_message gsup_msg;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070056 struct gsm_trans *trans;
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +070057 struct msgb *gsup_msgb;
58 uint16_t facility_ie_len;
59 uint8_t *facility_ie;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070060 uint8_t pdisc, tid;
61 uint8_t msg_type;
62 int rc;
Harald Welte6eafe912009-10-16 08:32:58 +020063
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070064 pdisc = gsm48_hdr_pdisc(gh);
65 msg_type = gsm48_hdr_msg_type(gh);
66 tid = gsm48_hdr_trans_id_flip_ti(gh);
Harald Welte2483f1b2016-06-19 18:06:02 +020067
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070068 /* Associate logging messages with this subscriber */
69 log_set_context(LOG_CTX_VLR_SUBSCR, conn->vsub);
70
71 DEBUGP(DMM, "Received SS/USSD data (trans_id=%x, msg_type=%s)\n",
72 tid, gsm48_pdisc_msgtype_name(pdisc, msg_type));
73
74 /* Reuse existing transaction, or create a new one */
75 trans = trans_find_by_id(conn, pdisc, tid);
76 if (!trans) {
77 /**
78 * According to GSM TS 04.80, section 2.4.2 "Register
79 * (mobile station to network direction)", the REGISTER
80 * message is sent by the mobile station to the network
81 * to assign a new transaction identifier for call independent
82 * supplementary service control and to request or acknowledge
83 * a supplementary service.
84 */
85 if (msg_type != GSM0480_MTYPE_REGISTER) {
86 LOGP(DMM, LOGL_ERROR, "Unexpected message (msg_type=%s), "
87 "transaction is not allocated yet\n",
88 gsm48_pdisc_msgtype_name(pdisc, msg_type));
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +070089 gsm48_tx_simple(conn,
90 GSM48_PDISC_NC_SS | (tid << 4),
91 GSM0480_MTYPE_RELEASE_COMPLETE);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +070092 return -EINVAL;
93 }
94
95 DEBUGP(DMM, " -> (new transaction)\n");
96 trans = trans_alloc(conn->network, conn->vsub,
97 pdisc, tid, new_callref++);
98 if (!trans) {
99 DEBUGP(DMM, " -> No memory for trans\n");
Vadim Yanitskiy9aec25e2018-06-12 06:26:28 +0700100 gsm48_tx_simple(conn,
101 GSM48_PDISC_NC_SS | (tid << 4),
102 GSM0480_MTYPE_RELEASE_COMPLETE);
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700103 return -ENOMEM;
104 }
105
106 trans->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_NC_SS);
107 trans->dlci = OMSC_LINKID_CB(msg);
108 cm_service_request_concludes(conn, msg);
109 }
Harald Welte2483f1b2016-06-19 18:06:02 +0200110
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700111 /* Attempt to extract Facility IE */
112 rc = gsm0480_extract_ie_by_tag(gh, msgb_l3len(msg),
113 &facility_ie, &facility_ie_len, GSM0480_IE_FACILITY);
114 if (rc) {
115 LOGP(DMM, LOGL_ERROR, "GSM 04.80 message parsing error, "
116 "couldn't extract Facility IE\n");
117 goto error;
Tobias Engelea730322013-12-28 17:03:14 +0100118 }
119
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700120 /* Facility IE is optional for RELEASE COMPLETE */
121 if (msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
122 if (!facility_ie || facility_ie_len < 2) {
123 LOGP(DMM, LOGL_ERROR, "GSM 04.80 message parsing error, "
124 "missing mandatory Facility IE\n");
125 rc = -EINVAL;
126 goto error;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200127 }
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700128 }
129
130 /* Compose a mew GSUP message */
131 memset(&gsup_msg, 0x00, sizeof(gsup_msg));
132 gsup_msg.message_type = OSMO_GSUP_MSGT_PROC_SS_REQUEST;
133 gsup_msg.session_id = trans->callref;
134
135 /**
136 * Perform A-interface to GSUP-interface mapping,
137 * according to GSM TS 09.11, table 4.2.
138 */
139 switch (msg_type) {
140 case GSM0480_MTYPE_REGISTER:
141 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_BEGIN;
142 break;
143 case GSM0480_MTYPE_FACILITY:
144 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
145 break;
146 case GSM0480_MTYPE_RELEASE_COMPLETE:
147 gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_END;
148 break;
149 }
150
151 /* Fill in the (optional) message payload */
152 if (facility_ie) {
153 gsup_msg.ss_info_len = facility_ie_len;
154 gsup_msg.ss_info = facility_ie;
155 }
156
157 /* Fill in subscriber's IMSI */
158 OSMO_STRLCPY_ARRAY(gsup_msg.imsi, conn->vsub->imsi);
159
160 /* Allocate GSUP message buffer */
161 gsup_msgb = gsup_client_msgb_alloc();
162 if (!gsup_msgb) {
163 LOGP(DMM, LOGL_ERROR, "Couldn't allocate GSUP message\n");
164 rc = -ENOMEM;
165 goto error;
166 }
167
168 /* Encode GSUP message */
169 rc = osmo_gsup_encode(gsup_msgb, &gsup_msg);
170 if (rc) {
171 LOGP(DMM, LOGL_ERROR, "Couldn't encode GSUP message\n");
172 goto error;
173 }
174
175 /* Finally send */
176 rc = gsup_client_send(conn->network->vlr->gsup_client, gsup_msgb);
177 if (rc) {
178 LOGP(DMM, LOGL_ERROR, "Couldn't send GSUP message\n");
179 goto error;
180 }
181
Vadim Yanitskiyfcc24ed2018-06-21 17:55:56 +0700182 /* Should we release connection? Or wait for response? */
183 if (msg_type == GSM0480_MTYPE_RELEASE_COMPLETE)
184 trans_free(trans);
185 else
186 msc_subscr_conn_communicating(conn);
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700187
188 return 0;
189
190error:
191 /* Abort transaction on DTAP-interface */
192 gsm0480_send_ussd_reject(conn, tid, -1,
193 GSM_0480_PROBLEM_CODE_TAG_GENERAL,
194 GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
195 if (trans)
196 trans_free(trans);
197
198 /* TODO: abort transaction on GSUP interface if any */
199 return rc;
200}
201
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700202/* Call-back from paging the B-end of the connection */
203static int handle_paging_event(unsigned int hooknum, unsigned int event,
204 struct msgb *msg, void *_conn, void *_transt)
205{
206 struct gsm_subscriber_connection *conn = _conn;
207 enum gsm_paging_event paging_event = event;
208 struct gsm_trans *transt = _transt;
209 struct gsm48_hdr *gh;
210 struct msgb *ss_msg;
211
212 OSMO_ASSERT(!transt->conn);
213 OSMO_ASSERT(transt->ss.msg);
214
215 switch (paging_event) {
216 case GSM_PAGING_SUCCEEDED:
217 DEBUGP(DMM, "Paging subscr %s succeeded!\n",
218 vlr_subscr_msisdn_or_name(transt->vsub));
219
220 /* Assign connection */
221 transt->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_NC_SS);
222 transt->paging_request = NULL;
223
224 /* Send stored message */
225 ss_msg = transt->ss.msg;
226 OSMO_ASSERT(ss_msg);
227
228 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
229 gh->proto_discr = GSM48_PDISC_NC_SS;
230 gh->proto_discr |= transt->transaction_id << 4;
231 gh->msg_type = GSM0480_MTYPE_REGISTER;
232
233 /* Sent to the MS, give ownership of ss_msg */
234 msc_tx_dtap(transt->conn, ss_msg);
235 transt->ss.msg = NULL;
236 break;
237 case GSM_PAGING_EXPIRED:
238 case GSM_PAGING_BUSY:
239 DEBUGP(DMM, "Paging subscr %s %s!\n",
240 vlr_subscr_msisdn_or_name(transt->vsub),
241 paging_event == GSM_PAGING_EXPIRED ? "expired" : "busy");
242
243 /* TODO: inform HLR about this failure */
244
245 msgb_free(transt->ss.msg);
246 transt->ss.msg = NULL;
247
248 transt->callref = 0;
249 transt->paging_request = NULL;
250 trans_free(transt);
251 break;
252 }
253
254 return 0;
255}
256
257static struct gsm_trans *establish_nc_ss_trans(struct gsm_network *net,
258 struct vlr_subscr *vsub, struct osmo_gsup_message *gsup_msg)
259{
260 struct gsm_subscriber_connection *conn;
261 struct gsm_trans *trans, *transt;
262 int tid;
263
264 if (gsup_msg->session_state != OSMO_GSUP_SESSION_STATE_BEGIN) {
265 LOGP(DMM, LOGL_ERROR, "Received non-BEGIN message "
266 "for non-existing transaction\n");
267 return NULL;
268 }
269
270 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
271 LOGP(DMM, LOGL_ERROR, "Missing mandatory Facility IE\n");
272 return NULL;
273 }
274
275 /* If subscriber is not "attached" */
276 if (!vsub->lac) {
277 LOGP(DMM, LOGL_ERROR, "Network-originated session "
278 "rejected - subscriber is not attached\n");
279 return NULL;
280 }
281
282 DEBUGP(DMM, "Establishing network-originated session\n");
283
284 /* Allocate a new transaction */
285 trans = trans_alloc(net, vsub, GSM48_PDISC_NC_SS,
286 0xff, gsup_msg->session_id);
287 if (!trans) {
288 DEBUGP(DMM, " -> No memory for trans\n");
289 return NULL;
290 }
291
292 /* Assign transaction ID */
293 tid = trans_assign_trans_id(trans->net,
294 trans->vsub, GSM48_PDISC_NC_SS, 0);
295 if (tid < 0) {
296 LOGP(DMM, LOGL_ERROR, "No free transaction ID\n");
297 /* TODO: inform HLR about this */
298 /* TODO: release connection with subscriber */
299 trans->callref = 0;
300 trans_free(trans);
301 return NULL;
302 }
303 trans->transaction_id = tid;
304
305 /* Attempt to find connection */
306 conn = connection_for_subscr(vsub);
307 if (conn) {
308 /* Assign connection */
309 trans->conn = msc_subscr_conn_get(conn, MSC_CONN_USE_TRANS_NC_SS);
310 trans->dlci = 0x00; /* SAPI=0, not SACCH */
311 return trans;
312 }
313
314 DEBUGP(DMM, "Triggering Paging Request\n");
315
316 /* Find transaction with this subscriber already paging */
317 llist_for_each_entry(transt, &net->trans_list, entry) {
318 /* Transaction of our conn? */
319 if (transt == trans || transt->vsub != vsub)
320 continue;
321
322 LOGP(DMM, LOGL_ERROR, "Paging already started, "
323 "rejecting message...\n");
324 trans_free(trans);
325 return NULL;
326 }
327
328 /* Trigger Paging Request */
329 trans->paging_request = subscr_request_conn(vsub,
330 &handle_paging_event, trans, "GSM 09.11 SS/USSD");
331 if (!trans->paging_request) {
332 LOGP(DMM, LOGL_ERROR, "Failed to allocate paging token\n");
333 trans_free(trans);
334 return NULL;
335 }
336
337 /* Store the Facility IE to be sent */
338 OSMO_ASSERT(trans->ss.msg == NULL);
339 trans->ss.msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
340 msgb_tlv_put(trans->ss.msg, GSM0480_IE_FACILITY,
341 gsup_msg->ss_info_len, gsup_msg->ss_info);
342
343 return NULL;
344}
345
346/* NC SS specific transaction release.
347 * Gets called by trans_free, DO NOT CALL YOURSELF! */
348void _gsm911_nc_ss_trans_free(struct gsm_trans *trans)
349{
350 /**
351 * TODO: if transaction wasn't properly terminated,
352 * we need to do it here by releasing the subscriber
353 * connection and sending notification via GSUP...
354 */
355 if (trans->ss.msg != NULL)
356 msgb_free(trans->ss.msg);
357}
358
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700359int gsm0911_gsup_handler(struct vlr_subscr *vsub,
360 struct osmo_gsup_message *gsup_msg)
361{
362 struct vlr_instance *vlr;
363 struct gsm_network *net;
364 struct gsm_trans *trans;
365 struct gsm48_hdr *gh;
366 struct msgb *ss_msg;
367 bool trans_end;
368
369 /* Associate logging messages with this subscriber */
370 log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
371
372 /* Obtain pointer to vlr_instance */
373 vlr = vsub->vlr;
374 OSMO_ASSERT(vlr);
375
376 /* Obtain pointer to gsm_network */
377 net = (struct gsm_network *) vlr->user_ctx;
378 OSMO_ASSERT(net);
379
380 /* Handle errors */
381 if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
382 /* FIXME: handle this error somehow! */
Harald Welte6307b852009-10-16 08:41:51 +0200383 return 0;
Holger Hans Peter Freyther5085e0b2016-07-12 17:53:26 +0200384 }
Harald Welte6eafe912009-10-16 08:32:58 +0200385
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700386 /* Attempt to find DTAP-transaction */
387 trans = trans_find_by_callref(net, gsup_msg->session_id);
388 if (!trans) {
Vadim Yanitskiyf2f83b02018-06-17 21:09:28 +0700389 /* Attempt to establish a new transaction */
390 trans = establish_nc_ss_trans(net, vsub, gsup_msg);
391 if (!trans) {
392 /* FIXME: send ERROR back to the HLR */
393 return -EINVAL;
394 }
395
396 /* Wait for Paging Response */
397 if (trans->paging_request)
398 return 0;
Harald Welte6eafe912009-10-16 08:32:58 +0200399 }
Holger Hans Peter Freyther24866632010-06-30 12:15:19 +0800400
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700401 /* Allocate and prepare a new MT message */
402 ss_msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD");
403 gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh));
404 gh->proto_discr = GSM48_PDISC_NC_SS;
405 gh->proto_discr |= trans->transaction_id << 4;
Vadim Yanitskiy10c64192018-04-17 19:17:11 +0700406
Vadim Yanitskiy8a6ef552018-06-12 08:21:20 +0700407 /**
408 * Perform GSUP-interface to A-interface mapping,
409 * according to GSM TS 09.11, table 4.1.
410 *
411 * TODO: see (note 3), both CONTINUE and END may
412 * be also mapped to REGISTER if a new transaction
413 * has to be established.
414 */
415 switch (gsup_msg->session_state) {
416 case OSMO_GSUP_SESSION_STATE_BEGIN:
417 gh->msg_type = GSM0480_MTYPE_REGISTER;
418 break;
419 case OSMO_GSUP_SESSION_STATE_CONTINUE:
420 gh->msg_type = GSM0480_MTYPE_FACILITY;
421 break;
422 case OSMO_GSUP_SESSION_STATE_END:
423 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
424 break;
425
426 /* Missing or incorrect session state */
427 case OSMO_GSUP_SESSION_STATE_NONE:
428 default:
429 LOGP(DMM, LOGL_ERROR, "Unexpected session state %d\n",
430 gsup_msg->session_state);
431 /* FIXME: send ERROR back to the HLR */
432 msgb_free(ss_msg);
433 return -EINVAL;
434 }
435
436 /* Facility IE is optional only for RELEASE COMPLETE */
437 if (gh->msg_type != GSM0480_MTYPE_RELEASE_COMPLETE) {
438 if (!gsup_msg->ss_info || gsup_msg->ss_info_len < 2) {
439 LOGP(DMM, LOGL_ERROR, "Missing mandatory Facility IE "
440 "for mapped 0x%02x message\n", gh->msg_type);
441 /* FIXME: send ERROR back to the HLR */
442 msgb_free(ss_msg);
443 return -EINVAL;
444 }
445 }
446
447 /* Append Facility IE if preset */
448 if (gsup_msg->ss_info && gsup_msg->ss_info_len > 2) {
449 /* Facility IE carries LV, others carry TLV */
450 if (gh->msg_type == GSM0480_MTYPE_FACILITY)
451 msgb_lv_put(ss_msg, gsup_msg->ss_info_len, gsup_msg->ss_info);
452 else
453 msgb_tlv_put(ss_msg, GSM0480_IE_FACILITY,
454 gsup_msg->ss_info_len, gsup_msg->ss_info);
455 }
456
457 /* Should we release the transaction? */
458 trans_end = (gh->msg_type == GSM0480_MTYPE_RELEASE_COMPLETE);
459
460 /* Sent to the MS, give ownership of ss_msg */
461 msc_tx_dtap(trans->conn, ss_msg);
462
463 /* Release transaction if required */
464 if (trans_end)
465 trans_free(trans);
466
467 return 0;
Harald Welte6eafe912009-10-16 08:32:58 +0200468}