blob: 135a5e4cde83496d249d4a338c8acf7dd6c5ab9a [file] [log] [blame]
Harald Welte3e6376d2010-12-22 23:54:51 +01001/* mncc_builtin.c - default, minimal built-in MNCC Application for
Alexander Couzensfbd96f52016-08-29 18:40:02 +02002 * standalone bsc_hack (network-in-the-box mode) */
Harald Welte3e6376d2010-12-22 23:54:51 +01003
4/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2009 by Andreas Eversberg <Andreas.Eversberg@versatel.de>
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
Harald Welte3e6376d2010-12-22 23:54:51 +010029
Neels Hofmeyr90843962017-09-04 15:04:35 +020030#include <osmocom/msc/gsm_04_08.h>
31#include <osmocom/msc/debug.h>
32#include <osmocom/msc/mncc.h>
33#include <osmocom/msc/mncc_int.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010034#include <osmocom/core/talloc.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020035#include <osmocom/msc/gsm_data.h>
36#include <osmocom/msc/transaction.h>
Harald Welte3e6376d2010-12-22 23:54:51 +010037
38void *tall_call_ctx;
39
40static LLIST_HEAD(call_list);
41
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020042static uint32_t new_callref = 0x00000001;
Harald Welte3e6376d2010-12-22 23:54:51 +010043
Harald Welteab386e62011-09-01 18:18:43 +020044struct mncc_int mncc_int = {
Andreas Eversberga83d5112013-12-07 18:32:28 +010045 .def_codec = { GSM48_CMODE_SPEECH_V1, GSM48_CMODE_SPEECH_V1 },
Harald Welteab386e62011-09-01 18:18:43 +020046};
47
Harald Welte3e6376d2010-12-22 23:54:51 +010048static void free_call(struct gsm_call *call)
49{
50 llist_del(&call->entry);
51 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
52 talloc_free(call);
53}
54
55
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020056static struct gsm_call *get_call_ref(uint32_t callref)
Harald Welte3e6376d2010-12-22 23:54:51 +010057{
58 struct gsm_call *callt;
59
60 llist_for_each_entry(callt, &call_list, entry) {
61 if (callt->callref == callref)
62 return callt;
63 }
64 return NULL;
65}
66
Harald Welte3e6376d2010-12-22 23:54:51 +010067/* on incoming call, look up database and send setup to remote subscr. */
68static int mncc_setup_ind(struct gsm_call *call, int msg_type,
69 struct gsm_mncc *setup)
70{
71 struct gsm_mncc mncc;
72 struct gsm_call *remote;
73
74 memset(&mncc, 0, sizeof(struct gsm_mncc));
75 mncc.callref = call->callref;
76
77 /* already have remote call */
78 if (call->remote_ref)
79 return 0;
80
81 /* transfer mode 1 would be packet mode, which was never specified */
82 if (setup->bearer_cap.mode != 0) {
83 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
84 "packet mode\n", call->callref);
85 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
86 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
87 goto out_reject;
88 }
89
90 /* we currently only do speech */
91 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
92 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
93 "voice calls\n", call->callref);
94 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
95 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
96 goto out_reject;
97 }
98
99 /* create remote call */
Andreas Eversbergc5e08512013-01-25 08:36:32 +0100100 if (!(remote = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte3e6376d2010-12-22 23:54:51 +0100101 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
102 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
103 goto out_reject;
104 }
105 llist_add_tail(&remote->entry, &call_list);
106 remote->net = call->net;
107 remote->callref = new_callref++;
108 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
109 call->callref, remote->callref);
110
111 /* link remote call */
112 call->remote_ref = remote->callref;
113 remote->remote_ref = call->callref;
114
Harald Weltebf0a7c92012-08-24 16:48:21 +0200115 /* send call proceeding */
116 memset(&mncc, 0, sizeof(struct gsm_mncc));
117 mncc.callref = call->callref;
118 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
119 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
120
Harald Welte3e6376d2010-12-22 23:54:51 +0100121 /* modify mode */
122 memset(&mncc, 0, sizeof(struct gsm_mncc));
123 mncc.callref = call->callref;
Neels Hofmeyre2f24d52017-05-08 15:12:20 +0200124 DEBUGP(DMNCC, "(call %x) Modify channel mode\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100125 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100126
Harald Welte3e6376d2010-12-22 23:54:51 +0100127 /* send setup to remote */
128// setup->fields |= MNCC_F_SIGNAL;
129// setup->signal = GSM48_SIGNAL_DIALTONE;
130 setup->callref = remote->callref;
131 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100132 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100133
134out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100135 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100136 free_call(call);
137 return 0;
138}
139
140static int mncc_alert_ind(struct gsm_call *call, int msg_type,
141 struct gsm_mncc *alert)
142{
143 struct gsm_call *remote;
144
145 /* send alerting to remote */
146 if (!(remote = get_call_ref(call->remote_ref)))
147 return 0;
148 alert->callref = remote->callref;
149 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100150 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100151}
152
153static int mncc_notify_ind(struct gsm_call *call, int msg_type,
154 struct gsm_mncc *notify)
155{
156 struct gsm_call *remote;
157
158 /* send notify to remote */
159 if (!(remote = get_call_ref(call->remote_ref)))
160 return 0;
161 notify->callref = remote->callref;
162 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100163 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100164}
165
166static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
167 struct gsm_mncc *connect)
168{
Neels Hofmeyrf9773b02018-11-29 23:01:58 +0100169 struct gsm_mncc connect_ack;
Harald Welte3e6376d2010-12-22 23:54:51 +0100170 struct gsm_call *remote;
Harald Welte53d51f52015-12-03 14:59:04 +0100171 struct gsm_mncc_bridge bridge = { .msg_type = MNCC_BRIDGE };
Harald Welte3e6376d2010-12-22 23:54:51 +0100172
173 /* acknowledge connect */
174 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
175 connect_ack.callref = call->callref;
176 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100177 mncc_tx_to_cc(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
Harald Welte3e6376d2010-12-22 23:54:51 +0100178
179 /* send connect message to remote */
180 if (!(remote = get_call_ref(call->remote_ref)))
181 return 0;
182 connect->callref = remote->callref;
183 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100184 mncc_tx_to_cc(remote->net, MNCC_SETUP_RSP, connect);
Harald Welte3e6376d2010-12-22 23:54:51 +0100185
186 /* bridge tch */
Harald Welte53d51f52015-12-03 14:59:04 +0100187 bridge.callref[0] = call->callref;
188 bridge.callref[1] = call->remote_ref;
Harald Welte3e6376d2010-12-22 23:54:51 +0100189 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
190
Neels Hofmeyrf9773b02018-11-29 23:01:58 +0100191 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
Harald Welte3e6376d2010-12-22 23:54:51 +0100192}
193
194static int mncc_disc_ind(struct gsm_call *call, int msg_type,
195 struct gsm_mncc *disc)
196{
197 struct gsm_call *remote;
198
199 /* send release */
200 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
201 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100202 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100203
204 /* send disc to remote */
205 if (!(remote = get_call_ref(call->remote_ref))) {
206 return 0;
207 }
208 disc->callref = remote->callref;
209 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
210 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100211 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100212}
213
214static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
215{
216 struct gsm_call *remote;
217
218 /* send release to remote */
219 if (!(remote = get_call_ref(call->remote_ref))) {
220 free_call(call);
221 return 0;
222 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100223
Harald Welte3e6376d2010-12-22 23:54:51 +0100224 rel->callref = remote->callref;
225 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
226 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100227
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100228 /*
229 * Release this side of the call right now. Otherwise we end up
230 * in this method for the other call and will also try to release
231 * it and then we will end up with a double free and a crash
232 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100233 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100234 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100235
236 return 0;
237}
238
239static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
240{
241 free_call(call);
242 return 0;
243}
244
Harald Welte3e6376d2010-12-22 23:54:51 +0100245/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100246int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100247{
Harald Welte29b64e92010-12-23 01:07:46 +0100248 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100249 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100250 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100251 int callref;
252 struct gsm_call *call = NULL, *callt;
253 int rc = 0;
254
255 /* Special messages */
256 switch(msg_type) {
257 }
258
259 /* find callref */
260 callref = data->callref;
261 llist_for_each_entry(callt, &call_list, entry) {
262 if (callt->callref == callref) {
263 call = callt;
264 break;
265 }
266 }
267
268 /* create callref, if setup is received */
269 if (!call) {
270 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100271 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100272 /* create call */
273 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
274 struct gsm_mncc rel;
275
276 memset(&rel, 0, sizeof(struct gsm_mncc));
277 rel.callref = callref;
278 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
279 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100280 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100281 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100282 }
283 llist_add_tail(&call->entry, &call_list);
284 call->net = net;
285 call->callref = callref;
286 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
287 }
288
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100289 if (mncc_is_data_frame(msg_type)) {
Neels Hofmeyre2f24d52017-05-08 15:12:20 +0200290 LOGP(DMNCC, LOGL_ERROR, "(call %x) Received data frame, which is not supported.\n",
291 call->callref);
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100292 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100293 }
294
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100295 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
296 get_mncc_name(msg_type));
297
Harald Welte3e6376d2010-12-22 23:54:51 +0100298 switch(msg_type) {
299 case MNCC_SETUP_IND:
300 rc = mncc_setup_ind(call, msg_type, arg);
301 break;
302 case MNCC_SETUP_CNF:
303 rc = mncc_setup_cnf(call, msg_type, arg);
304 break;
305 case MNCC_SETUP_COMPL_IND:
306 break;
307 case MNCC_CALL_CONF_IND:
308 /* we now need to MODIFY the channel */
Harald Welte76556372010-12-22 23:57:45 +0100309 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100310 break;
311 case MNCC_ALERT_IND:
312 rc = mncc_alert_ind(call, msg_type, arg);
313 break;
314 case MNCC_NOTIFY_IND:
315 rc = mncc_notify_ind(call, msg_type, arg);
316 break;
317 case MNCC_DISC_IND:
318 rc = mncc_disc_ind(call, msg_type, arg);
319 break;
320 case MNCC_REL_IND:
321 case MNCC_REJ_IND:
322 rc = mncc_rel_ind(call, msg_type, arg);
323 break;
324 case MNCC_REL_CNF:
325 rc = mncc_rel_cnf(call, msg_type, arg);
326 break;
327 case MNCC_FACILITY_IND:
328 break;
329 case MNCC_START_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200330 rc = mncc_tx_to_cc(net, MNCC_START_DTMF_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100331 break;
332 case MNCC_STOP_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200333 rc = mncc_tx_to_cc(net, MNCC_STOP_DTMF_RSP, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100334 break;
335 case MNCC_MODIFY_IND:
336 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
337 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
338 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
339 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100340 rc = mncc_tx_to_cc(net, MNCC_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100341 break;
342 case MNCC_MODIFY_CNF:
343 break;
344 case MNCC_HOLD_IND:
345 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
346 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
347 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
348 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100349 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100350 break;
351 case MNCC_RETRIEVE_IND:
352 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
353 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
354 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
355 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100356 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100357 break;
Harald Welte3e6376d2010-12-22 23:54:51 +0100358 default:
359 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
360 break;
361 }
362
Harald Welte29b64e92010-12-23 01:07:46 +0100363out_free:
Holger Hans Peter Freythera8ddb082012-03-01 20:30:32 +0100364 msgb_free(msg);
Harald Welte29b64e92010-12-23 01:07:46 +0100365
Harald Welte3e6376d2010-12-22 23:54:51 +0100366 return rc;
367}