blob: 067cc92f86b97e62e75777c49e58e18d8af3df10 [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
Holger Hans Peter Freyther53122b02015-08-20 19:10:58 +020068uint8_t mncc_codec_for_mode(int lchan_type)
Harald Welteab386e62011-09-01 18:18:43 +020069{
70 /* FIXME: check codec capabilities of the phone */
71
Holger Hans Peter Freyther53122b02015-08-20 19:10:58 +020072 if (lchan_type != GSM_LCHAN_TCH_H)
Harald Welteab386e62011-09-01 18:18:43 +020073 return mncc_int.def_codec[0];
74 else
75 return mncc_int.def_codec[1];
76}
Harald Welte3e6376d2010-12-22 23:54:51 +010077
Holger Hans Peter Freyther53122b02015-08-20 19:10:58 +020078static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
79{
80 return mncc_codec_for_mode(setup->lchan_type);
81}
82
Harald Welte3e6376d2010-12-22 23:54:51 +010083/* on incoming call, look up database and send setup to remote subscr. */
84static int mncc_setup_ind(struct gsm_call *call, int msg_type,
85 struct gsm_mncc *setup)
86{
87 struct gsm_mncc mncc;
88 struct gsm_call *remote;
89
90 memset(&mncc, 0, sizeof(struct gsm_mncc));
91 mncc.callref = call->callref;
92
93 /* already have remote call */
94 if (call->remote_ref)
95 return 0;
96
97 /* transfer mode 1 would be packet mode, which was never specified */
98 if (setup->bearer_cap.mode != 0) {
99 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
100 "packet mode\n", call->callref);
101 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
102 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
103 goto out_reject;
104 }
105
106 /* we currently only do speech */
107 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
108 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
109 "voice calls\n", call->callref);
110 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
111 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
112 goto out_reject;
113 }
114
115 /* create remote call */
Andreas Eversbergc5e08512013-01-25 08:36:32 +0100116 if (!(remote = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte3e6376d2010-12-22 23:54:51 +0100117 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
118 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
119 goto out_reject;
120 }
121 llist_add_tail(&remote->entry, &call_list);
122 remote->net = call->net;
123 remote->callref = new_callref++;
124 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
125 call->callref, remote->callref);
126
127 /* link remote call */
128 call->remote_ref = remote->callref;
129 remote->remote_ref = call->callref;
130
Harald Weltebf0a7c92012-08-24 16:48:21 +0200131 /* send call proceeding */
132 memset(&mncc, 0, sizeof(struct gsm_mncc));
133 mncc.callref = call->callref;
134 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
135 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
136
Harald Welte3e6376d2010-12-22 23:54:51 +0100137 /* modify mode */
138 memset(&mncc, 0, sizeof(struct gsm_mncc));
139 mncc.callref = call->callref;
Harald Welteab386e62011-09-01 18:18:43 +0200140 mncc.lchan_mode = determine_lchan_mode(setup);
Max8db12e42016-04-18 23:11:18 +0200141 DEBUGP(DMNCC, "(call %x) Modify channel mode: %s\n", call->callref,
142 get_value_string(gsm48_chan_mode_names, mncc.lchan_mode));
Harald Welte76556372010-12-22 23:57:45 +0100143 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100144
Harald Welte3e6376d2010-12-22 23:54:51 +0100145 /* send setup to remote */
146// setup->fields |= MNCC_F_SIGNAL;
147// setup->signal = GSM48_SIGNAL_DIALTONE;
148 setup->callref = remote->callref;
149 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100150 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100151
152out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100153 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100154 free_call(call);
155 return 0;
156}
157
158static int mncc_alert_ind(struct gsm_call *call, int msg_type,
159 struct gsm_mncc *alert)
160{
161 struct gsm_call *remote;
162
163 /* send alerting to remote */
164 if (!(remote = get_call_ref(call->remote_ref)))
165 return 0;
166 alert->callref = remote->callref;
167 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100168 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100169}
170
171static int mncc_notify_ind(struct gsm_call *call, int msg_type,
172 struct gsm_mncc *notify)
173{
174 struct gsm_call *remote;
175
176 /* send notify to remote */
177 if (!(remote = get_call_ref(call->remote_ref)))
178 return 0;
179 notify->callref = remote->callref;
180 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100181 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100182}
183
184static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
185 struct gsm_mncc *connect)
186{
187 struct gsm_mncc connect_ack, frame_recv;
188 struct gsm_network *net = call->net;
189 struct gsm_call *remote;
Harald Welte53d51f52015-12-03 14:59:04 +0100190 struct gsm_mncc_bridge bridge = { .msg_type = MNCC_BRIDGE };
Harald Welte3e6376d2010-12-22 23:54:51 +0100191
192 /* acknowledge connect */
193 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
194 connect_ack.callref = call->callref;
195 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100196 mncc_tx_to_cc(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
Harald Welte3e6376d2010-12-22 23:54:51 +0100197
198 /* send connect message to remote */
199 if (!(remote = get_call_ref(call->remote_ref)))
200 return 0;
201 connect->callref = remote->callref;
202 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100203 mncc_tx_to_cc(remote->net, MNCC_SETUP_RSP, connect);
Harald Welte3e6376d2010-12-22 23:54:51 +0100204
205 /* bridge tch */
Harald Welte53d51f52015-12-03 14:59:04 +0100206 bridge.callref[0] = call->callref;
207 bridge.callref[1] = call->remote_ref;
Harald Welte3e6376d2010-12-22 23:54:51 +0100208 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
209
210 /* in direct mode, we always have to bridge the channels */
211 if (ipacc_rtp_direct)
Harald Welte53d51f52015-12-03 14:59:04 +0100212 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
Harald Welte3e6376d2010-12-22 23:54:51 +0100213
214 /* proxy mode */
215 if (!net->handover.active) {
216 /* in the no-handover case, we can bridge, i.e. use
217 * the old RTP proxy code */
Harald Welte53d51f52015-12-03 14:59:04 +0100218 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
Harald Welte3e6376d2010-12-22 23:54:51 +0100219 } else {
220 /* in case of handover, we need to re-write the RTP
221 * SSRC, sequence and timestamp values and thus
222 * need to enable RTP receive for both directions */
223 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
224 frame_recv.callref = call->callref;
Harald Welte76556372010-12-22 23:57:45 +0100225 mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100226 frame_recv.callref = call->remote_ref;
Harald Welte76556372010-12-22 23:57:45 +0100227 return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100228 }
229}
230
231static int mncc_disc_ind(struct gsm_call *call, int msg_type,
232 struct gsm_mncc *disc)
233{
234 struct gsm_call *remote;
235
236 /* send release */
237 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
238 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100239 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100240
241 /* send disc to remote */
242 if (!(remote = get_call_ref(call->remote_ref))) {
243 return 0;
244 }
245 disc->callref = remote->callref;
246 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
247 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100248 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100249}
250
251static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
252{
253 struct gsm_call *remote;
254
255 /* send release to remote */
256 if (!(remote = get_call_ref(call->remote_ref))) {
257 free_call(call);
258 return 0;
259 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100260
Harald Welte3e6376d2010-12-22 23:54:51 +0100261 rel->callref = remote->callref;
262 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
263 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100264
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100265 /*
266 * Release this side of the call right now. Otherwise we end up
267 * in this method for the other call and will also try to release
268 * it and then we will end up with a double free and a crash
269 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100270 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100271 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100272
273 return 0;
274}
275
276static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
277{
278 free_call(call);
279 return 0;
280}
281
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100282/* receiving a (speech) traffic frame from the BSC code */
283static int mncc_rcv_data(struct gsm_call *call, int msg_type,
Harald Welte3e6376d2010-12-22 23:54:51 +0100284 struct gsm_data_frame *dfr)
285{
286 struct gsm_trans *remote_trans;
287
288 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
289
290 /* this shouldn't really happen */
291 if (!remote_trans || !remote_trans->conn) {
292 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
293 return -EIO;
294 }
295
296 /* RTP socket of remote end has meanwhile died */
297 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
298 return -EIO;
299
300 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
301}
302
303
304/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100305int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100306{
Harald Welte29b64e92010-12-23 01:07:46 +0100307 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100308 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100309 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100310 int callref;
311 struct gsm_call *call = NULL, *callt;
312 int rc = 0;
313
314 /* Special messages */
315 switch(msg_type) {
316 }
317
318 /* find callref */
319 callref = data->callref;
320 llist_for_each_entry(callt, &call_list, entry) {
321 if (callt->callref == callref) {
322 call = callt;
323 break;
324 }
325 }
326
327 /* create callref, if setup is received */
328 if (!call) {
329 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100330 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100331 /* create call */
332 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
333 struct gsm_mncc rel;
334
335 memset(&rel, 0, sizeof(struct gsm_mncc));
336 rel.callref = callref;
337 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
338 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100339 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100340 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100341 }
342 llist_add_tail(&call->entry, &call_list);
343 call->net = net;
344 call->callref = callref;
345 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
346 }
347
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100348 if (mncc_is_data_frame(msg_type)) {
349 rc = mncc_rcv_data(call, msg_type, arg);
350 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100351 }
352
Andreas Eversberg9acbe4c2013-03-11 08:12:43 +0100353 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
354 get_mncc_name(msg_type));
355
Harald Welte3e6376d2010-12-22 23:54:51 +0100356 switch(msg_type) {
357 case MNCC_SETUP_IND:
358 rc = mncc_setup_ind(call, msg_type, arg);
359 break;
360 case MNCC_SETUP_CNF:
361 rc = mncc_setup_cnf(call, msg_type, arg);
362 break;
363 case MNCC_SETUP_COMPL_IND:
364 break;
365 case MNCC_CALL_CONF_IND:
366 /* we now need to MODIFY the channel */
Harald Welteab386e62011-09-01 18:18:43 +0200367 data->lchan_mode = determine_lchan_mode(data);
Harald Welte76556372010-12-22 23:57:45 +0100368 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100369 break;
370 case MNCC_ALERT_IND:
371 rc = mncc_alert_ind(call, msg_type, arg);
372 break;
373 case MNCC_NOTIFY_IND:
374 rc = mncc_notify_ind(call, msg_type, arg);
375 break;
376 case MNCC_DISC_IND:
377 rc = mncc_disc_ind(call, msg_type, arg);
378 break;
379 case MNCC_REL_IND:
380 case MNCC_REJ_IND:
381 rc = mncc_rel_ind(call, msg_type, arg);
382 break;
383 case MNCC_REL_CNF:
384 rc = mncc_rel_cnf(call, msg_type, arg);
385 break;
386 case MNCC_FACILITY_IND:
387 break;
388 case MNCC_START_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200389 rc = mncc_tx_to_cc(net, MNCC_START_DTMF_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100390 break;
391 case MNCC_STOP_DTMF_IND:
Harald Welte0c566a42016-10-29 22:23:19 +0200392 rc = mncc_tx_to_cc(net, MNCC_STOP_DTMF_RSP, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100393 break;
394 case MNCC_MODIFY_IND:
395 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
396 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
397 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
398 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100399 rc = mncc_tx_to_cc(net, MNCC_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100400 break;
401 case MNCC_MODIFY_CNF:
402 break;
403 case MNCC_HOLD_IND:
404 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
405 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
406 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
407 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100408 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100409 break;
410 case MNCC_RETRIEVE_IND:
411 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
412 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
413 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
414 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100415 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100416 break;
Harald Welte3e6376d2010-12-22 23:54:51 +0100417 default:
418 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
419 break;
420 }
421
Harald Welte29b64e92010-12-23 01:07:46 +0100422out_free:
Holger Hans Peter Freythera8ddb082012-03-01 20:30:32 +0100423 msgb_free(msg);
Harald Welte29b64e92010-12-23 01:07:46 +0100424
Harald Welte3e6376d2010-12-22 23:54:51 +0100425 return rc;
426}