2 * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <osmocore/talloc.h>
30 #include <osmocom/bb/common/logging.h>
31 #include <osmocom/bb/common/osmocom_data.h>
32 #include <osmocom/bb/mobile/mncc.h>
33 #include <osmocom/bb/mobile/vty.h>
36 static uint32_t new_callref = 1;
37 static LLIST_HEAD(call_list);
43 void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
45 static void free_call(struct gsm_call *call)
47 llist_del(&call->entry);
48 DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
53 struct gsm_call *get_call_ref(uint32_t callref)
55 struct gsm_call *callt;
57 llist_for_each_entry(callt, &call_list, entry) {
58 if (callt->callref == callref)
64 static int8_t mncc_get_bearer(struct gsm_support *sup, uint8_t speech_ver)
69 LOGP(DMNCC, LOGL_INFO, " net suggests full rate v3\n");
71 LOGP(DMNCC, LOGL_INFO, " full rate v3 not supported\n");
77 LOGP(DMNCC, LOGL_INFO, " net suggests full rate v2\n");
79 LOGP(DMNCC, LOGL_INFO, " full rate v2 not supported\n");
83 case 0: /* mandatory */
85 LOGP(DMNCC, LOGL_INFO, " net suggests full rate v1\n");
87 LOGP(DMNCC, LOGL_INFO, " full rate v1 not supported\n");
93 LOGP(DMNCC, LOGL_INFO, " net suggests half rate v3\n");
95 LOGP(DMNCC, LOGL_INFO, " half rate v3 not supported\n");
101 LOGP(DMNCC, LOGL_INFO, " net suggests half rate v1\n");
103 LOGP(DMNCC, LOGL_INFO, " half rate v1 not supported\n");
108 LOGP(DMNCC, LOGL_INFO, " net suggests unknown speech version "
116 static void mncc_set_bearer(struct osmocom_ms *ms, int8_t speech_ver,
117 struct gsm_mncc *mncc)
119 struct gsm_support *sup = &ms->support;
120 struct gsm_settings *set = &ms->settings;
123 mncc->fields |= MNCC_F_BEARER_CAP;
124 mncc->bearer_cap.coding = 0;
125 if (sup->ch_cap == GSM_CAP_SDCCH_TCHF_TCHH
126 && (sup->half_v1 || sup->half_v3)) {
127 mncc->bearer_cap.radio = 3;
128 LOGP(DMNCC, LOGL_INFO, " support TCH/H also\n");
130 mncc->bearer_cap.radio = 1;
131 LOGP(DMNCC, LOGL_INFO, " support TCH/F only\n");
133 mncc->bearer_cap.speech_ctm = 0;
134 /* if no specific speech_ver is given */
135 if (speech_ver < 0) {
136 /* if half rate is supported and prefered */
137 if (sup->half_v3 && set->half && set->half_prefer) {
138 mncc->bearer_cap.speech_ver[i++] = 5;
139 LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
141 if (sup->half_v1 && set->half && set->half_prefer) {
142 mncc->bearer_cap.speech_ver[i++] = 1;
143 LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
145 /* if full rate is supported */
147 mncc->bearer_cap.speech_ver[i++] = 4;
148 LOGP(DMNCC, LOGL_INFO, " support full rate v3\n");
151 mncc->bearer_cap.speech_ver[i++] = 2;
152 LOGP(DMNCC, LOGL_INFO, " support full rate v2\n");
154 if (sup->full_v1) { /* mandatory, so it's always true */
155 mncc->bearer_cap.speech_ver[i++] = 0;
156 LOGP(DMNCC, LOGL_INFO, " support full rate v1\n");
158 /* if half rate is supported and not prefered */
159 if (sup->half_v3 && set->half && !set->half_prefer) {
160 mncc->bearer_cap.speech_ver[i++] = 5;
161 LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
163 if (sup->half_v1 && set->half && !set->half_prefer) {
164 mncc->bearer_cap.speech_ver[i++] = 1;
165 LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
167 /* if specific speech_ver is given (it must be supported) */
169 mncc->bearer_cap.speech_ver[i++] = speech_ver;
170 mncc->bearer_cap.speech_ver[i] = -1; /* end of list */
171 mncc->bearer_cap.transfer = 0;
172 mncc->bearer_cap.mode = 0;
176 * MNCCms dummy application
179 /* this is a minimal implementation as required by GSM 04.08 */
180 int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg)
182 struct gsm_mncc *data = arg;
183 uint32_t callref = data->callref;
186 if (msg_type == MNCC_REL_IND || msg_type == MNCC_REL_CNF)
189 LOGP(DMNCC, LOGL_INFO, "Rejecting incomming call\n");
191 /* reject, as we don't support Calls */
192 memset(&rel, 0, sizeof(struct gsm_mncc));
193 rel.callref = callref;
194 mncc_set_cause(&rel, GSM48_CAUSE_LOC_USER,
195 GSM48_CC_CAUSE_INCOMPAT_DEST);
197 return mncc_send(ms, MNCC_REL_REQ, &rel);
201 * MNCCms basic call application
204 int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
206 struct gsm_settings *set = &ms->settings;
207 struct gsm_support *sup = &ms->support;
208 struct gsm_mncc *data = arg;
209 struct gsm_call *call = get_call_ref(data->callref);
210 struct gsm_mncc mncc;
212 int8_t speech_ver = -1, speech_ver_half = -1, temp;
215 /* call does not exist */
216 if (!call && msg_type != MNCC_SETUP_IND) {
217 LOGP(DMNCC, LOGL_INFO, "Rejecting incomming call "
218 "(callref %x)\n", data->callref);
219 if (msg_type == MNCC_REL_IND || msg_type == MNCC_REL_CNF)
221 cause = GSM48_CC_CAUSE_INCOMPAT_DEST;
223 memset(&mncc, 0, sizeof(struct gsm_mncc));
224 mncc.callref = data->callref;
225 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_USER, cause);
226 return mncc_send(ms, MNCC_REL_REQ, &mncc);
229 /* setup without call */
231 if (llist_empty(&call_list))
233 call = talloc_zero(l23_ctx, struct gsm_call);
236 call->callref = data->callref;
237 llist_add_tail(&call->entry, &call_list);
240 /* not in initiated state anymore */
245 vty_notify(ms, NULL);
246 switch (data->cause.value) {
247 case GSM48_CC_CAUSE_UNASSIGNED_NR:
248 vty_notify(ms, "Call: Number not assigned\n");
250 case GSM48_CC_CAUSE_NO_ROUTE:
251 vty_notify(ms, "Call: Destination unreachable\n");
253 case GSM48_CC_CAUSE_NORM_CALL_CLEAR:
254 vty_notify(ms, "Call: Remote hangs up\n");
256 case GSM48_CC_CAUSE_USER_BUSY:
257 vty_notify(ms, "Call: Remote busy\n");
259 case GSM48_CC_CAUSE_USER_NOTRESPOND:
260 vty_notify(ms, "Call: Remote not responding\n");
262 case GSM48_CC_CAUSE_USER_ALERTING_NA:
263 vty_notify(ms, "Call: Remote not answering\n");
265 case GSM48_CC_CAUSE_CALL_REJECTED:
266 vty_notify(ms, "Call has been rejected\n");
268 case GSM48_CC_CAUSE_NUMBER_CHANGED:
269 vty_notify(ms, "Call: Number changed\n");
271 case GSM48_CC_CAUSE_PRE_EMPTION:
272 vty_notify(ms, "Call: Cleared due to pre-emption\n");
274 case GSM48_CC_CAUSE_DEST_OOO:
275 vty_notify(ms, "Call: Remote out of order\n");
277 case GSM48_CC_CAUSE_INV_NR_FORMAT:
278 vty_notify(ms, "Call: Number invalid or imcomplete\n");
280 case GSM48_CC_CAUSE_NO_CIRCUIT_CHAN:
281 vty_notify(ms, "Call: No channel available\n");
283 case GSM48_CC_CAUSE_NETWORK_OOO:
284 vty_notify(ms, "Call: Network out of order\n");
286 case GSM48_CC_CAUSE_TEMP_FAILURE:
287 vty_notify(ms, "Call: Temporary failure\n");
289 case GSM48_CC_CAUSE_SWITCH_CONG:
290 vty_notify(ms, "Congestion\n");
293 vty_notify(ms, "Call has been disconnected\n");
295 LOGP(DMNCC, LOGL_INFO, "Call has been disconnected "
296 "(cause %d)\n", data->cause.value);
297 if ((data->fields & MNCC_F_PROGRESS)
298 && data->progress.descr == 8) {
299 vty_notify(ms, "Please hang up!\n");
303 cause = GSM48_CC_CAUSE_NORM_CALL_CLEAR;
307 vty_notify(ms, NULL);
308 if (data->cause.value == GSM48_CC_CAUSE_CALL_REJECTED)
309 vty_notify(ms, "Call has been rejected\n");
311 vty_notify(ms, "Call has been released\n");
312 LOGP(DMNCC, LOGL_INFO, "Call has been released (cause %d)\n",
316 case MNCC_CALL_PROC_IND:
317 vty_notify(ms, NULL);
318 vty_notify(ms, "Call is proceeding\n");
319 LOGP(DMNCC, LOGL_INFO, "Call is proceeding\n");
320 if ((data->fields & MNCC_F_BEARER_CAP)
321 && data->bearer_cap.speech_ver[0] >= 0) {
322 mncc_get_bearer(sup, data->bearer_cap.speech_ver[0]);
326 vty_notify(ms, NULL);
327 vty_notify(ms, "Call is aleriting\n");
328 LOGP(DMNCC, LOGL_INFO, "Call is alerting\n");
331 vty_notify(ms, NULL);
332 vty_notify(ms, "Call is answered\n");
333 LOGP(DMNCC, LOGL_INFO, "Call is answered\n");
336 vty_notify(ms, NULL);
337 if (!first_call && !ms->settings.cw) {
338 vty_notify(ms, "Incomming call rejected while busy\n");
339 LOGP(DMNCC, LOGL_INFO, "Incomming call but busy\n");
340 cause = GSM48_CC_CAUSE_USER_BUSY;
343 /* select first supported speech_ver */
344 if ((data->fields & MNCC_F_BEARER_CAP)) {
347 for (i = 0; data->bearer_cap.speech_ver[i] >= 0; i++) {
349 temp = mncc_get_bearer(sup,
350 data->bearer_cap.speech_ver[i]);
353 if (temp == 5 || temp == 1) { /* half */
354 /* only the first half rate */
355 if (speech_ver_half < 0)
356 speech_ver_half = temp;
358 /* only the first full rate */
363 /* half and full given */
364 if (speech_ver_half >= 0 && speech_ver >= 0) {
365 if (set->half_prefer) {
366 LOGP(DMNCC, LOGL_INFO, " both supported"
367 " codec rates are given, using "
368 "preferred half rate\n");
369 speech_ver = speech_ver_half;
371 LOGP(DMNCC, LOGL_INFO, " both supported"
372 " codec rates are given, using "
373 "preferred full rate\n");
374 } else if (speech_ver_half < 0 && speech_ver < 0) {
375 LOGP(DMNCC, LOGL_INFO, " no supported codec "
377 /* only half rate is given, use it */
378 } else if (speech_ver_half >= 0) {
379 LOGP(DMNCC, LOGL_INFO, " only supported half "
380 "rate codec is given, using it\n");
381 speech_ver = speech_ver_half;
382 /* only full rate is given, use it */
384 LOGP(DMNCC, LOGL_INFO, " only supported full "
385 "rate codec is given, using it\n");
387 if (speech_ver < 0) {
388 vty_notify(ms, "Incomming call rejected, no "
390 LOGP(DMNCC, LOGL_INFO, "Incomming call "
391 "rejected, no voice call\n");
392 cause = GSM48_CC_CAUSE_BEARERSERV_UNIMPL;
396 /* presentation allowed if present == 0 */
397 if (data->calling.present || !data->calling.number[0])
398 vty_notify(ms, "Incomming call (anonymous)\n");
399 else if (data->calling.type == 1)
400 vty_notify(ms, "Incomming call (from +%s)\n",
401 data->calling.number);
402 else if (data->calling.type == 2)
403 vty_notify(ms, "Incomming call (from 0-%s)\n",
404 data->calling.number);
406 vty_notify(ms, "Incomming call (from %s)\n",
407 data->calling.number);
408 LOGP(DMNCC, LOGL_INFO, "Incomming call (from %s callref %x)\n",
409 data->calling.number, call->callref);
410 memset(&mncc, 0, sizeof(struct gsm_mncc));
411 mncc.callref = call->callref;
412 /* only include bearer cap, if not given in setup
413 * or if multiple codecs are given
414 * or if not only full rate
415 * or if given codec is unimplemented
417 if (!(data->fields & MNCC_F_BEARER_CAP) || speech_ver < 0)
418 mncc_set_bearer(ms, -1, &mncc);
419 else if (data->bearer_cap.speech_ver[1] >= 0
421 mncc_set_bearer(ms, speech_ver, &mncc);
422 mncc_send(ms, MNCC_CALL_CONF_REQ, &mncc);
424 LOGP(DMNCC, LOGL_INFO, "Ring!\n");
426 LOGP(DMNCC, LOGL_INFO, "Knock!\n");
430 memset(&mncc, 0, sizeof(struct gsm_mncc));
431 mncc.callref = call->callref;
432 mncc_send(ms, MNCC_ALERT_REQ, &mncc);
434 case MNCC_SETUP_COMPL_IND:
435 vty_notify(ms, NULL);
436 vty_notify(ms, "Call is connected\n");
437 LOGP(DMNCC, LOGL_INFO, "Call is connected\n");
440 vty_notify(ms, NULL);
441 vty_notify(ms, "Call is on hold\n");
442 LOGP(DMNCC, LOGL_INFO, "Call is on hold\n");
446 vty_notify(ms, NULL);
447 vty_notify(ms, "Call hold was rejected\n");
448 LOGP(DMNCC, LOGL_INFO, "Call hold was rejected\n");
450 case MNCC_RETRIEVE_CNF:
451 vty_notify(ms, NULL);
452 vty_notify(ms, "Call is retrieved\n");
453 LOGP(DMNCC, LOGL_INFO, "Call is retrieved\n");
456 case MNCC_RETRIEVE_REJ:
457 vty_notify(ms, NULL);
458 vty_notify(ms, "Call retrieve was rejected\n");
459 LOGP(DMNCC, LOGL_INFO, "Call retrieve was rejected\n");
462 LOGP(DMNCC, LOGL_INFO, "Message 0x%02x unsupported\n",
470 int mncc_call(struct osmocom_ms *ms, char *number)
472 struct gsm_call *call;
473 struct gsm_mncc setup;
475 llist_for_each_entry(call, &call_list, entry) {
477 vty_notify(ms, NULL);
478 vty_notify(ms, "Please put active call on hold "
480 LOGP(DMNCC, LOGL_INFO, "Cannot make a call, busy!\n");
485 call = talloc_zero(l23_ctx, struct gsm_call);
488 call->callref = new_callref++;
490 llist_add_tail(&call->entry, &call_list);
492 memset(&setup, 0, sizeof(struct gsm_mncc));
493 setup.callref = call->callref;
495 if (!strncasecmp(number, "emerg", 5)) {
496 LOGP(DMNCC, LOGL_INFO, "Make emergency call\n");
500 LOGP(DMNCC, LOGL_INFO, "Make call to %s\n", number);
502 setup.fields |= MNCC_F_CALLED;
503 if (number[0] == '+') {
505 setup.called.type = 1; /* international */
507 setup.called.type = 0; /* auto/unknown - prefix must be
509 setup.called.plan = 1; /* ISDN */
510 strncpy(setup.called.number, number,
511 sizeof(setup.called.number) - 1);
513 /* bearer capability (mandatory) */
514 mncc_set_bearer(ms, -1, &setup);
515 if (ms->settings.clir)
517 else if (ms->settings.clip)
521 return mncc_send(ms, MNCC_SETUP_REQ, &setup);
524 int mncc_hangup(struct osmocom_ms *ms)
526 struct gsm_call *call, *found = NULL;
527 struct gsm_mncc disc;
529 llist_for_each_entry(call, &call_list, entry) {
536 LOGP(DMNCC, LOGL_INFO, "No active call to hangup\n");
537 vty_notify(ms, NULL);
538 vty_notify(ms, "No active call\n");
542 memset(&disc, 0, sizeof(struct gsm_mncc));
543 disc.callref = found->callref;
544 mncc_set_cause(&disc, GSM48_CAUSE_LOC_USER,
545 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
546 return mncc_send(ms, (call->init) ? MNCC_REL_REQ : MNCC_DISC_REQ,
550 int mncc_answer(struct osmocom_ms *ms)
552 struct gsm_call *call, *alerting = NULL;
556 llist_for_each_entry(call, &call_list, entry) {
559 else if (!call->hold)
563 LOGP(DMNCC, LOGL_INFO, "No call alerting\n");
564 vty_notify(ms, NULL);
565 vty_notify(ms, "No alerting call\n");
569 LOGP(DMNCC, LOGL_INFO, "Answer but we have an active call\n");
570 vty_notify(ms, NULL);
571 vty_notify(ms, "Please put active call on hold first!\n");
577 memset(&rsp, 0, sizeof(struct gsm_mncc));
578 rsp.callref = alerting->callref;
579 return mncc_send(ms, MNCC_SETUP_RSP, &rsp);
582 int mncc_hold(struct osmocom_ms *ms)
584 struct gsm_call *call, *found = NULL;
585 struct gsm_mncc hold;
587 llist_for_each_entry(call, &call_list, entry) {
594 LOGP(DMNCC, LOGL_INFO, "No active call to hold\n");
595 vty_notify(ms, NULL);
596 vty_notify(ms, "No active call\n");
600 memset(&hold, 0, sizeof(struct gsm_mncc));
601 hold.callref = found->callref;
602 return mncc_send(ms, MNCC_HOLD_REQ, &hold);
605 int mncc_retrieve(struct osmocom_ms *ms, int number)
607 struct gsm_call *call;
608 struct gsm_mncc retr;
609 int holdnum = 0, active = 0, i = 0;
611 llist_for_each_entry(call, &call_list, entry) {
618 LOGP(DMNCC, LOGL_INFO, "Cannot retrieve during active call\n");
619 vty_notify(ms, NULL);
620 vty_notify(ms, "Hold active call first!\n");
624 vty_notify(ms, NULL);
625 vty_notify(ms, "No call on hold!\n");
628 if (holdnum > 1 && number <= 0) {
629 vty_notify(ms, NULL);
630 vty_notify(ms, "Select call 1..%d\n", holdnum);
633 if (holdnum == 1 && number <= 0)
635 if (number > holdnum) {
636 vty_notify(ms, NULL);
637 vty_notify(ms, "Given number %d out of range!\n", number);
638 vty_notify(ms, "Select call 1..%d\n", holdnum);
642 llist_for_each_entry(call, &call_list, entry) {
648 memset(&retr, 0, sizeof(struct gsm_mncc));
649 retr.callref = call->callref;
650 return mncc_send(ms, MNCC_RETRIEVE_REQ, &retr);