blob: ac6e7345d345c83456dddb06a4e3c086d15c74c6 [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
30#include <openbsc/gsm_04_08.h>
31#include <openbsc/debug.h>
32#include <openbsc/mncc.h>
Harald Welteab386e62011-09-01 18:18:43 +020033#include <openbsc/mncc_int.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010034#include <osmocom/core/talloc.h>
Harald Welte3e6376d2010-12-22 23:54:51 +010035#include <openbsc/gsm_data.h>
36#include <openbsc/transaction.h>
37#include <openbsc/rtp_proxy.h>
38
39void *tall_call_ctx;
40
41static LLIST_HEAD(call_list);
42
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020043static uint32_t new_callref = 0x00000001;
Harald Welte3e6376d2010-12-22 23:54:51 +010044
Harald Welteab386e62011-09-01 18:18:43 +020045struct mncc_int mncc_int = {
Andreas Eversberga83d5112013-12-07 18:32:28 +010046 .def_codec = { GSM48_CMODE_SPEECH_V1, GSM48_CMODE_SPEECH_V1 },
Harald Welteab386e62011-09-01 18:18:43 +020047};
48
Harald Welte3e6376d2010-12-22 23:54:51 +010049static void free_call(struct gsm_call *call)
50{
51 llist_del(&call->entry);
52 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
53 talloc_free(call);
54}
55
56
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020057static struct gsm_call *get_call_ref(uint32_t callref)
Harald Welte3e6376d2010-12-22 23:54:51 +010058{
59 struct gsm_call *callt;
60
61 llist_for_each_entry(callt, &call_list, entry) {
62 if (callt->callref == callref)
63 return callt;
64 }
65 return NULL;
66}
67
Harald Welte3e6376d2010-12-22 23:54:51 +010068/* on incoming call, look up database and send setup to remote subscr. */
69static int mncc_setup_ind(struct gsm_call *call, int msg_type,
70 struct gsm_mncc *setup)
71{
72 struct gsm_mncc mncc;
73 struct gsm_call *remote;
74
75 memset(&mncc, 0, sizeof(struct gsm_mncc));
76 mncc.callref = call->callref;
77
78 /* already have remote call */
79 if (call->remote_ref)
80 return 0;
81
82 /* transfer mode 1 would be packet mode, which was never specified */
83 if (setup->bearer_cap.mode != 0) {
84 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
85 "packet mode\n", call->callref);
86 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
87 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
88 goto out_reject;
89 }
90
91 /* we currently only do speech */
92 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
93 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
94 "voice calls\n", call->callref);
95 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
96 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
97 goto out_reject;
98 }
99
100 /* create remote call */
Andreas Eversbergc5e08512013-01-25 08:36:32 +0100101 if (!(remote = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte3e6376d2010-12-22 23:54:51 +0100102 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
103 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
104 goto out_reject;
105 }
106 llist_add_tail(&remote->entry, &call_list);
107 remote->net = call->net;
108 remote->callref = new_callref++;
109 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
110 call->callref, remote->callref);
111
112 /* link remote call */
113 call->remote_ref = remote->callref;
114 remote->remote_ref = call->callref;
115
Harald Weltebf0a7c92012-08-24 16:48:21 +0200116 /* send call proceeding */
117 memset(&mncc, 0, sizeof(struct gsm_mncc));
118 mncc.callref = call->callref;
119 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
120 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
121
Harald Welte3e6376d2010-12-22 23:54:51 +0100122 /* modify mode */
123 memset(&mncc, 0, sizeof(struct gsm_mncc));
124 mncc.callref = call->callref;
Neels Hofmeyre2f24d52017-05-08 15:12:20 +0200125 DEBUGP(DMNCC, "(call %x) Modify channel mode\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100126 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100127
Harald Welte3e6376d2010-12-22 23:54:51 +0100128 /* send setup to remote */
129// setup->fields |= MNCC_F_SIGNAL;
130// setup->signal = GSM48_SIGNAL_DIALTONE;
131 setup->callref = remote->callref;
132 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100133 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100134
135out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100136 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100137 free_call(call);
138 return 0;
139}
140
141static int mncc_alert_ind(struct gsm_call *call, int msg_type,
142 struct gsm_mncc *alert)
143{
144 struct gsm_call *remote;
145
146 /* send alerting to remote */
147 if (!(remote = get_call_ref(call->remote_ref)))
148 return 0;
149 alert->callref = remote->callref;
150 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100151 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100152}
153
154static int mncc_notify_ind(struct gsm_call *call, int msg_type,
155 struct gsm_mncc *notify)
156{
157 struct gsm_call *remote;
158
159 /* send notify to remote */
160 if (!(remote = get_call_ref(call->remote_ref)))
161 return 0;
162 notify->callref = remote->callref;
163 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100164 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100165}
166
167static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
168 struct gsm_mncc *connect)
169{
170 struct gsm_mncc connect_ack, frame_recv;
171 struct gsm_network *net = call->net;
172 struct gsm_call *remote;
Harald Welte53d51f52015-12-03 14:59:04 +0100173 struct gsm_mncc_bridge bridge = { .msg_type = MNCC_BRIDGE };
Harald Welte3e6376d2010-12-22 23:54:51 +0100174
175 /* acknowledge connect */
176 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
177 connect_ack.callref = call->callref;
178 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100179 mncc_tx_to_cc(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
Harald Welte3e6376d2010-12-22 23:54:51 +0100180
181 /* send connect message to remote */
182 if (!(remote = get_call_ref(call->remote_ref)))
183 return 0;
184 connect->callref = remote->callref;
185 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100186 mncc_tx_to_cc(remote->net, MNCC_SETUP_RSP, connect);
Harald Welte3e6376d2010-12-22 23:54:51 +0100187
188 /* bridge tch */
Harald Welte53d51f52015-12-03 14:59:04 +0100189 bridge.callref[0] = call->callref;
190 bridge.callref[1] = call->remote_ref;
Harald Welte3e6376d2010-12-22 23:54:51 +0100191 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
192
Harald Welte3e6376d2010-12-22 23:54:51 +0100193 /* proxy mode */
194 if (!net->handover.active) {
195 /* in the no-handover case, we can bridge, i.e. use
196 * the old RTP proxy code */
Harald Welte53d51f52015-12-03 14:59:04 +0100197 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
Harald Welte3e6376d2010-12-22 23:54:51 +0100198 } else {
199 /* in case of handover, we need to re-write the RTP
200 * SSRC, sequence and timestamp values and thus
201 * need to enable RTP receive for both directions */
202 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
203 frame_recv.callref = call->callref;
Harald Welte76556372010-12-22 23:57:45 +0100204 mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100205 frame_recv.callref = call->remote_ref;
Harald Welte76556372010-12-22 23:57:45 +0100206 return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100207 }
208}
209
210static int mncc_disc_ind(struct gsm_call *call, int msg_type,
211 struct gsm_mncc *disc)
212{
213 struct gsm_call *remote;
214
215 /* send release */
216 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
217 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100218 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100219
220 /* send disc to remote */
221 if (!(remote = get_call_ref(call->remote_ref))) {
222 return 0;
223 }
224 disc->callref = remote->callref;
225 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
226 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100227 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100228}
229
230static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
231{
232 struct gsm_call *remote;
233
234 /* send release to remote */
235 if (!(remote = get_call_ref(call->remote_ref))) {
236 free_call(call);
237 return 0;
238 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100239
Harald Welte3e6376d2010-12-22 23:54:51 +0100240 rel->callref = remote->callref;
241 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
242 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100243
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100244 /*
245 * Release this side of the call right now. Otherwise we end up
246 * in this method for the other call and will also try to release
247 * it and then we will end up with a double free and a crash
248 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100249 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100250 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100251
252 return 0;
253}
254
255static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
256{
257 free_call(call);
258 return 0;
259}
260
Harald Welte3e6376d2010-12-22 23:54:51 +0100261/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100262int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100263{
Harald Welte29b64e92010-12-23 01:07:46 +0100264 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100265 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100266 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100267 int callref;
268 struct gsm_call *call = NULL, *callt;
269 int rc = 0;
270
271 /* Special messages */
272 switch(msg_type) {
273 }
274
275 /* find callref */
276 callref = data->callref;
277 llist_for_each_entry(callt, &call_list, entry) {
278 if (callt->callref == callref) {
279 call = callt;
280 break;
281 }
282 }
283
284 /* create callref, if setup is received */
285 if (!call) {
286 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100287 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100288 /* create call */
289 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
290 struct gsm_mncc rel;
291
292 memset(&rel, 0, sizeof(struct gsm_mncc));
293 rel.callref = callref;
294 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
295 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100296 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100297 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100298 }
299 llist_add_tail(&call->entry, &call_list);
300 call->net = net;
301 call->callref = callref;
302 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
303 }
304
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100305 if (mncc_is_data_frame(msg_type)) {
Neels Hofmeyre2f24d52017-05-08 15:12:20 +0200306 LOGP(DMNCC, LOGL_ERROR, "(call %x) Received data frame, which is not supported.\n",
307 call->callref);
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100308 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100309 }
310
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100311 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
312 get_mncc_name(msg_type));
313
Harald Welte3e6376d2010-12-22 23:54:51 +0100314 switch(msg_type) {
315 case MNCC_SETUP_IND:
316 rc = mncc_setup_ind(call, msg_type, arg);
317 break;
318 case MNCC_SETUP_CNF:
319 rc = mncc_setup_cnf(call, msg_type, arg);
320 break;
321 case MNCC_SETUP_COMPL_IND:
322 break;
323 case MNCC_CALL_CONF_IND:
324 /* we now need to MODIFY the channel */
Harald Welte76556372010-12-22 23:57:45 +0100325 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100326 break;
327 case MNCC_ALERT_IND:
328 rc = mncc_alert_ind(call, msg_type, arg);
329 break;
330 case MNCC_NOTIFY_IND:
331 rc = mncc_notify_ind(call, msg_type, arg);
332 break;
333 case MNCC_DISC_IND:
334 rc = mncc_disc_ind(call, msg_type, arg);
335 break;
336 case MNCC_REL_IND:
337 case MNCC_REJ_IND:
338 rc = mncc_rel_ind(call, msg_type, arg);
339 break;
340 case MNCC_REL_CNF:
341 rc = mncc_rel_cnf(call, msg_type, arg);
342 break;
343 case MNCC_FACILITY_IND:
344 break;
345 case MNCC_START_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200346 rc = mncc_tx_to_cc(net, MNCC_START_DTMF_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100347 break;
348 case MNCC_STOP_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200349 rc = mncc_tx_to_cc(net, MNCC_STOP_DTMF_RSP, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100350 break;
351 case MNCC_MODIFY_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 MODIFY 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_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100357 break;
358 case MNCC_MODIFY_CNF:
359 break;
360 case MNCC_HOLD_IND:
361 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
362 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
363 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
364 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100365 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100366 break;
367 case MNCC_RETRIEVE_IND:
368 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
369 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
370 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
371 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100372 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100373 break;
Harald Welte3e6376d2010-12-22 23:54:51 +0100374 default:
375 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
376 break;
377 }
378
Harald Welte29b64e92010-12-23 01:07:46 +0100379out_free:
Holger Hans Peter Freythera8ddb082012-03-01 20:30:32 +0100380 msgb_free(msg);
Harald Welte29b64e92010-12-23 01:07:46 +0100381
Harald Welte3e6376d2010-12-22 23:54:51 +0100382 return rc;
383}