blob: 105f1dd9610fdf427fb1944771e529eaabaabb0a [file] [log] [blame]
Harald Welte3e6376d2010-12-22 23:54:51 +01001/* mncc_builtin.c - default, minimal built-in MNCC Application for
2 * standalone bsc_hack (netowrk-in-the-box mode) */
3
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>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010033#include <osmocom/core/talloc.h>
Harald Welte3e6376d2010-12-22 23:54:51 +010034#include <openbsc/gsm_data.h>
35#include <openbsc/transaction.h>
36#include <openbsc/rtp_proxy.h>
37
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
44static void free_call(struct gsm_call *call)
45{
46 llist_del(&call->entry);
47 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
48 talloc_free(call);
49}
50
51
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020052static struct gsm_call *get_call_ref(uint32_t callref)
Harald Welte3e6376d2010-12-22 23:54:51 +010053{
54 struct gsm_call *callt;
55
56 llist_for_each_entry(callt, &call_list, entry) {
57 if (callt->callref == callref)
58 return callt;
59 }
60 return NULL;
61}
62
63
64/* on incoming call, look up database and send setup to remote subscr. */
65static int mncc_setup_ind(struct gsm_call *call, int msg_type,
66 struct gsm_mncc *setup)
67{
68 struct gsm_mncc mncc;
69 struct gsm_call *remote;
70
71 memset(&mncc, 0, sizeof(struct gsm_mncc));
72 mncc.callref = call->callref;
73
74 /* already have remote call */
75 if (call->remote_ref)
76 return 0;
77
78 /* transfer mode 1 would be packet mode, which was never specified */
79 if (setup->bearer_cap.mode != 0) {
80 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
81 "packet mode\n", call->callref);
82 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
83 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
84 goto out_reject;
85 }
86
87 /* we currently only do speech */
88 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
89 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
90 "voice calls\n", call->callref);
91 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
92 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
93 goto out_reject;
94 }
95
96 /* create remote call */
97 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
98 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
99 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
100 goto out_reject;
101 }
102 llist_add_tail(&remote->entry, &call_list);
103 remote->net = call->net;
104 remote->callref = new_callref++;
105 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
106 call->callref, remote->callref);
107
108 /* link remote call */
109 call->remote_ref = remote->callref;
110 remote->remote_ref = call->callref;
111
112 /* modify mode */
113 memset(&mncc, 0, sizeof(struct gsm_mncc));
114 mncc.callref = call->callref;
115 mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
116 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100117 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100118
119 /* send call proceeding */
120 memset(&mncc, 0, sizeof(struct gsm_mncc));
121 mncc.callref = call->callref;
122 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100123 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100124
125 /* send setup to remote */
126// setup->fields |= MNCC_F_SIGNAL;
127// setup->signal = GSM48_SIGNAL_DIALTONE;
128 setup->callref = remote->callref;
129 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100130 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100131
132out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100133 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100134 free_call(call);
135 return 0;
136}
137
138static int mncc_alert_ind(struct gsm_call *call, int msg_type,
139 struct gsm_mncc *alert)
140{
141 struct gsm_call *remote;
142
143 /* send alerting to remote */
144 if (!(remote = get_call_ref(call->remote_ref)))
145 return 0;
146 alert->callref = remote->callref;
147 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100148 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100149}
150
151static int mncc_notify_ind(struct gsm_call *call, int msg_type,
152 struct gsm_mncc *notify)
153{
154 struct gsm_call *remote;
155
156 /* send notify to remote */
157 if (!(remote = get_call_ref(call->remote_ref)))
158 return 0;
159 notify->callref = remote->callref;
160 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100161 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100162}
163
164static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
165 struct gsm_mncc *connect)
166{
167 struct gsm_mncc connect_ack, frame_recv;
168 struct gsm_network *net = call->net;
169 struct gsm_call *remote;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200170 uint32_t refs[2];
Harald Welte3e6376d2010-12-22 23:54:51 +0100171
172 /* acknowledge connect */
173 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
174 connect_ack.callref = call->callref;
175 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100176 mncc_tx_to_cc(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
Harald Welte3e6376d2010-12-22 23:54:51 +0100177
178 /* send connect message to remote */
179 if (!(remote = get_call_ref(call->remote_ref)))
180 return 0;
181 connect->callref = remote->callref;
182 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100183 mncc_tx_to_cc(remote->net, MNCC_SETUP_RSP, connect);
Harald Welte3e6376d2010-12-22 23:54:51 +0100184
185 /* bridge tch */
186 refs[0] = call->callref;
187 refs[1] = call->remote_ref;
188 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
189
190 /* in direct mode, we always have to bridge the channels */
191 if (ipacc_rtp_direct)
Harald Welte76556372010-12-22 23:57:45 +0100192 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100193
194 /* proxy mode */
195 if (!net->handover.active) {
196 /* in the no-handover case, we can bridge, i.e. use
197 * the old RTP proxy code */
Harald Welte76556372010-12-22 23:57:45 +0100198 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100199 } else {
200 /* in case of handover, we need to re-write the RTP
201 * SSRC, sequence and timestamp values and thus
202 * need to enable RTP receive for both directions */
203 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
204 frame_recv.callref = call->callref;
Harald Welte76556372010-12-22 23:57:45 +0100205 mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100206 frame_recv.callref = call->remote_ref;
Harald Welte76556372010-12-22 23:57:45 +0100207 return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100208 }
209}
210
211static int mncc_disc_ind(struct gsm_call *call, int msg_type,
212 struct gsm_mncc *disc)
213{
214 struct gsm_call *remote;
215
216 /* send release */
217 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
218 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100219 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100220
221 /* send disc to remote */
222 if (!(remote = get_call_ref(call->remote_ref))) {
223 return 0;
224 }
225 disc->callref = remote->callref;
226 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
227 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100228 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100229}
230
231static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
232{
233 struct gsm_call *remote;
234
235 /* send release to remote */
236 if (!(remote = get_call_ref(call->remote_ref))) {
237 free_call(call);
238 return 0;
239 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100240
Harald Welte3e6376d2010-12-22 23:54:51 +0100241 rel->callref = remote->callref;
242 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
243 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100244
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100245 /*
246 * Release this side of the call right now. Otherwise we end up
247 * in this method for the other call and will also try to release
248 * it and then we will end up with a double free and a crash
249 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100250 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100251 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100252
253 return 0;
254}
255
256static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
257{
258 free_call(call);
259 return 0;
260}
261
262/* receiving a TCH/F frame from the BSC code */
263static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
264 struct gsm_data_frame *dfr)
265{
266 struct gsm_trans *remote_trans;
267
268 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
269
270 /* this shouldn't really happen */
271 if (!remote_trans || !remote_trans->conn) {
272 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
273 return -EIO;
274 }
275
276 /* RTP socket of remote end has meanwhile died */
277 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
278 return -EIO;
279
280 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
281}
282
283
284/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100285int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100286{
Harald Welte29b64e92010-12-23 01:07:46 +0100287 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100288 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100289 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100290 int callref;
291 struct gsm_call *call = NULL, *callt;
292 int rc = 0;
293
294 /* Special messages */
295 switch(msg_type) {
296 }
297
298 /* find callref */
299 callref = data->callref;
300 llist_for_each_entry(callt, &call_list, entry) {
301 if (callt->callref == callref) {
302 call = callt;
303 break;
304 }
305 }
306
307 /* create callref, if setup is received */
308 if (!call) {
309 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100310 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100311 /* create call */
312 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
313 struct gsm_mncc rel;
314
315 memset(&rel, 0, sizeof(struct gsm_mncc));
316 rel.callref = callref;
317 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
318 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100319 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100320 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100321 }
322 llist_add_tail(&call->entry, &call_list);
323 call->net = net;
324 call->callref = callref;
325 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
326 }
327
328 switch (msg_type) {
329 case GSM_TCHF_FRAME:
330 case GSM_TCHF_FRAME_EFR:
331 break;
332 default:
333 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
334 get_mncc_name(msg_type));
335 break;
336 }
337
338 switch(msg_type) {
339 case MNCC_SETUP_IND:
340 rc = mncc_setup_ind(call, msg_type, arg);
341 break;
342 case MNCC_SETUP_CNF:
343 rc = mncc_setup_cnf(call, msg_type, arg);
344 break;
345 case MNCC_SETUP_COMPL_IND:
346 break;
347 case MNCC_CALL_CONF_IND:
348 /* we now need to MODIFY the channel */
349 data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
Harald Welte76556372010-12-22 23:57:45 +0100350 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100351 break;
352 case MNCC_ALERT_IND:
353 rc = mncc_alert_ind(call, msg_type, arg);
354 break;
355 case MNCC_NOTIFY_IND:
356 rc = mncc_notify_ind(call, msg_type, arg);
357 break;
358 case MNCC_DISC_IND:
359 rc = mncc_disc_ind(call, msg_type, arg);
360 break;
361 case MNCC_REL_IND:
362 case MNCC_REJ_IND:
363 rc = mncc_rel_ind(call, msg_type, arg);
364 break;
365 case MNCC_REL_CNF:
366 rc = mncc_rel_cnf(call, msg_type, arg);
367 break;
368 case MNCC_FACILITY_IND:
369 break;
370 case MNCC_START_DTMF_IND:
371 break;
372 case MNCC_STOP_DTMF_IND:
373 break;
374 case MNCC_MODIFY_IND:
375 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
376 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
377 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
378 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100379 rc = mncc_tx_to_cc(net, MNCC_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100380 break;
381 case MNCC_MODIFY_CNF:
382 break;
383 case MNCC_HOLD_IND:
384 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
385 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
386 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
387 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100388 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100389 break;
390 case MNCC_RETRIEVE_IND:
391 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
392 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
393 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
394 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100395 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100396 break;
397 case GSM_TCHF_FRAME:
398 case GSM_TCHF_FRAME_EFR:
399 rc = mncc_rcv_tchf(call, msg_type, arg);
400 break;
401 default:
402 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
403 break;
404 }
405
Harald Welte29b64e92010-12-23 01:07:46 +0100406out_free:
407 talloc_free(msg);
408
Harald Welte3e6376d2010-12-22 23:54:51 +0100409 return rc;
410}