blob: 180b626e78f6eb32b0e82efa96c7d3ffbdbc5d79 [file] [log] [blame]
Harald Welte7ce5e252010-12-22 02:02:48 +01001/* mncc.c - default, minimal built-in MNCC Application for
2 * standalone bsc_hack (netowrk-in-the-box mode) */
3
Harald Welte4bfdfe72009-06-10 23:11:52 +08004/* (C) 2008-2009 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
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte4bfdfe72009-06-10 23:11:52 +080011 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte4bfdfe72009-06-10 23:11:52 +080017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte4bfdfe72009-06-10 23:11:52 +080020 *
21 */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
Harald Welte09b7e7f2009-12-12 21:36:53 +010027#include <errno.h>
Harald Welte4bfdfe72009-06-10 23:11:52 +080028#include <sys/types.h>
29
30#include <openbsc/gsm_04_08.h>
31#include <openbsc/debug.h>
32#include <openbsc/mncc.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010033#include <osmocore/talloc.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020034#include <openbsc/gsm_data.h>
Harald Welteedbc0f72009-12-20 14:22:11 +010035#include <openbsc/transaction.h>
36#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020037
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020038void *tall_call_ctx;
Harald Welte4bfdfe72009-06-10 23:11:52 +080039
40static struct mncc_names {
41 char *name;
42 int value;
43} mncc_names[] = {
44 {"MNCC_SETUP_REQ", 0x0101},
45 {"MNCC_SETUP_IND", 0x0102},
46 {"MNCC_SETUP_RSP", 0x0103},
47 {"MNCC_SETUP_CNF", 0x0104},
48 {"MNCC_SETUP_COMPL_REQ",0x0105},
49 {"MNCC_SETUP_COMPL_IND",0x0106},
50 {"MNCC_CALL_CONF_IND", 0x0107},
51 {"MNCC_CALL_PROC_REQ", 0x0108},
52 {"MNCC_PROGRESS_REQ", 0x0109},
53 {"MNCC_ALERT_REQ", 0x010a},
54 {"MNCC_ALERT_IND", 0x010b},
55 {"MNCC_NOTIFY_REQ", 0x010c},
56 {"MNCC_NOTIFY_IND", 0x010d},
57 {"MNCC_DISC_REQ", 0x010e},
58 {"MNCC_DISC_IND", 0x010f},
59 {"MNCC_REL_REQ", 0x0110},
60 {"MNCC_REL_IND", 0x0111},
61 {"MNCC_REL_CNF", 0x0112},
62 {"MNCC_FACILITY_REQ", 0x0113},
63 {"MNCC_FACILITY_IND", 0x0114},
64 {"MNCC_START_DTMF_IND", 0x0115},
65 {"MNCC_START_DTMF_RSP", 0x0116},
66 {"MNCC_START_DTMF_REJ", 0x0117},
67 {"MNCC_STOP_DTMF_IND", 0x0118},
68 {"MNCC_STOP_DTMF_RSP", 0x0119},
69 {"MNCC_MODIFY_REQ", 0x011a},
70 {"MNCC_MODIFY_IND", 0x011b},
71 {"MNCC_MODIFY_RSP", 0x011c},
72 {"MNCC_MODIFY_CNF", 0x011d},
73 {"MNCC_MODIFY_REJ", 0x011e},
74 {"MNCC_HOLD_IND", 0x011f},
75 {"MNCC_HOLD_CNF", 0x0120},
76 {"MNCC_HOLD_REJ", 0x0121},
77 {"MNCC_RETRIEVE_IND", 0x0122},
78 {"MNCC_RETRIEVE_CNF", 0x0123},
79 {"MNCC_RETRIEVE_REJ", 0x0124},
80 {"MNCC_USERINFO_REQ", 0x0125},
81 {"MNCC_USERINFO_IND", 0x0126},
82 {"MNCC_REJ_REQ", 0x0127},
83 {"MNCC_REJ_IND", 0x0128},
84
85 {"MNCC_BRIDGE", 0x0200},
86 {"MNCC_FRAME_RECV", 0x0201},
87 {"MNCC_FRAME_DROP", 0x0202},
88 {"MNCC_LCHAN_MODIFY", 0x0203},
89
Harald Welteaca8f152009-12-19 23:06:41 +010090 {"GSM_TCH_FRAME", 0x0300},
Harald Welte4bfdfe72009-06-10 23:11:52 +080091
Harald Welteb1d4c8e2009-12-17 23:10:46 +010092 {NULL, 0} };
Harald Welte4bfdfe72009-06-10 23:11:52 +080093
94static LLIST_HEAD(call_list);
95
96static u_int32_t new_callref = 0x00000001;
97
98char *get_mncc_name(int value)
99{
100 int i;
101
102 for (i = 0; mncc_names[i].name; i++) {
103 if (mncc_names[i].value == value)
104 return mncc_names[i].name;
105 }
106
107 return "MNCC_Unknown";
108}
109
110static void free_call(struct gsm_call *call)
111{
112 llist_del(&call->entry);
113 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
Harald Welte2cf161b2009-06-20 22:36:41 +0200114 talloc_free(call);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800115}
116
117
118struct gsm_call *get_call_ref(u_int32_t callref)
119{
120 struct gsm_call *callt;
121
122 llist_for_each_entry(callt, &call_list, entry) {
123 if (callt->callref == callref)
124 return callt;
125 }
126 return NULL;
127}
128
129void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
130{
131 data->fields |= MNCC_F_CAUSE;
132 data->cause.location = loc;
133 data->cause.value = val;
134}
135
136/* on incoming call, look up database and send setup to remote subscr. */
137static int mncc_setup_ind(struct gsm_call *call, int msg_type,
138 struct gsm_mncc *setup)
139{
140 struct gsm_mncc mncc;
141 struct gsm_call *remote;
142
Harald Welte09b7e7f2009-12-12 21:36:53 +0100143 memset(&mncc, 0, sizeof(struct gsm_mncc));
144 mncc.callref = call->callref;
145
Harald Welte4bfdfe72009-06-10 23:11:52 +0800146 /* already have remote call */
147 if (call->remote_ref)
148 return 0;
149
Harald Welte09b7e7f2009-12-12 21:36:53 +0100150 /* transfer mode 1 would be packet mode, which was never specified */
151 if (setup->bearer_cap.mode != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100152 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
153 "packet mode\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100154 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
155 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
156 goto out_reject;
157 }
158
159 /* we currently only do speech */
160 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100161 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
162 "voice calls\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100163 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
164 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
165 goto out_reject;
166 }
167
Harald Welte4bfdfe72009-06-10 23:11:52 +0800168 /* create remote call */
Harald Welte2cf161b2009-06-20 22:36:41 +0200169 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
Harald Weltec66b71c2009-06-11 14:23:20 +0800170 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
171 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100172 goto out_reject;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800173 }
174 llist_add_tail(&remote->entry, &call_list);
175 remote->net = call->net;
176 remote->callref = new_callref++;
177 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
178 call->callref, remote->callref);
179
180 /* link remote call */
181 call->remote_ref = remote->callref;
182 remote->remote_ref = call->callref;
183
184 /* modify mode */
185 memset(&mncc, 0, sizeof(struct gsm_mncc));
186 mncc.callref = call->callref;
187 mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
188 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
189 mncc_send(call->net, MNCC_LCHAN_MODIFY, &mncc);
190
191 /* send call proceeding */
192 memset(&mncc, 0, sizeof(struct gsm_mncc));
193 mncc.callref = call->callref;
194 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
195 mncc_send(call->net, MNCC_CALL_PROC_REQ, &mncc);
196
197 /* send setup to remote */
198// setup->fields |= MNCC_F_SIGNAL;
199// setup->signal = GSM48_SIGNAL_DIALTONE;
200 setup->callref = remote->callref;
201 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
202 return mncc_send(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100203
204out_reject:
205 mncc_send(call->net, MNCC_REJ_REQ, &mncc);
206 free_call(call);
207 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800208}
209
210static int mncc_alert_ind(struct gsm_call *call, int msg_type,
211 struct gsm_mncc *alert)
212{
213 struct gsm_call *remote;
214
215 /* send alerting to remote */
216 if (!(remote = get_call_ref(call->remote_ref)))
217 return 0;
218 alert->callref = remote->callref;
219 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
220 return mncc_send(remote->net, MNCC_ALERT_REQ, alert);
221}
222
223static int mncc_notify_ind(struct gsm_call *call, int msg_type,
224 struct gsm_mncc *notify)
225{
226 struct gsm_call *remote;
227
228 /* send notify to remote */
229 if (!(remote = get_call_ref(call->remote_ref)))
230 return 0;
231 notify->callref = remote->callref;
232 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
233 return mncc_send(remote->net, MNCC_NOTIFY_REQ, notify);
234}
235
236static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
237 struct gsm_mncc *connect)
238{
Harald Welteedbc0f72009-12-20 14:22:11 +0100239 struct gsm_mncc connect_ack, frame_recv;
240 struct gsm_network *net = call->net;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800241 struct gsm_call *remote;
242 u_int32_t refs[2];
243
244 /* acknowledge connect */
245 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
246 connect_ack.callref = call->callref;
247 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
248 mncc_send(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
249
250 /* send connect message to remote */
251 if (!(remote = get_call_ref(call->remote_ref)))
252 return 0;
253 connect->callref = remote->callref;
254 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
255 mncc_send(remote->net, MNCC_SETUP_RSP, connect);
256
257 /* bridge tch */
258 refs[0] = call->callref;
259 refs[1] = call->remote_ref;
260 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
Harald Welteedbc0f72009-12-20 14:22:11 +0100261
262 /* in direct mode, we always have to bridge the channels */
263 if (ipacc_rtp_direct)
264 return mncc_send(call->net, MNCC_BRIDGE, refs);
265
266 /* proxy mode */
267 if (!net->handover.active) {
268 /* in the no-handover case, we can bridge, i.e. use
269 * the old RTP proxy code */
270 return mncc_send(call->net, MNCC_BRIDGE, refs);
271 } else {
272 /* in case of handover, we need to re-write the RTP
273 * SSRC, sequence and timestamp values and thus
274 * need to enable RTP receive for both directions */
275 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
276 frame_recv.callref = call->callref;
277 mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
278 frame_recv.callref = call->remote_ref;
279 return mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
280 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800281}
282
283static int mncc_disc_ind(struct gsm_call *call, int msg_type,
284 struct gsm_mncc *disc)
285{
286 struct gsm_call *remote;
287
288 /* send release */
289 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
290 call->callref, disc->cause.value);
291 mncc_send(call->net, MNCC_REL_REQ, disc);
292
293 /* send disc to remote */
294 if (!(remote = get_call_ref(call->remote_ref))) {
295 return 0;
296 }
297 disc->callref = remote->callref;
298 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
299 remote->callref, disc->cause.value);
300 return mncc_send(remote->net, MNCC_DISC_REQ, disc);
301}
302
303static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
304{
305 struct gsm_call *remote;
306
307 /* send release to remote */
308 if (!(remote = get_call_ref(call->remote_ref))) {
309 free_call(call);
310 return 0;
311 }
312 rel->callref = remote->callref;
313 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
314 call->callref, rel->cause.value);
315 mncc_send(remote->net, MNCC_REL_REQ, rel);
316
317 free_call(call);
318
319 return 0;
320}
321
322static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
323{
324 free_call(call);
325 return 0;
326}
327
Harald Welteedbc0f72009-12-20 14:22:11 +0100328/* receiving a TCH/F frame from the BSC code */
329static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
330 struct gsm_data_frame *dfr)
331{
332 struct gsm_trans *remote_trans;
333
334 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
335
336 /* this shouldn't really happen */
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100337 if (!remote_trans || !remote_trans->conn) {
Harald Welteedbc0f72009-12-20 14:22:11 +0100338 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
339 return -EIO;
340 }
341
342 /* RTP socket of remote end has meanwhile died */
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100343 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
Harald Welteedbc0f72009-12-20 14:22:11 +0100344 return -EIO;
345
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100346 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
Harald Welteedbc0f72009-12-20 14:22:11 +0100347}
348
349
Harald Welte4bfdfe72009-06-10 23:11:52 +0800350int mncc_recv(struct gsm_network *net, int msg_type, void *arg)
351{
352 struct gsm_mncc *data = arg;
353 int callref;
354 struct gsm_call *call = NULL, *callt;
355 int rc = 0;
356
357 /* Special messages */
358 switch(msg_type) {
359 }
360
361 /* find callref */
362 callref = data->callref;
363 llist_for_each_entry(callt, &call_list, entry) {
364 if (callt->callref == callref) {
365 call = callt;
366 break;
367 }
368 }
369
370 /* create callref, if setup is received */
371 if (!call) {
372 if (msg_type != MNCC_SETUP_IND)
373 return 0; /* drop */
374 /* create call */
Harald Welte9b11e872009-06-26 19:42:28 +0200375 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte4bfdfe72009-06-10 23:11:52 +0800376 struct gsm_mncc rel;
377
378 memset(&rel, 0, sizeof(struct gsm_mncc));
379 rel.callref = callref;
Harald Weltec66b71c2009-06-11 14:23:20 +0800380 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
381 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800382 mncc_send(net, MNCC_REL_REQ, &rel);
383 return 0;
384 }
385 llist_add_tail(&call->entry, &call_list);
386 call->net = net;
387 call->callref = callref;
388 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
389 }
390
Harald Welteedbc0f72009-12-20 14:22:11 +0100391 switch (msg_type) {
392 case GSM_TCHF_FRAME:
393 case GSM_TCHF_FRAME_EFR:
394 break;
395 default:
396 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
397 get_mncc_name(msg_type));
398 break;
399 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800400
401 switch(msg_type) {
402 case MNCC_SETUP_IND:
403 rc = mncc_setup_ind(call, msg_type, arg);
404 break;
405 case MNCC_SETUP_CNF:
406 rc = mncc_setup_cnf(call, msg_type, arg);
407 break;
408 case MNCC_SETUP_COMPL_IND:
409 break;
410 case MNCC_CALL_CONF_IND:
411 /* we now need to MODIFY the channel */
412 data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
413 mncc_send(call->net, MNCC_LCHAN_MODIFY, data);
414 break;
415 case MNCC_ALERT_IND:
416 rc = mncc_alert_ind(call, msg_type, arg);
417 break;
418 case MNCC_NOTIFY_IND:
419 rc = mncc_notify_ind(call, msg_type, arg);
420 break;
421 case MNCC_DISC_IND:
422 rc = mncc_disc_ind(call, msg_type, arg);
423 break;
424 case MNCC_REL_IND:
425 case MNCC_REJ_IND:
426 rc = mncc_rel_ind(call, msg_type, arg);
427 break;
428 case MNCC_REL_CNF:
429 rc = mncc_rel_cnf(call, msg_type, arg);
430 break;
431 case MNCC_FACILITY_IND:
432 break;
433 case MNCC_START_DTMF_IND:
434 break;
435 case MNCC_STOP_DTMF_IND:
436 break;
437 case MNCC_MODIFY_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800438 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
439 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800440 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
441 call->callref, data->cause.value);
442 rc = mncc_send(net, MNCC_MODIFY_REJ, data);
443 break;
444 case MNCC_MODIFY_CNF:
445 break;
446 case MNCC_HOLD_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800447 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
448 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800449 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
450 call->callref, data->cause.value);
451 rc = mncc_send(net, MNCC_HOLD_REJ, data);
452 break;
453 case MNCC_RETRIEVE_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800454 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
455 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800456 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
457 call->callref, data->cause.value);
458 rc = mncc_send(net, MNCC_RETRIEVE_REJ, data);
459 break;
Harald Welteedbc0f72009-12-20 14:22:11 +0100460 case GSM_TCHF_FRAME:
461 case GSM_TCHF_FRAME_EFR:
462 rc = mncc_rcv_tchf(call, msg_type, arg);
463 break;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800464 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100465 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800466 break;
467 }
468
469 return rc;
470}