blob: 0226b27489c52f52ec4738fa0305fb82d74c64fc [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>
29#include <sys/types.h>
30
31#include <openbsc/gsm_04_08.h>
32#include <openbsc/debug.h>
33#include <openbsc/mncc.h>
34#include <osmocore/talloc.h>
35#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
43static u_int32_t new_callref = 0x00000001;
44
45static void free_call(struct gsm_call *call)
46{
47 llist_del(&call->entry);
48 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
49 talloc_free(call);
50}
51
52
53static struct gsm_call *get_call_ref(u_int32_t callref)
54{
55 struct gsm_call *callt;
56
57 llist_for_each_entry(callt, &call_list, entry) {
58 if (callt->callref == callref)
59 return callt;
60 }
61 return NULL;
62}
63
64
65/* on incoming call, look up database and send setup to remote subscr. */
66static int mncc_setup_ind(struct gsm_call *call, int msg_type,
67 struct gsm_mncc *setup)
68{
69 struct gsm_mncc mncc;
70 struct gsm_call *remote;
71
72 memset(&mncc, 0, sizeof(struct gsm_mncc));
73 mncc.callref = call->callref;
74
75 /* already have remote call */
76 if (call->remote_ref)
77 return 0;
78
79 /* transfer mode 1 would be packet mode, which was never specified */
80 if (setup->bearer_cap.mode != 0) {
81 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
82 "packet mode\n", call->callref);
83 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
84 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
85 goto out_reject;
86 }
87
88 /* we currently only do speech */
89 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
90 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
91 "voice calls\n", call->callref);
92 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
93 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
94 goto out_reject;
95 }
96
97 /* create remote call */
98 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
99 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
100 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
101 goto out_reject;
102 }
103 llist_add_tail(&remote->entry, &call_list);
104 remote->net = call->net;
105 remote->callref = new_callref++;
106 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
107 call->callref, remote->callref);
108
109 /* link remote call */
110 call->remote_ref = remote->callref;
111 remote->remote_ref = call->callref;
112
113 /* modify mode */
114 memset(&mncc, 0, sizeof(struct gsm_mncc));
115 mncc.callref = call->callref;
116 mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
117 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100118 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100119
120 /* send call proceeding */
121 memset(&mncc, 0, sizeof(struct gsm_mncc));
122 mncc.callref = call->callref;
123 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100124 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100125
126 /* send setup to remote */
127// setup->fields |= MNCC_F_SIGNAL;
128// setup->signal = GSM48_SIGNAL_DIALTONE;
129 setup->callref = remote->callref;
130 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100131 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100132
133out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100134 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100135 free_call(call);
136 return 0;
137}
138
139static int mncc_alert_ind(struct gsm_call *call, int msg_type,
140 struct gsm_mncc *alert)
141{
142 struct gsm_call *remote;
143
144 /* send alerting to remote */
145 if (!(remote = get_call_ref(call->remote_ref)))
146 return 0;
147 alert->callref = remote->callref;
148 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100149 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100150}
151
152static int mncc_notify_ind(struct gsm_call *call, int msg_type,
153 struct gsm_mncc *notify)
154{
155 struct gsm_call *remote;
156
157 /* send notify to remote */
158 if (!(remote = get_call_ref(call->remote_ref)))
159 return 0;
160 notify->callref = remote->callref;
161 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100162 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100163}
164
165static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
166 struct gsm_mncc *connect)
167{
168 struct gsm_mncc connect_ack, frame_recv;
169 struct gsm_network *net = call->net;
170 struct gsm_call *remote;
171 u_int32_t refs[2];
172
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 */
187 refs[0] = call->callref;
188 refs[1] = call->remote_ref;
189 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
190
191 /* in direct mode, we always have to bridge the channels */
192 if (ipacc_rtp_direct)
Harald Welte76556372010-12-22 23:57:45 +0100193 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100194
195 /* proxy mode */
196 if (!net->handover.active) {
197 /* in the no-handover case, we can bridge, i.e. use
198 * the old RTP proxy code */
Harald Welte76556372010-12-22 23:57:45 +0100199 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100200 } else {
201 /* in case of handover, we need to re-write the RTP
202 * SSRC, sequence and timestamp values and thus
203 * need to enable RTP receive for both directions */
204 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
205 frame_recv.callref = call->callref;
Harald Welte76556372010-12-22 23:57:45 +0100206 mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100207 frame_recv.callref = call->remote_ref;
Harald Welte76556372010-12-22 23:57:45 +0100208 return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100209 }
210}
211
212static int mncc_disc_ind(struct gsm_call *call, int msg_type,
213 struct gsm_mncc *disc)
214{
215 struct gsm_call *remote;
216
217 /* send release */
218 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
219 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100220 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100221
222 /* send disc to remote */
223 if (!(remote = get_call_ref(call->remote_ref))) {
224 return 0;
225 }
226 disc->callref = remote->callref;
227 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
228 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100229 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100230}
231
232static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
233{
234 struct gsm_call *remote;
235
236 /* send release to remote */
237 if (!(remote = get_call_ref(call->remote_ref))) {
238 free_call(call);
239 return 0;
240 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100241
Harald Welte3e6376d2010-12-22 23:54:51 +0100242 rel->callref = remote->callref;
243 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
244 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100245
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100246 /*
247 * Release this side of the call right now. Otherwise we end up
248 * in this method for the other call and will also try to release
249 * it and then we will end up with a double free and a crash
250 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100251 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100252 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100253
254 return 0;
255}
256
257static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
258{
259 free_call(call);
260 return 0;
261}
262
263/* receiving a TCH/F frame from the BSC code */
264static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
265 struct gsm_data_frame *dfr)
266{
267 struct gsm_trans *remote_trans;
268
269 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
270
271 /* this shouldn't really happen */
272 if (!remote_trans || !remote_trans->conn) {
273 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
274 return -EIO;
275 }
276
277 /* RTP socket of remote end has meanwhile died */
278 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
279 return -EIO;
280
281 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
282}
283
284
285/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100286int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100287{
Harald Welte29b64e92010-12-23 01:07:46 +0100288 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100289 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100290 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100291 int callref;
292 struct gsm_call *call = NULL, *callt;
293 int rc = 0;
294
295 /* Special messages */
296 switch(msg_type) {
297 }
298
299 /* find callref */
300 callref = data->callref;
301 llist_for_each_entry(callt, &call_list, entry) {
302 if (callt->callref == callref) {
303 call = callt;
304 break;
305 }
306 }
307
308 /* create callref, if setup is received */
309 if (!call) {
310 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100311 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100312 /* create call */
313 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
314 struct gsm_mncc rel;
315
316 memset(&rel, 0, sizeof(struct gsm_mncc));
317 rel.callref = callref;
318 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
319 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100320 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100321 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100322 }
323 llist_add_tail(&call->entry, &call_list);
324 call->net = net;
325 call->callref = callref;
326 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
327 }
328
329 switch (msg_type) {
330 case GSM_TCHF_FRAME:
331 case GSM_TCHF_FRAME_EFR:
332 break;
333 default:
334 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
335 get_mncc_name(msg_type));
336 break;
337 }
338
339 switch(msg_type) {
340 case MNCC_SETUP_IND:
341 rc = mncc_setup_ind(call, msg_type, arg);
342 break;
343 case MNCC_SETUP_CNF:
344 rc = mncc_setup_cnf(call, msg_type, arg);
345 break;
346 case MNCC_SETUP_COMPL_IND:
347 break;
348 case MNCC_CALL_CONF_IND:
349 /* we now need to MODIFY the channel */
350 data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
Harald Welte76556372010-12-22 23:57:45 +0100351 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100352 break;
353 case MNCC_ALERT_IND:
354 rc = mncc_alert_ind(call, msg_type, arg);
355 break;
356 case MNCC_NOTIFY_IND:
357 rc = mncc_notify_ind(call, msg_type, arg);
358 break;
359 case MNCC_DISC_IND:
360 rc = mncc_disc_ind(call, msg_type, arg);
361 break;
362 case MNCC_REL_IND:
363 case MNCC_REJ_IND:
364 rc = mncc_rel_ind(call, msg_type, arg);
365 break;
366 case MNCC_REL_CNF:
367 rc = mncc_rel_cnf(call, msg_type, arg);
368 break;
369 case MNCC_FACILITY_IND:
370 break;
371 case MNCC_START_DTMF_IND:
372 break;
373 case MNCC_STOP_DTMF_IND:
374 break;
375 case MNCC_MODIFY_IND:
376 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
377 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
378 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
379 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100380 rc = mncc_tx_to_cc(net, MNCC_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100381 break;
382 case MNCC_MODIFY_CNF:
383 break;
384 case MNCC_HOLD_IND:
385 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
386 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
387 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
388 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100389 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100390 break;
391 case MNCC_RETRIEVE_IND:
392 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
393 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
394 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
395 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100396 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100397 break;
398 case GSM_TCHF_FRAME:
399 case GSM_TCHF_FRAME_EFR:
400 rc = mncc_rcv_tchf(call, msg_type, arg);
401 break;
402 default:
403 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
404 break;
405 }
406
Harald Welte29b64e92010-12-23 01:07:46 +0100407out_free:
408 talloc_free(msg);
409
Harald Welte3e6376d2010-12-22 23:54:51 +0100410 return rc;
411}