blob: 31d9b4325b4fdefe3b1bd309ec31bf72fd5bf635 [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>
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 = {
46 .def_codec = { GSM48_CMODE_SPEECH_EFR, GSM48_CMODE_SPEECH_V1 },
47};
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 Welteab386e62011-09-01 18:18:43 +020068static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
69{
70 /* FIXME: check codec capabilities of the phone */
71
72 if (setup->lchan_type == GSM_LCHAN_TCH_F)
73 return mncc_int.def_codec[0];
74 else
75 return mncc_int.def_codec[1];
76}
Harald Welte3e6376d2010-12-22 23:54:51 +010077
78/* on incoming call, look up database and send setup to remote subscr. */
79static int mncc_setup_ind(struct gsm_call *call, int msg_type,
80 struct gsm_mncc *setup)
81{
82 struct gsm_mncc mncc;
83 struct gsm_call *remote;
84
85 memset(&mncc, 0, sizeof(struct gsm_mncc));
86 mncc.callref = call->callref;
87
88 /* already have remote call */
89 if (call->remote_ref)
90 return 0;
91
92 /* transfer mode 1 would be packet mode, which was never specified */
93 if (setup->bearer_cap.mode != 0) {
94 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
95 "packet mode\n", call->callref);
96 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
97 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
98 goto out_reject;
99 }
100
101 /* we currently only do speech */
102 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
103 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
104 "voice calls\n", call->callref);
105 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
106 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
107 goto out_reject;
108 }
109
110 /* create remote call */
111 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
112 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
113 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
114 goto out_reject;
115 }
116 llist_add_tail(&remote->entry, &call_list);
117 remote->net = call->net;
118 remote->callref = new_callref++;
119 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
120 call->callref, remote->callref);
121
122 /* link remote call */
123 call->remote_ref = remote->callref;
124 remote->remote_ref = call->callref;
125
126 /* modify mode */
127 memset(&mncc, 0, sizeof(struct gsm_mncc));
128 mncc.callref = call->callref;
Harald Welteab386e62011-09-01 18:18:43 +0200129 mncc.lchan_mode = determine_lchan_mode(setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100130 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100131 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100132
133 /* send call proceeding */
134 memset(&mncc, 0, sizeof(struct gsm_mncc));
135 mncc.callref = call->callref;
136 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100137 mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100138
139 /* send setup to remote */
140// setup->fields |= MNCC_F_SIGNAL;
141// setup->signal = GSM48_SIGNAL_DIALTONE;
142 setup->callref = remote->callref;
143 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100144 return mncc_tx_to_cc(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte3e6376d2010-12-22 23:54:51 +0100145
146out_reject:
Harald Welte76556372010-12-22 23:57:45 +0100147 mncc_tx_to_cc(call->net, MNCC_REJ_REQ, &mncc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100148 free_call(call);
149 return 0;
150}
151
152static int mncc_alert_ind(struct gsm_call *call, int msg_type,
153 struct gsm_mncc *alert)
154{
155 struct gsm_call *remote;
156
157 /* send alerting to remote */
158 if (!(remote = get_call_ref(call->remote_ref)))
159 return 0;
160 alert->callref = remote->callref;
161 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100162 return mncc_tx_to_cc(remote->net, MNCC_ALERT_REQ, alert);
Harald Welte3e6376d2010-12-22 23:54:51 +0100163}
164
165static int mncc_notify_ind(struct gsm_call *call, int msg_type,
166 struct gsm_mncc *notify)
167{
168 struct gsm_call *remote;
169
170 /* send notify to remote */
171 if (!(remote = get_call_ref(call->remote_ref)))
172 return 0;
173 notify->callref = remote->callref;
174 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100175 return mncc_tx_to_cc(remote->net, MNCC_NOTIFY_REQ, notify);
Harald Welte3e6376d2010-12-22 23:54:51 +0100176}
177
178static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
179 struct gsm_mncc *connect)
180{
181 struct gsm_mncc connect_ack, frame_recv;
182 struct gsm_network *net = call->net;
183 struct gsm_call *remote;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200184 uint32_t refs[2];
Harald Welte3e6376d2010-12-22 23:54:51 +0100185
186 /* acknowledge connect */
187 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
188 connect_ack.callref = call->callref;
189 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100190 mncc_tx_to_cc(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
Harald Welte3e6376d2010-12-22 23:54:51 +0100191
192 /* send connect message to remote */
193 if (!(remote = get_call_ref(call->remote_ref)))
194 return 0;
195 connect->callref = remote->callref;
196 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
Harald Welte76556372010-12-22 23:57:45 +0100197 mncc_tx_to_cc(remote->net, MNCC_SETUP_RSP, connect);
Harald Welte3e6376d2010-12-22 23:54:51 +0100198
199 /* bridge tch */
200 refs[0] = call->callref;
201 refs[1] = call->remote_ref;
202 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
203
204 /* in direct mode, we always have to bridge the channels */
205 if (ipacc_rtp_direct)
Harald Welte76556372010-12-22 23:57:45 +0100206 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100207
208 /* proxy mode */
209 if (!net->handover.active) {
210 /* in the no-handover case, we can bridge, i.e. use
211 * the old RTP proxy code */
Harald Welte76556372010-12-22 23:57:45 +0100212 return mncc_tx_to_cc(call->net, MNCC_BRIDGE, refs);
Harald Welte3e6376d2010-12-22 23:54:51 +0100213 } else {
214 /* in case of handover, we need to re-write the RTP
215 * SSRC, sequence and timestamp values and thus
216 * need to enable RTP receive for both directions */
217 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
218 frame_recv.callref = call->callref;
Harald Welte76556372010-12-22 23:57:45 +0100219 mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100220 frame_recv.callref = call->remote_ref;
Harald Welte76556372010-12-22 23:57:45 +0100221 return mncc_tx_to_cc(call->net, MNCC_FRAME_RECV, &frame_recv);
Harald Welte3e6376d2010-12-22 23:54:51 +0100222 }
223}
224
225static int mncc_disc_ind(struct gsm_call *call, int msg_type,
226 struct gsm_mncc *disc)
227{
228 struct gsm_call *remote;
229
230 /* send release */
231 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
232 call->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100233 mncc_tx_to_cc(call->net, MNCC_REL_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100234
235 /* send disc to remote */
236 if (!(remote = get_call_ref(call->remote_ref))) {
237 return 0;
238 }
239 disc->callref = remote->callref;
240 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
241 remote->callref, disc->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100242 return mncc_tx_to_cc(remote->net, MNCC_DISC_REQ, disc);
Harald Welte3e6376d2010-12-22 23:54:51 +0100243}
244
245static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
246{
247 struct gsm_call *remote;
248
249 /* send release to remote */
250 if (!(remote = get_call_ref(call->remote_ref))) {
251 free_call(call);
252 return 0;
253 }
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100254
Harald Welte3e6376d2010-12-22 23:54:51 +0100255 rel->callref = remote->callref;
256 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
257 call->callref, rel->cause.value);
Harald Welte3e6376d2010-12-22 23:54:51 +0100258
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100259 /*
260 * Release this side of the call right now. Otherwise we end up
261 * in this method for the other call and will also try to release
262 * it and then we will end up with a double free and a crash
263 */
Harald Welte3e6376d2010-12-22 23:54:51 +0100264 free_call(call);
Holger Hans Peter Freythera61c7092011-01-27 15:05:45 +0100265 mncc_tx_to_cc(remote->net, MNCC_REL_REQ, rel);
Harald Welte3e6376d2010-12-22 23:54:51 +0100266
267 return 0;
268}
269
270static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
271{
272 free_call(call);
273 return 0;
274}
275
276/* receiving a TCH/F frame from the BSC code */
277static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
278 struct gsm_data_frame *dfr)
279{
280 struct gsm_trans *remote_trans;
281
282 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
283
284 /* this shouldn't really happen */
285 if (!remote_trans || !remote_trans->conn) {
286 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
287 return -EIO;
288 }
289
290 /* RTP socket of remote end has meanwhile died */
291 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
292 return -EIO;
293
294 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
295}
296
297
298/* Internal MNCC handler input function (from CC -> MNCC -> here) */
Harald Welte29b64e92010-12-23 01:07:46 +0100299int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
Harald Welte3e6376d2010-12-22 23:54:51 +0100300{
Harald Welte29b64e92010-12-23 01:07:46 +0100301 void *arg = msgb_data(msg);
Harald Welte3e6376d2010-12-22 23:54:51 +0100302 struct gsm_mncc *data = arg;
Harald Welte29b64e92010-12-23 01:07:46 +0100303 int msg_type = data->msg_type;
Harald Welte3e6376d2010-12-22 23:54:51 +0100304 int callref;
305 struct gsm_call *call = NULL, *callt;
306 int rc = 0;
307
308 /* Special messages */
309 switch(msg_type) {
310 }
311
312 /* find callref */
313 callref = data->callref;
314 llist_for_each_entry(callt, &call_list, entry) {
315 if (callt->callref == callref) {
316 call = callt;
317 break;
318 }
319 }
320
321 /* create callref, if setup is received */
322 if (!call) {
323 if (msg_type != MNCC_SETUP_IND)
Harald Welte29b64e92010-12-23 01:07:46 +0100324 goto out_free; /* drop */
Harald Welte3e6376d2010-12-22 23:54:51 +0100325 /* create call */
326 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
327 struct gsm_mncc rel;
328
329 memset(&rel, 0, sizeof(struct gsm_mncc));
330 rel.callref = callref;
331 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
332 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte76556372010-12-22 23:57:45 +0100333 mncc_tx_to_cc(net, MNCC_REL_REQ, &rel);
Harald Welte29b64e92010-12-23 01:07:46 +0100334 goto out_free;
Harald Welte3e6376d2010-12-22 23:54:51 +0100335 }
336 llist_add_tail(&call->entry, &call_list);
337 call->net = net;
338 call->callref = callref;
339 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
340 }
341
342 switch (msg_type) {
343 case GSM_TCHF_FRAME:
344 case GSM_TCHF_FRAME_EFR:
345 break;
346 default:
347 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
348 get_mncc_name(msg_type));
349 break;
350 }
351
352 switch(msg_type) {
353 case MNCC_SETUP_IND:
354 rc = mncc_setup_ind(call, msg_type, arg);
355 break;
356 case MNCC_SETUP_CNF:
357 rc = mncc_setup_cnf(call, msg_type, arg);
358 break;
359 case MNCC_SETUP_COMPL_IND:
360 break;
361 case MNCC_CALL_CONF_IND:
362 /* we now need to MODIFY the channel */
Harald Welteab386e62011-09-01 18:18:43 +0200363 data->lchan_mode = determine_lchan_mode(data);
Harald Welte76556372010-12-22 23:57:45 +0100364 mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100365 break;
366 case MNCC_ALERT_IND:
367 rc = mncc_alert_ind(call, msg_type, arg);
368 break;
369 case MNCC_NOTIFY_IND:
370 rc = mncc_notify_ind(call, msg_type, arg);
371 break;
372 case MNCC_DISC_IND:
373 rc = mncc_disc_ind(call, msg_type, arg);
374 break;
375 case MNCC_REL_IND:
376 case MNCC_REJ_IND:
377 rc = mncc_rel_ind(call, msg_type, arg);
378 break;
379 case MNCC_REL_CNF:
380 rc = mncc_rel_cnf(call, msg_type, arg);
381 break;
382 case MNCC_FACILITY_IND:
383 break;
384 case MNCC_START_DTMF_IND:
385 break;
386 case MNCC_STOP_DTMF_IND:
387 break;
388 case MNCC_MODIFY_IND:
389 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
390 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
391 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
392 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100393 rc = mncc_tx_to_cc(net, MNCC_MODIFY_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100394 break;
395 case MNCC_MODIFY_CNF:
396 break;
397 case MNCC_HOLD_IND:
398 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
399 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
400 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
401 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100402 rc = mncc_tx_to_cc(net, MNCC_HOLD_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100403 break;
404 case MNCC_RETRIEVE_IND:
405 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
406 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
407 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
408 call->callref, data->cause.value);
Harald Welte76556372010-12-22 23:57:45 +0100409 rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
Harald Welte3e6376d2010-12-22 23:54:51 +0100410 break;
411 case GSM_TCHF_FRAME:
412 case GSM_TCHF_FRAME_EFR:
413 rc = mncc_rcv_tchf(call, msg_type, arg);
414 break;
415 default:
416 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
417 break;
418 }
419
Harald Welte29b64e92010-12-23 01:07:46 +0100420out_free:
421 talloc_free(msg);
422
Harald Welte3e6376d2010-12-22 23:54:51 +0100423 return rc;
424}