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_settings *set, 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_settings *set = &ms->settings;
122 mncc->fields |= MNCC_F_BEARER_CAP;
123 mncc->bearer_cap.coding = 0;
124 if (set->ch_cap == GSM_CAP_SDCCH_TCHF_TCHH
125 && (set->half_v1 || set->half_v3)) {
126 mncc->bearer_cap.radio = 3;
127 LOGP(DMNCC, LOGL_INFO, " support TCH/H also\n");
129 mncc->bearer_cap.radio = 1;
130 LOGP(DMNCC, LOGL_INFO, " support TCH/F only\n");
132 mncc->bearer_cap.speech_ctm = 0;
133 /* if no specific speech_ver is given */
134 if (speech_ver < 0) {
135 /* if half rate is supported and prefered */
136 if (set->half_v3 && set->half && set->half_prefer) {
137 mncc->bearer_cap.speech_ver[i++] = 5;
138 LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
140 if (set->half_v1 && set->half && set->half_prefer) {
141 mncc->bearer_cap.speech_ver[i++] = 1;
142 LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
144 /* if full rate is supported */
146 mncc->bearer_cap.speech_ver[i++] = 4;
147 LOGP(DMNCC, LOGL_INFO, " support full rate v3\n");
150 mncc->bearer_cap.speech_ver[i++] = 2;
151 LOGP(DMNCC, LOGL_INFO, " support full rate v2\n");
153 if (set->full_v1) { /* mandatory, so it's always true */
154 mncc->bearer_cap.speech_ver[i++] = 0;
155 LOGP(DMNCC, LOGL_INFO, " support full rate v1\n");
157 /* if half rate is supported and not prefered */
158 if (set->half_v3 && set->half && !set->half_prefer) {
159 mncc->bearer_cap.speech_ver[i++] = 5;
160 LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
162 if (set->half_v1 && set->half && !set->half_prefer) {
163 mncc->bearer_cap.speech_ver[i++] = 1;
164 LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
166 /* if specific speech_ver is given (it must be supported) */
168 mncc->bearer_cap.speech_ver[i++] = speech_ver;
169 mncc->bearer_cap.speech_ver[i] = -1; /* end of list */
170 mncc->bearer_cap.transfer = 0;
171 mncc->bearer_cap.mode = 0;
175 * MNCCms dummy application
178 /* this is a minimal implementation as required by GSM 04.08 */
179 int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg)
181 struct gsm_mncc *data = arg;
182 uint32_t callref = data->callref;
185 if (msg_type == MNCC_REL_IND || msg_type == MNCC_REL_CNF)
188 LOGP(DMNCC, LOGL_INFO, "Rejecting incomming call\n");
190 /* reject, as we don't support Calls */
191 memset(&rel, 0, sizeof(struct gsm_mncc));
192 rel.callref = callref;
193 mncc_set_cause(&rel, GSM48_CAUSE_LOC_USER,
194 GSM48_CC_CAUSE_INCOMPAT_DEST);
196 return mncc_send(ms, MNCC_REL_REQ, &rel);
200 * MNCCms basic call application
203 int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
205 struct gsm_settings *set = &ms->settings;
206 struct gsm_mncc *data = arg;
207 struct gsm_call *call = get_call_ref(data->callref);
208 struct gsm_mncc mncc;
210 int8_t speech_ver = -1, speech_ver_half = -1, temp;
213 /* call does not exist */
214 if (!call && msg_type != MNCC_SETUP_IND) {
215 LOGP(DMNCC, LOGL_INFO, "Rejecting incomming call "
216 "(callref %x)\n", data->callref);
217 if (msg_type == MNCC_REL_IND || msg_type == MNCC_REL_CNF)
219 cause = GSM48_CC_CAUSE_INCOMPAT_DEST;
221 memset(&mncc, 0, sizeof(struct gsm_mncc));
222 mncc.callref = data->callref;
223 mncc_set_cause(&mncc, GSM48_CAUSE_LOC_USER, cause);
224 return mncc_send(ms, MNCC_REL_REQ, &mncc);
227 /* setup without call */
229 if (llist_empty(&call_list))
231 call = talloc_zero(l23_ctx, struct gsm_call);
234 call->callref = data->callref;
235 llist_add_tail(&call->entry, &call_list);
238 /* not in initiated state anymore */
243 vty_notify(ms, NULL);
244 switch (data->cause.value) {
245 case GSM48_CC_CAUSE_UNASSIGNED_NR:
246 vty_notify(ms, "Call: Number not assigned\n");
248 case GSM48_CC_CAUSE_NO_ROUTE:
249 vty_notify(ms, "Call: Destination unreachable\n");
251 case GSM48_CC_CAUSE_NORM_CALL_CLEAR:
252 vty_notify(ms, "Call: Remote hangs up\n");
254 case GSM48_CC_CAUSE_USER_BUSY:
255 vty_notify(ms, "Call: Remote busy\n");
257 case GSM48_CC_CAUSE_USER_NOTRESPOND:
258 vty_notify(ms, "Call: Remote not responding\n");
260 case GSM48_CC_CAUSE_USER_ALERTING_NA:
261 vty_notify(ms, "Call: Remote not answering\n");
263 case GSM48_CC_CAUSE_CALL_REJECTED:
264 vty_notify(ms, "Call has been rejected\n");
266 case GSM48_CC_CAUSE_NUMBER_CHANGED:
267 vty_notify(ms, "Call: Number changed\n");
269 case GSM48_CC_CAUSE_PRE_EMPTION:
270 vty_notify(ms, "Call: Cleared due to pre-emption\n");
272 case GSM48_CC_CAUSE_DEST_OOO:
273 vty_notify(ms, "Call: Remote out of order\n");
275 case GSM48_CC_CAUSE_INV_NR_FORMAT:
276 vty_notify(ms, "Call: Number invalid or imcomplete\n");
278 case GSM48_CC_CAUSE_NO_CIRCUIT_CHAN:
279 vty_notify(ms, "Call: No channel available\n");
281 case GSM48_CC_CAUSE_NETWORK_OOO:
282 vty_notify(ms, "Call: Network out of order\n");
284 case GSM48_CC_CAUSE_TEMP_FAILURE:
285 vty_notify(ms, "Call: Temporary failure\n");
287 case GSM48_CC_CAUSE_SWITCH_CONG:
288 vty_notify(ms, "Congestion\n");
291 vty_notify(ms, "Call has been disconnected\n");
293 LOGP(DMNCC, LOGL_INFO, "Call has been disconnected "
294 "(cause %d)\n", data->cause.value);
295 if ((data->fields & MNCC_F_PROGRESS)
296 && data->progress.descr == 8) {
297 vty_notify(ms, "Please hang up!\n");
301 cause = GSM48_CC_CAUSE_NORM_CALL_CLEAR;
305 vty_notify(ms, NULL);
306 if (data->cause.value == GSM48_CC_CAUSE_CALL_REJECTED)
307 vty_notify(ms, "Call has been rejected\n");
309 vty_notify(ms, "Call has been released\n");
310 LOGP(DMNCC, LOGL_INFO, "Call has been released (cause %d)\n",
314 case MNCC_CALL_PROC_IND:
315 vty_notify(ms, NULL);
316 vty_notify(ms, "Call is proceeding\n");
317 LOGP(DMNCC, LOGL_INFO, "Call is proceeding\n");
318 if ((data->fields & MNCC_F_BEARER_CAP)
319 && data->bearer_cap.speech_ver[0] >= 0) {
320 mncc_get_bearer(set, data->bearer_cap.speech_ver[0]);
324 vty_notify(ms, NULL);
325 vty_notify(ms, "Call is aleriting\n");
326 LOGP(DMNCC, LOGL_INFO, "Call is alerting\n");
329 vty_notify(ms, NULL);
330 vty_notify(ms, "Call is answered\n");
331 LOGP(DMNCC, LOGL_INFO, "Call is answered\n");
334 vty_notify(ms, NULL);
335 if (!first_call && !ms->settings.cw) {
336 vty_notify(ms, "Incomming call rejected while busy\n");
337 LOGP(DMNCC, LOGL_INFO, "Incomming call but busy\n");
338 cause = GSM48_CC_CAUSE_USER_BUSY;
341 /* select first supported speech_ver */
342 if ((data->fields & MNCC_F_BEARER_CAP)) {
345 for (i = 0; data->bearer_cap.speech_ver[i] >= 0; i++) {
347 temp = mncc_get_bearer(set,
348 data->bearer_cap.speech_ver[i]);
351 if (temp == 5 || temp == 1) { /* half */
352 /* only the first half rate */
353 if (speech_ver_half < 0)
354 speech_ver_half = temp;
356 /* only the first full rate */
361 /* half and full given */
362 if (speech_ver_half >= 0 && speech_ver >= 0) {
363 if (set->half_prefer) {
364 LOGP(DMNCC, LOGL_INFO, " both supported"
365 " codec rates are given, using "
366 "preferred half rate\n");
367 speech_ver = speech_ver_half;
369 LOGP(DMNCC, LOGL_INFO, " both supported"
370 " codec rates are given, using "
371 "preferred full rate\n");
372 } else if (speech_ver_half < 0 && speech_ver < 0) {
373 LOGP(DMNCC, LOGL_INFO, " no supported codec "
375 /* only half rate is given, use it */
376 } else if (speech_ver_half >= 0) {
377 LOGP(DMNCC, LOGL_INFO, " only supported half "
378 "rate codec is given, using it\n");
379 speech_ver = speech_ver_half;
380 /* only full rate is given, use it */
382 LOGP(DMNCC, LOGL_INFO, " only supported full "
383 "rate codec is given, using it\n");
386 /* presentation allowed if present == 0 */
387 if (data->calling.present || !data->calling.number[0])
388 vty_notify(ms, "Incomming call (anonymous)\n");
389 else if (data->calling.type == 1)
390 vty_notify(ms, "Incomming call (from +%s)\n",
391 data->calling.number);
392 else if (data->calling.type == 2)
393 vty_notify(ms, "Incomming call (from 0-%s)\n",
394 data->calling.number);
396 vty_notify(ms, "Incomming call (from %s)\n",
397 data->calling.number);
398 LOGP(DMNCC, LOGL_INFO, "Incomming call (from %s callref %x)\n",
399 data->calling.number, call->callref);
400 memset(&mncc, 0, sizeof(struct gsm_mncc));
401 mncc.callref = call->callref;
402 /* only include bearer cap, if not given in setup
403 * or if multiple codecs are given
404 * or if not only full rate
405 * or if given codec is unimplemented
407 if (!(data->fields & MNCC_F_BEARER_CAP) || speech_ver < 0)
408 mncc_set_bearer(ms, -1, &mncc);
409 else if (data->bearer_cap.speech_ver[1] >= 0
411 mncc_set_bearer(ms, speech_ver, &mncc);
412 mncc_send(ms, MNCC_CALL_CONF_REQ, &mncc);
414 LOGP(DMNCC, LOGL_INFO, "Ring!\n");
416 LOGP(DMNCC, LOGL_INFO, "Knock!\n");
420 memset(&mncc, 0, sizeof(struct gsm_mncc));
421 mncc.callref = call->callref;
422 mncc_send(ms, MNCC_ALERT_REQ, &mncc);
424 case MNCC_SETUP_COMPL_IND:
425 vty_notify(ms, NULL);
426 vty_notify(ms, "Call is connected\n");
427 LOGP(DMNCC, LOGL_INFO, "Call is connected\n");
430 vty_notify(ms, NULL);
431 vty_notify(ms, "Call is on hold\n");
432 LOGP(DMNCC, LOGL_INFO, "Call is on hold\n");
436 vty_notify(ms, NULL);
437 vty_notify(ms, "Call hold was rejected\n");
438 LOGP(DMNCC, LOGL_INFO, "Call hold was rejected\n");
440 case MNCC_RETRIEVE_CNF:
441 vty_notify(ms, NULL);
442 vty_notify(ms, "Call is retrieved\n");
443 LOGP(DMNCC, LOGL_INFO, "Call is retrieved\n");
446 case MNCC_RETRIEVE_REJ:
447 vty_notify(ms, NULL);
448 vty_notify(ms, "Call retrieve was rejected\n");
449 LOGP(DMNCC, LOGL_INFO, "Call retrieve was rejected\n");
452 LOGP(DMNCC, LOGL_INFO, "Message 0x%02x unsupported\n",
460 int mncc_call(struct osmocom_ms *ms, char *number)
462 struct gsm_call *call;
463 struct gsm_mncc setup;
465 llist_for_each_entry(call, &call_list, entry) {
467 vty_notify(ms, NULL);
468 vty_notify(ms, "Please put active call on hold "
470 LOGP(DMNCC, LOGL_INFO, "Cannot make a call, busy!\n");
475 call = talloc_zero(l23_ctx, struct gsm_call);
478 call->callref = new_callref++;
480 llist_add_tail(&call->entry, &call_list);
482 memset(&setup, 0, sizeof(struct gsm_mncc));
483 setup.callref = call->callref;
485 if (!strncasecmp(number, "emerg", 5)) {
486 LOGP(DMNCC, LOGL_INFO, "Make emergency call\n");
490 LOGP(DMNCC, LOGL_INFO, "Make call to %s\n", number);
492 setup.fields |= MNCC_F_CALLED;
493 if (number[0] == '+') {
495 setup.called.type = 1; /* international */
497 setup.called.type = 0; /* auto/unknown - prefix must be
499 setup.called.plan = 1; /* ISDN */
500 strncpy(setup.called.number, number,
501 sizeof(setup.called.number) - 1);
503 /* bearer capability (mandatory) */
504 mncc_set_bearer(ms, -1, &setup);
505 if (ms->settings.clir)
507 else if (ms->settings.clip)
511 return mncc_send(ms, MNCC_SETUP_REQ, &setup);
514 int mncc_hangup(struct osmocom_ms *ms)
516 struct gsm_call *call, *found = NULL;
517 struct gsm_mncc disc;
519 llist_for_each_entry(call, &call_list, entry) {
526 LOGP(DMNCC, LOGL_INFO, "No active call to hangup\n");
527 vty_notify(ms, NULL);
528 vty_notify(ms, "No active call\n");
532 memset(&disc, 0, sizeof(struct gsm_mncc));
533 disc.callref = found->callref;
534 mncc_set_cause(&disc, GSM48_CAUSE_LOC_USER,
535 GSM48_CC_CAUSE_NORM_CALL_CLEAR);
536 return mncc_send(ms, (call->init) ? MNCC_REL_REQ : MNCC_DISC_REQ,
540 int mncc_answer(struct osmocom_ms *ms)
542 struct gsm_call *call, *alerting = NULL;
546 llist_for_each_entry(call, &call_list, entry) {
549 else if (!call->hold)
553 LOGP(DMNCC, LOGL_INFO, "No call alerting\n");
554 vty_notify(ms, NULL);
555 vty_notify(ms, "No alerting call\n");
559 LOGP(DMNCC, LOGL_INFO, "Answer but we have an active call\n");
560 vty_notify(ms, NULL);
561 vty_notify(ms, "Please put active call on hold first!\n");
567 memset(&rsp, 0, sizeof(struct gsm_mncc));
568 rsp.callref = alerting->callref;
569 return mncc_send(ms, MNCC_SETUP_RSP, &rsp);
572 int mncc_hold(struct osmocom_ms *ms)
574 struct gsm_call *call, *found = NULL;
575 struct gsm_mncc hold;
577 llist_for_each_entry(call, &call_list, entry) {
584 LOGP(DMNCC, LOGL_INFO, "No active call to hold\n");
585 vty_notify(ms, NULL);
586 vty_notify(ms, "No active call\n");
590 memset(&hold, 0, sizeof(struct gsm_mncc));
591 hold.callref = found->callref;
592 return mncc_send(ms, MNCC_HOLD_REQ, &hold);
595 int mncc_retrieve(struct osmocom_ms *ms, int number)
597 struct gsm_call *call;
598 struct gsm_mncc retr;
599 int holdnum = 0, active = 0, i = 0;
601 llist_for_each_entry(call, &call_list, entry) {
608 LOGP(DMNCC, LOGL_INFO, "Cannot retrieve during active call\n");
609 vty_notify(ms, NULL);
610 vty_notify(ms, "Hold active call first!\n");
614 vty_notify(ms, NULL);
615 vty_notify(ms, "No call on hold!\n");
618 if (holdnum > 1 && number <= 0) {
619 vty_notify(ms, NULL);
620 vty_notify(ms, "Select call 1..%d\n", holdnum);
623 if (holdnum == 1 && number <= 0)
625 if (number > holdnum) {
626 vty_notify(ms, NULL);
627 vty_notify(ms, "Given number %d out of range!\n", number);
628 vty_notify(ms, "Select call 1..%d\n", holdnum);
632 llist_for_each_entry(call, &call_list, entry) {
638 memset(&retr, 0, sizeof(struct gsm_mncc));
639 retr.callref = call->callref;
640 return mncc_send(ms, MNCC_RETRIEVE_REQ, &retr);