blob: ee67a224dc8ee59153db2339f0131cc115f281a7 [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
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>
Harald Welte09b7e7f2009-12-12 21:36:53 +010028#include <errno.h>
Harald Welte4bfdfe72009-06-10 23:11:52 +080029#include <sys/types.h>
30
31#include <openbsc/gsm_04_08.h>
32#include <openbsc/debug.h>
33#include <openbsc/mncc.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010034#include <osmocore/talloc.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020035#include <openbsc/gsm_data.h>
Harald Welteedbc0f72009-12-20 14:22:11 +010036#include <openbsc/transaction.h>
37#include <openbsc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020038
Harald Welte (local)d19e58b2009-08-15 02:30:58 +020039void *tall_call_ctx;
Harald Welte4bfdfe72009-06-10 23:11:52 +080040
41static struct mncc_names {
42 char *name;
43 int value;
44} mncc_names[] = {
45 {"MNCC_SETUP_REQ", 0x0101},
46 {"MNCC_SETUP_IND", 0x0102},
47 {"MNCC_SETUP_RSP", 0x0103},
48 {"MNCC_SETUP_CNF", 0x0104},
49 {"MNCC_SETUP_COMPL_REQ",0x0105},
50 {"MNCC_SETUP_COMPL_IND",0x0106},
51 {"MNCC_CALL_CONF_IND", 0x0107},
52 {"MNCC_CALL_PROC_REQ", 0x0108},
53 {"MNCC_PROGRESS_REQ", 0x0109},
54 {"MNCC_ALERT_REQ", 0x010a},
55 {"MNCC_ALERT_IND", 0x010b},
56 {"MNCC_NOTIFY_REQ", 0x010c},
57 {"MNCC_NOTIFY_IND", 0x010d},
58 {"MNCC_DISC_REQ", 0x010e},
59 {"MNCC_DISC_IND", 0x010f},
60 {"MNCC_REL_REQ", 0x0110},
61 {"MNCC_REL_IND", 0x0111},
62 {"MNCC_REL_CNF", 0x0112},
63 {"MNCC_FACILITY_REQ", 0x0113},
64 {"MNCC_FACILITY_IND", 0x0114},
65 {"MNCC_START_DTMF_IND", 0x0115},
66 {"MNCC_START_DTMF_RSP", 0x0116},
67 {"MNCC_START_DTMF_REJ", 0x0117},
68 {"MNCC_STOP_DTMF_IND", 0x0118},
69 {"MNCC_STOP_DTMF_RSP", 0x0119},
70 {"MNCC_MODIFY_REQ", 0x011a},
71 {"MNCC_MODIFY_IND", 0x011b},
72 {"MNCC_MODIFY_RSP", 0x011c},
73 {"MNCC_MODIFY_CNF", 0x011d},
74 {"MNCC_MODIFY_REJ", 0x011e},
75 {"MNCC_HOLD_IND", 0x011f},
76 {"MNCC_HOLD_CNF", 0x0120},
77 {"MNCC_HOLD_REJ", 0x0121},
78 {"MNCC_RETRIEVE_IND", 0x0122},
79 {"MNCC_RETRIEVE_CNF", 0x0123},
80 {"MNCC_RETRIEVE_REJ", 0x0124},
81 {"MNCC_USERINFO_REQ", 0x0125},
82 {"MNCC_USERINFO_IND", 0x0126},
83 {"MNCC_REJ_REQ", 0x0127},
84 {"MNCC_REJ_IND", 0x0128},
85
86 {"MNCC_BRIDGE", 0x0200},
87 {"MNCC_FRAME_RECV", 0x0201},
88 {"MNCC_FRAME_DROP", 0x0202},
89 {"MNCC_LCHAN_MODIFY", 0x0203},
90
Harald Welteaca8f152009-12-19 23:06:41 +010091 {"GSM_TCH_FRAME", 0x0300},
Harald Welte4bfdfe72009-06-10 23:11:52 +080092
Harald Welteb1d4c8e2009-12-17 23:10:46 +010093 {NULL, 0} };
Harald Welte4bfdfe72009-06-10 23:11:52 +080094
95static LLIST_HEAD(call_list);
96
97static u_int32_t new_callref = 0x00000001;
98
99char *get_mncc_name(int value)
100{
101 int i;
102
103 for (i = 0; mncc_names[i].name; i++) {
104 if (mncc_names[i].value == value)
105 return mncc_names[i].name;
106 }
107
108 return "MNCC_Unknown";
109}
110
111static void free_call(struct gsm_call *call)
112{
113 llist_del(&call->entry);
114 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
Harald Welte2cf161b2009-06-20 22:36:41 +0200115 talloc_free(call);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800116}
117
118
119struct gsm_call *get_call_ref(u_int32_t callref)
120{
121 struct gsm_call *callt;
122
123 llist_for_each_entry(callt, &call_list, entry) {
124 if (callt->callref == callref)
125 return callt;
126 }
127 return NULL;
128}
129
130void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
131{
132 data->fields |= MNCC_F_CAUSE;
133 data->cause.location = loc;
134 data->cause.value = val;
135}
136
137/* on incoming call, look up database and send setup to remote subscr. */
138static int mncc_setup_ind(struct gsm_call *call, int msg_type,
139 struct gsm_mncc *setup)
140{
141 struct gsm_mncc mncc;
142 struct gsm_call *remote;
143
Harald Welte09b7e7f2009-12-12 21:36:53 +0100144 memset(&mncc, 0, sizeof(struct gsm_mncc));
145 mncc.callref = call->callref;
146
Harald Welte4bfdfe72009-06-10 23:11:52 +0800147 /* already have remote call */
148 if (call->remote_ref)
149 return 0;
150
Harald Welte09b7e7f2009-12-12 21:36:53 +0100151 /* transfer mode 1 would be packet mode, which was never specified */
152 if (setup->bearer_cap.mode != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100153 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support "
154 "packet mode\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100155 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
156 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
157 goto out_reject;
158 }
159
160 /* we currently only do speech */
161 if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100162 LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support "
163 "voice calls\n", call->callref);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100164 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
165 GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
166 goto out_reject;
167 }
168
Harald Welte4bfdfe72009-06-10 23:11:52 +0800169 /* create remote call */
Harald Welte2cf161b2009-06-20 22:36:41 +0200170 if (!(remote = talloc(tall_call_ctx, struct gsm_call))) {
Harald Weltec66b71c2009-06-11 14:23:20 +0800171 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
172 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100173 goto out_reject;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800174 }
175 llist_add_tail(&remote->entry, &call_list);
176 remote->net = call->net;
177 remote->callref = new_callref++;
178 DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
179 call->callref, remote->callref);
180
181 /* link remote call */
182 call->remote_ref = remote->callref;
183 remote->remote_ref = call->callref;
184
185 /* modify mode */
186 memset(&mncc, 0, sizeof(struct gsm_mncc));
187 mncc.callref = call->callref;
188 mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
189 DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
190 mncc_send(call->net, MNCC_LCHAN_MODIFY, &mncc);
191
192 /* send call proceeding */
193 memset(&mncc, 0, sizeof(struct gsm_mncc));
194 mncc.callref = call->callref;
195 DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
196 mncc_send(call->net, MNCC_CALL_PROC_REQ, &mncc);
197
198 /* send setup to remote */
199// setup->fields |= MNCC_F_SIGNAL;
200// setup->signal = GSM48_SIGNAL_DIALTONE;
201 setup->callref = remote->callref;
202 DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
203 return mncc_send(remote->net, MNCC_SETUP_REQ, setup);
Harald Welte09b7e7f2009-12-12 21:36:53 +0100204
205out_reject:
206 mncc_send(call->net, MNCC_REJ_REQ, &mncc);
207 free_call(call);
208 return 0;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800209}
210
211static int mncc_alert_ind(struct gsm_call *call, int msg_type,
212 struct gsm_mncc *alert)
213{
214 struct gsm_call *remote;
215
216 /* send alerting to remote */
217 if (!(remote = get_call_ref(call->remote_ref)))
218 return 0;
219 alert->callref = remote->callref;
220 DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
221 return mncc_send(remote->net, MNCC_ALERT_REQ, alert);
222}
223
224static int mncc_notify_ind(struct gsm_call *call, int msg_type,
225 struct gsm_mncc *notify)
226{
227 struct gsm_call *remote;
228
229 /* send notify to remote */
230 if (!(remote = get_call_ref(call->remote_ref)))
231 return 0;
232 notify->callref = remote->callref;
233 DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
234 return mncc_send(remote->net, MNCC_NOTIFY_REQ, notify);
235}
236
237static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
238 struct gsm_mncc *connect)
239{
Harald Welteedbc0f72009-12-20 14:22:11 +0100240 struct gsm_mncc connect_ack, frame_recv;
241 struct gsm_network *net = call->net;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800242 struct gsm_call *remote;
243 u_int32_t refs[2];
244
245 /* acknowledge connect */
246 memset(&connect_ack, 0, sizeof(struct gsm_mncc));
247 connect_ack.callref = call->callref;
248 DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
249 mncc_send(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
250
251 /* send connect message to remote */
252 if (!(remote = get_call_ref(call->remote_ref)))
253 return 0;
254 connect->callref = remote->callref;
255 DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
256 mncc_send(remote->net, MNCC_SETUP_RSP, connect);
257
258 /* bridge tch */
259 refs[0] = call->callref;
260 refs[1] = call->remote_ref;
261 DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
Harald Welteedbc0f72009-12-20 14:22:11 +0100262
263 /* in direct mode, we always have to bridge the channels */
264 if (ipacc_rtp_direct)
265 return mncc_send(call->net, MNCC_BRIDGE, refs);
266
267 /* proxy mode */
268 if (!net->handover.active) {
269 /* in the no-handover case, we can bridge, i.e. use
270 * the old RTP proxy code */
271 return mncc_send(call->net, MNCC_BRIDGE, refs);
272 } else {
273 /* in case of handover, we need to re-write the RTP
274 * SSRC, sequence and timestamp values and thus
275 * need to enable RTP receive for both directions */
276 memset(&frame_recv, 0, sizeof(struct gsm_mncc));
277 frame_recv.callref = call->callref;
278 mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
279 frame_recv.callref = call->remote_ref;
280 return mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv);
281 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800282}
283
284static int mncc_disc_ind(struct gsm_call *call, int msg_type,
285 struct gsm_mncc *disc)
286{
287 struct gsm_call *remote;
288
289 /* send release */
290 DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
291 call->callref, disc->cause.value);
292 mncc_send(call->net, MNCC_REL_REQ, disc);
293
294 /* send disc to remote */
295 if (!(remote = get_call_ref(call->remote_ref))) {
296 return 0;
297 }
298 disc->callref = remote->callref;
299 DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
300 remote->callref, disc->cause.value);
301 return mncc_send(remote->net, MNCC_DISC_REQ, disc);
302}
303
304static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
305{
306 struct gsm_call *remote;
307
308 /* send release to remote */
309 if (!(remote = get_call_ref(call->remote_ref))) {
310 free_call(call);
311 return 0;
312 }
313 rel->callref = remote->callref;
314 DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
315 call->callref, rel->cause.value);
316 mncc_send(remote->net, MNCC_REL_REQ, rel);
317
318 free_call(call);
319
320 return 0;
321}
322
323static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
324{
325 free_call(call);
326 return 0;
327}
328
Harald Welteedbc0f72009-12-20 14:22:11 +0100329/* receiving a TCH/F frame from the BSC code */
330static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
331 struct gsm_data_frame *dfr)
332{
333 struct gsm_trans *remote_trans;
334
335 remote_trans = trans_find_by_callref(call->net, call->remote_ref);
336
337 /* this shouldn't really happen */
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100338 if (!remote_trans || !remote_trans->conn) {
Harald Welteedbc0f72009-12-20 14:22:11 +0100339 LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
340 return -EIO;
341 }
342
343 /* RTP socket of remote end has meanwhile died */
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100344 if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
Harald Welteedbc0f72009-12-20 14:22:11 +0100345 return -EIO;
346
Holger Hans Peter Freythere95d4822010-03-23 07:00:22 +0100347 return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
Harald Welteedbc0f72009-12-20 14:22:11 +0100348}
349
350
Harald Welte4bfdfe72009-06-10 23:11:52 +0800351int mncc_recv(struct gsm_network *net, int msg_type, void *arg)
352{
353 struct gsm_mncc *data = arg;
354 int callref;
355 struct gsm_call *call = NULL, *callt;
356 int rc = 0;
357
358 /* Special messages */
359 switch(msg_type) {
360 }
361
362 /* find callref */
363 callref = data->callref;
364 llist_for_each_entry(callt, &call_list, entry) {
365 if (callt->callref == callref) {
366 call = callt;
367 break;
368 }
369 }
370
371 /* create callref, if setup is received */
372 if (!call) {
373 if (msg_type != MNCC_SETUP_IND)
374 return 0; /* drop */
375 /* create call */
Harald Welte9b11e872009-06-26 19:42:28 +0200376 if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) {
Harald Welte4bfdfe72009-06-10 23:11:52 +0800377 struct gsm_mncc rel;
378
379 memset(&rel, 0, sizeof(struct gsm_mncc));
380 rel.callref = callref;
Harald Weltec66b71c2009-06-11 14:23:20 +0800381 mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
382 GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800383 mncc_send(net, MNCC_REL_REQ, &rel);
384 return 0;
385 }
386 llist_add_tail(&call->entry, &call_list);
387 call->net = net;
388 call->callref = callref;
389 DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
390 }
391
Harald Welteedbc0f72009-12-20 14:22:11 +0100392 switch (msg_type) {
393 case GSM_TCHF_FRAME:
394 case GSM_TCHF_FRAME_EFR:
395 break;
396 default:
397 DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
398 get_mncc_name(msg_type));
399 break;
400 }
Harald Welte4bfdfe72009-06-10 23:11:52 +0800401
402 switch(msg_type) {
403 case MNCC_SETUP_IND:
404 rc = mncc_setup_ind(call, msg_type, arg);
405 break;
406 case MNCC_SETUP_CNF:
407 rc = mncc_setup_cnf(call, msg_type, arg);
408 break;
409 case MNCC_SETUP_COMPL_IND:
410 break;
411 case MNCC_CALL_CONF_IND:
412 /* we now need to MODIFY the channel */
413 data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
414 mncc_send(call->net, MNCC_LCHAN_MODIFY, data);
415 break;
416 case MNCC_ALERT_IND:
417 rc = mncc_alert_ind(call, msg_type, arg);
418 break;
419 case MNCC_NOTIFY_IND:
420 rc = mncc_notify_ind(call, msg_type, arg);
421 break;
422 case MNCC_DISC_IND:
423 rc = mncc_disc_ind(call, msg_type, arg);
424 break;
425 case MNCC_REL_IND:
426 case MNCC_REJ_IND:
427 rc = mncc_rel_ind(call, msg_type, arg);
428 break;
429 case MNCC_REL_CNF:
430 rc = mncc_rel_cnf(call, msg_type, arg);
431 break;
432 case MNCC_FACILITY_IND:
433 break;
434 case MNCC_START_DTMF_IND:
435 break;
436 case MNCC_STOP_DTMF_IND:
437 break;
438 case MNCC_MODIFY_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800439 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
440 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800441 DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
442 call->callref, data->cause.value);
443 rc = mncc_send(net, MNCC_MODIFY_REJ, data);
444 break;
445 case MNCC_MODIFY_CNF:
446 break;
447 case MNCC_HOLD_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800448 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
449 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800450 DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
451 call->callref, data->cause.value);
452 rc = mncc_send(net, MNCC_HOLD_REJ, data);
453 break;
454 case MNCC_RETRIEVE_IND:
Harald Weltec66b71c2009-06-11 14:23:20 +0800455 mncc_set_cause(data, GSM48_CAUSE_LOC_PRN_S_LU,
456 GSM48_CC_CAUSE_SERV_OPT_UNIMPL);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800457 DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
458 call->callref, data->cause.value);
459 rc = mncc_send(net, MNCC_RETRIEVE_REJ, data);
460 break;
Harald Welteedbc0f72009-12-20 14:22:11 +0100461 case GSM_TCHF_FRAME:
462 case GSM_TCHF_FRAME_EFR:
463 rc = mncc_rcv_tchf(call, msg_type, arg);
464 break;
Harald Welte4bfdfe72009-06-10 23:11:52 +0800465 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100466 LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
Harald Welte4bfdfe72009-06-10 23:11:52 +0800467 break;
468 }
469
470 return rc;
471}