blob: 15e2978e607a8526050afa04f47e7908c834ee58 [file] [log] [blame]
Harald Welte4bfdfe72009-06-10 23:11:52 +08001/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
2 * (C) 2009 by Andreas Eversberg <Andreas.Eversberg@versatel.de>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Harald Welte09b7e7f2009-12-12 21:36:53 +010025#include <errno.h>
Harald Welte4bfdfe72009-06-10 23:11:52 +080026#include <sys/types.h>
27
28#include <openbsc/gsm_04_08.h>
29#include <openbsc/debug.h>
30#include <openbsc/mncc.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020031#include <openbsc/talloc.h>
32#include <openbsc/gsm_data.h>
Harald Welteedbc0f72009-12-20 14:22:11 +010033#include <openbsc/transaction.h>
34#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020035
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020036void *tall_call_ctx;
Harald Welte4bfdfe72009-06-10 23:11:52 +080037
38static struct mncc_names {
39 char *name;
40 int value;
41} mncc_names[] = {
42 {"MNCC_SETUP_REQ", 0x0101},
43 {"MNCC_SETUP_IND", 0x0102},
44 {"MNCC_SETUP_RSP", 0x0103},
45 {"MNCC_SETUP_CNF", 0x0104},
46 {"MNCC_SETUP_COMPL_REQ",0x0105},
47 {"MNCC_SETUP_COMPL_IND",0x0106},
48 {"MNCC_CALL_CONF_IND", 0x0107},
49 {"MNCC_CALL_PROC_REQ", 0x0108},
50 {"MNCC_PROGRESS_REQ", 0x0109},
51 {"MNCC_ALERT_REQ", 0x010a},
52 {"MNCC_ALERT_IND", 0x010b},
53 {"MNCC_NOTIFY_REQ", 0x010c},
54 {"MNCC_NOTIFY_IND", 0x010d},
55 {"MNCC_DISC_REQ", 0x010e},
56 {"MNCC_DISC_IND", 0x010f},
57 {"MNCC_REL_REQ", 0x0110},
58 {"MNCC_REL_IND", 0x0111},
59 {"MNCC_REL_CNF", 0x0112},
60 {"MNCC_FACILITY_REQ", 0x0113},
61 {"MNCC_FACILITY_IND", 0x0114},
62 {"MNCC_START_DTMF_IND", 0x0115},
63 {"MNCC_START_DTMF_RSP", 0x0116},
64 {"MNCC_START_DTMF_REJ", 0x0117},
65 {"MNCC_STOP_DTMF_IND", 0x0118},
66 {"MNCC_STOP_DTMF_RSP", 0x0119},
67 {"MNCC_MODIFY_REQ", 0x011a},
68 {"MNCC_MODIFY_IND", 0x011b},
69 {"MNCC_MODIFY_RSP", 0x011c},
70 {"MNCC_MODIFY_CNF", 0x011d},
71 {"MNCC_MODIFY_REJ", 0x011e},
72 {"MNCC_HOLD_IND", 0x011f},
73 {"MNCC_HOLD_CNF", 0x0120},
74 {"MNCC_HOLD_REJ", 0x0121},
75 {"MNCC_RETRIEVE_IND", 0x0122},
76 {"MNCC_RETRIEVE_CNF", 0x0123},
77 {"MNCC_RETRIEVE_REJ", 0x0124},
78 {"MNCC_USERINFO_REQ", 0x0125},
79 {"MNCC_USERINFO_IND", 0x0126},
80 {"MNCC_REJ_REQ", 0x0127},
81 {"MNCC_REJ_IND", 0x0128},
82
83 {"MNCC_BRIDGE", 0x0200},
84 {"MNCC_FRAME_RECV", 0x0201},
85 {"MNCC_FRAME_DROP", 0x0202},
86 {"MNCC_LCHAN_MODIFY", 0x0203},
87
Harald Welteaca8f152009-12-19 23:06:41 +010088 {"GSM_TCH_FRAME", 0x0300},
Harald Welte4bfdfe72009-06-10 23:11:52 +080089
Harald Welteb1d4c8e2009-12-17 23:10:46 +010090 {NULL, 0} };
Harald Welte4bfdfe72009-06-10 23:11:52 +080091
92static LLIST_HEAD(call_list);
93
94static u_int32_t new_callref = 0x00000001;
95
96char *get_mncc_name(int value)
97{
98 int i;
99
100 for (i = 0; mncc_names[i].name; i++) {
101 if (mncc_names[i].value == value)
102 return mncc_names[i].name;
103 }
104
105 return "MNCC_Unknown";
106}
107
108static void free_call(struct gsm_call *call)
109{
110 llist_del(&call->entry);
111 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
Harald Welte2cf161b2009-06-20 22:36:41 +0200112 talloc_free(call);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800113}
114
115
116struct gsm_call *get_call_ref(u_int32_t callref)
117{
118 struct gsm_call *callt;
119
120 llist_for_each_entry(callt, &call_list, entry) {
121 if (callt->callref == callref)
122 return callt;
123 }
124 return NULL;
125}
126
127void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
128{
129 data->fields |= MNCC_F_CAUSE;
130 data->cause.location = loc;
131 data->cause.value = val;
132}
133
134/* on incoming call, look up database and send setup to remote subscr. */
135static int mncc_setup_ind(struct gsm_call *call, int msg_type,
136 struct gsm_mncc *setup)
137{
138 struct gsm_mncc mncc;
139 struct gsm_call *remote;
140
Harald Welte09b7e7f2009-12-12 21:36:53 +0100141 memset(&mncc, 0, sizeof(struct gsm_mncc));
142 mncc.callref = call->callref;
143
Harald Welte4bfdfe72009-06-10 23:11:52 +0800144 /* already have remote call */
145 if (call->remote_ref)
146 return 0;
147
Harald Welte09b7e7f2009-12-12 21:36:53 +0100148 /* transfer mode 1 would be packet mode, which was never specified */
149 if (setup->bearer_cap.mode != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100150 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
151 "packet mode\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100152 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
153 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
154 goto out_reject;
155 }
156
157 /* we currently only do speech */
158 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100159 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
160 "voice calls\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100161 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
162 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
163 goto out_reject;
164 }
165
Harald Welte4bfdfe72009-06-10 23:11:52 +0800166 /* create remote call */
Harald Welte2cf161b2009-06-20 22:36:41 +0200167 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
Harald Weltec66b71c2009-06-11 14:23:20 +0800168 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
169 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100170 goto out_reject;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800171 }
172 llist_add_tail(&remote->entry, &call_list);
173 remote->net = call->net;
174 remote->callref = new_callref++;
175 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
176 call->callref, remote->callref);
177
178 /* link remote call */
179 call->remote_ref = remote->callref;
180 remote->remote_ref = call->callref;
181
182 /* modify mode */
183 memset(&mncc, 0, sizeof(struct gsm_mncc));
184 mncc.callref = call->callref;
185 mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
186 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
187 mncc_send(call->net, MNCC_LCHAN_MODIFY, &mncc);
188
189 /* send call proceeding */
190 memset(&mncc, 0, sizeof(struct gsm_mncc));
191 mncc.callref = call->callref;
192 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
193 mncc_send(call->net, MNCC_CALL_PROC_REQ, &mncc);
194
195 /* send setup to remote */
196// setup->fields |= MNCC_F_SIGNAL;
197// setup->signal = GSM48_SIGNAL_DIALTONE;
198 setup->callref = remote->callref;
199 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
200 return mncc_send(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100201
202out_reject:
203 mncc_send(call->net, MNCC_REJ_REQ, &mncc);
204 free_call(call);
205 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800206}
207
208static int mncc_alert_ind(struct gsm_call *call, int msg_type,
209 struct gsm_mncc *alert)
210{
211 struct gsm_call *remote;
212
213 /* send alerting to remote */
214 if (!(remote = get_call_ref(call->remote_ref)))
215 return 0;
216 alert->callref = remote->callref;
217 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
218 return mncc_send(remote->net, MNCC_ALERT_REQ, alert);
219}
220
221static int mncc_notify_ind(struct gsm_call *call, int msg_type,
222 struct gsm_mncc *notify)
223{
224 struct gsm_call *remote;
225
226 /* send notify to remote */
227 if (!(remote = get_call_ref(call->remote_ref)))
228 return 0;
229 notify->callref = remote->callref;
230 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
231 return mncc_send(remote->net, MNCC_NOTIFY_REQ, notify);
232}
233
234static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
235 struct gsm_mncc *connect)
236{
Harald Welteedbc0f72009-12-20 14:22:11 +0100237 struct gsm_mncc connect_ack, frame_recv;
238 struct gsm_network *net = call->net;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800239 struct gsm_call *remote;
240 u_int32_t refs[2];
241
242 /* acknowledge connect */
243 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
244 connect_ack.callref = call->callref;
245 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
246 mncc_send(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
247
248 /* send connect message to remote */
249 if (!(remote = get_call_ref(call->remote_ref)))
250 return 0;
251 connect->callref = remote->callref;
252 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
253 mncc_send(remote->net, MNCC_SETUP_RSP, connect);
254
255 /* bridge tch */
256 refs[0] = call->callref;
257 refs[1] = call->remote_ref;
258 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
Harald Welteedbc0f72009-12-20 14:22:11 +0100259
260 /* in direct mode, we always have to bridge the channels */
261 if (ipacc_rtp_direct)
262 return mncc_send(call->net, MNCC_BRIDGE, refs);
263
264 /* proxy mode */
265 if (!net->handover.active) {
266 /* in the no-handover case, we can bridge, i.e. use
267 * the old RTP proxy code */
268 return mncc_send(call->net, MNCC_BRIDGE, refs);
269 } else {
270 /* in case of handover, we need to re-write the RTP
271 * SSRC, sequence and timestamp values and thus
272 * need to enable RTP receive for both directions */
273 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
274 frame_recv.callref = call->callref;
275 mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
276 frame_recv.callref = call->remote_ref;
277 return mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
278 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800279}
280
281static int mncc_disc_ind(struct gsm_call *call, int msg_type,
282 struct gsm_mncc *disc)
283{
284 struct gsm_call *remote;
285
286 /* send release */
287 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
288 call->callref, disc->cause.value);
289 mncc_send(call->net, MNCC_REL_REQ, disc);
290
291 /* send disc to remote */
292 if (!(remote = get_call_ref(call->remote_ref))) {
293 return 0;
294 }
295 disc->callref = remote->callref;
296 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
297 remote->callref, disc->cause.value);
298 return mncc_send(remote->net, MNCC_DISC_REQ, disc);
299}
300
301static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
302{
303 struct gsm_call *remote;
304
305 /* send release to remote */
306 if (!(remote = get_call_ref(call->remote_ref))) {
307 free_call(call);
308 return 0;
309 }
310 rel->callref = remote->callref;
311 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
312 call->callref, rel->cause.value);
313 mncc_send(remote->net, MNCC_REL_REQ, rel);
314
315 free_call(call);
316
317 return 0;
318}
319
320static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
321{
322 free_call(call);
323 return 0;
324}
325
Harald Welteedbc0f72009-12-20 14:22:11 +0100326/* receiving a TCH/F frame from the BSC code */
327static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
328 struct gsm_data_frame *dfr)
329{
330 struct gsm_trans *remote_trans;
331
332 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
333
334 /* this shouldn't really happen */
335 if (!remote_trans || !remote_trans->lchan) {
336 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
337 return -EIO;
338 }
339
340 /* RTP socket of remote end has meanwhile died */
341 if (!remote_trans->lchan->abis_ip.rtp_socket)
342 return -EIO;
343
344 return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr);
345}
346
347
Harald Welte4bfdfe72009-06-10 23:11:52 +0800348int mncc_recv(struct gsm_network *net, int msg_type, void *arg)
349{
350 struct gsm_mncc *data = arg;
351 int callref;
352 struct gsm_call *call = NULL, *callt;
353 int rc = 0;
354
355 /* Special messages */
356 switch(msg_type) {
357 }
358
359 /* find callref */
360 callref = data->callref;
361 llist_for_each_entry(callt, &call_list, entry) {
362 if (callt->callref == callref) {
363 call = callt;
364 break;
365 }
366 }
367
368 /* create callref, if setup is received */
369 if (!call) {
370 if (msg_type != MNCC_SETUP_IND)
371 return 0; /* drop */
372 /* create call */
Harald Welte9b11e872009-06-26 19:42:28 +0200373 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte4bfdfe72009-06-10 23:11:52 +0800374 struct gsm_mncc rel;
375
376 memset(&rel, 0, sizeof(struct gsm_mncc));
377 rel.callref = callref;
Harald Weltec66b71c2009-06-11 14:23:20 +0800378 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
379 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800380 mncc_send(net, MNCC_REL_REQ, &rel);
381 return 0;
382 }
383 llist_add_tail(&call->entry, &call_list);
384 call->net = net;
385 call->callref = callref;
386 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
387 }
388
Harald Welteedbc0f72009-12-20 14:22:11 +0100389 switch (msg_type) {
390 case GSM_TCHF_FRAME:
391 case GSM_TCHF_FRAME_EFR:
392 break;
393 default:
394 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
395 get_mncc_name(msg_type));
396 break;
397 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800398
399 switch(msg_type) {
400 case MNCC_SETUP_IND:
401 rc = mncc_setup_ind(call, msg_type, arg);
402 break;
403 case MNCC_SETUP_CNF:
404 rc = mncc_setup_cnf(call, msg_type, arg);
405 break;
406 case MNCC_SETUP_COMPL_IND:
407 break;
408 case MNCC_CALL_CONF_IND:
409 /* we now need to MODIFY the channel */
410 data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
411 mncc_send(call->net, MNCC_LCHAN_MODIFY, data);
412 break;
413 case MNCC_ALERT_IND:
414 rc = mncc_alert_ind(call, msg_type, arg);
415 break;
416 case MNCC_NOTIFY_IND:
417 rc = mncc_notify_ind(call, msg_type, arg);
418 break;
419 case MNCC_DISC_IND:
420 rc = mncc_disc_ind(call, msg_type, arg);
421 break;
422 case MNCC_REL_IND:
423 case MNCC_REJ_IND:
424 rc = mncc_rel_ind(call, msg_type, arg);
425 break;
426 case MNCC_REL_CNF:
427 rc = mncc_rel_cnf(call, msg_type, arg);
428 break;
429 case MNCC_FACILITY_IND:
430 break;
431 case MNCC_START_DTMF_IND:
432 break;
433 case MNCC_STOP_DTMF_IND:
434 break;
435 case MNCC_MODIFY_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800436 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
437 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800438 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
439 call->callref, data->cause.value);
440 rc = mncc_send(net, MNCC_MODIFY_REJ, data);
441 break;
442 case MNCC_MODIFY_CNF:
443 break;
444 case MNCC_HOLD_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800445 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
446 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800447 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
448 call->callref, data->cause.value);
449 rc = mncc_send(net, MNCC_HOLD_REJ, data);
450 break;
451 case MNCC_RETRIEVE_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800452 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
453 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800454 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
455 call->callref, data->cause.value);
456 rc = mncc_send(net, MNCC_RETRIEVE_REJ, data);
457 break;
Harald Welteedbc0f72009-12-20 14:22:11 +0100458 case GSM_TCHF_FRAME:
459 case GSM_TCHF_FRAME_EFR:
460 rc = mncc_rcv_tchf(call, msg_type, arg);
461 break;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800462 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100463 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800464 break;
465 }
466
467 return rc;
468}