From: Andreas.Eversberg Date: Sun, 20 Jun 2010 17:43:55 +0000 (+0000) Subject: layer23: Added support for waiting calls, hold/retrieve calls. X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=17e0a2c07501fce7ed790845c372878fbe0e52bb;p=osmocom-bb.git layer23: Added support for waiting calls, hold/retrieve calls. --- diff --git a/src/host/layer23/include/osmocom/mncc.h b/src/host/layer23/include/osmocom/mncc.h index 0b5ddea..d1d4d38 100644 --- a/src/host/layer23/include/osmocom/mncc.h +++ b/src/host/layer23/include/osmocom/mncc.h @@ -35,6 +35,9 @@ struct gsm_call { void *ms; uint32_t callref; + + uint8_t hold; /* call on hold */ + uint8_t ring; /* call is ringing/knocking */ }; #define MNCC_SETUP_REQ 0x0101 diff --git a/src/host/layer23/include/osmocom/settings.h b/src/host/layer23/include/osmocom/settings.h index 895d8c8..70cceea 100644 --- a/src/host/layer23/include/osmocom/settings.h +++ b/src/host/layer23/include/osmocom/settings.h @@ -20,6 +20,9 @@ struct gsm_settings { uint8_t test_rplmn_valid; uint16_t test_rplmn_mcc, test_rplmn_mnc; uint8_t test_always; /* ...search hplmn... */ + + /* call related settings */ + uint8_t cw; /* set if call-waiting is allowed */ }; int gsm_settings_init(struct osmocom_ms *ms); diff --git a/src/host/layer23/src/mnccms.c b/src/host/layer23/src/mnccms.c index bf1690b..1dda80b 100644 --- a/src/host/layer23/src/mnccms.c +++ b/src/host/layer23/src/mnccms.c @@ -104,7 +104,6 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) if (msg_type == MNCC_REL_IND || msg_type == MNCC_REL_CNF) return 0; cause = GSM48_CC_CAUSE_INCOMPAT_DEST; - release: memset(&mncc, 0, sizeof(struct gsm_mncc)); mncc.callref = data->callref; @@ -211,8 +210,8 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) break; case MNCC_SETUP_IND: vty_notify(ms, NULL); - if (!llist_empty(&call_list)) { - vty_notify(ms, "Incomming call rejected\n"); + if (!llist_empty(&call_list) && !ms->settings.cw) { + vty_notify(ms, "Incomming call rejected while busy\n"); LOGP(DMNCC, LOGL_INFO, "Incomming call but busy\n"); cause = GSM48_CC_CAUSE_NORM_CALL_CLEAR; goto release; @@ -232,11 +231,39 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) memset(&mncc, 0, sizeof(struct gsm_mncc)); mncc.callref = call->callref; mncc_send(ms, MNCC_CALL_CONF_REQ, &mncc); - LOGP(DMNCC, LOGL_INFO, "Ring!\n"); + if (llist_empty(&call_list)) + LOGP(DMNCC, LOGL_INFO, "Ring!\n"); + else { + LOGP(DMNCC, LOGL_INFO, "Knock!\n"); + call->hold = 1; + } + call->ring = 1; memset(&mncc, 0, sizeof(struct gsm_mncc)); mncc.callref = call->callref; mncc_send(ms, MNCC_ALERT_REQ, &mncc); break; + case MNCC_HOLD_CNF: + vty_notify(ms, NULL); + vty_notify(ms, "Call is on hold\n"); + LOGP(DMNCC, LOGL_INFO, "Call is on hold\n"); + call->hold = 1; + break; + case MNCC_HOLD_REJ: + vty_notify(ms, NULL); + vty_notify(ms, "Call hold was rejected\n"); + LOGP(DMNCC, LOGL_INFO, "Call hold was rejected\n"); + break; + case MNCC_RETRIEVE_CNF: + vty_notify(ms, NULL); + vty_notify(ms, "Call is retrieved\n"); + LOGP(DMNCC, LOGL_INFO, "Call is retrieved\n"); + call->hold = 0; + break; + case MNCC_RETRIEVE_REJ: + vty_notify(ms, NULL); + vty_notify(ms, "Call retrieve was rejected\n"); + LOGP(DMNCC, LOGL_INFO, "Call retrieve was rejected\n"); + break; default: LOGP(DMNCC, LOGL_INFO, "Message 0x%02x unsupported\n", msg_type); @@ -251,9 +278,14 @@ int mncc_call(struct osmocom_ms *ms, char *number) struct gsm_call *call; struct gsm_mncc setup; - if (!llist_empty(&call_list)) { - LOGP(DMNCC, LOGL_INFO, "Cannot make a call, busy!\n"); - return -EBUSY; + llist_for_each_entry(call, &call_list, entry) { + if (!call->hold) { + vty_notify(ms, NULL); + vty_notify(ms, "Please put active call on hold " + "first!\n"); + LOGP(DMNCC, LOGL_INFO, "Cannot make a call, busy!\n"); + return -EBUSY; + } } call = talloc_zero(l23_ctx, struct gsm_call); @@ -292,17 +324,24 @@ int mncc_call(struct osmocom_ms *ms, char *number) int mncc_hangup(struct osmocom_ms *ms) { - struct gsm_call *call; + struct gsm_call *call, *found = NULL; struct gsm_mncc disc; - if (llist_empty(&call_list)) { + llist_for_each_entry(call, &call_list, entry) { + if (!call->hold) { + found = call; + break; + } + } + if (!found) { LOGP(DMNCC, LOGL_INFO, "No active call to hangup\n"); - return -EBUSY; + vty_notify(ms, NULL); + vty_notify(ms, "No active call\n"); + return -EINVAL; } - call = llist_entry(call_list.next, struct gsm_call, entry); memset(&disc, 0, sizeof(struct gsm_mncc)); - disc.callref = call->callref; + disc.callref = found->callref; mncc_set_cause(&disc, GSM48_CAUSE_LOC_USER, GSM48_CC_CAUSE_NORM_CALL_CLEAR); return mncc_send(ms, MNCC_DISC_REQ, &disc); @@ -310,22 +349,106 @@ int mncc_hangup(struct osmocom_ms *ms) int mncc_answer(struct osmocom_ms *ms) { - struct gsm_call *call; + struct gsm_call *call, *alerting = NULL; struct gsm_mncc rsp; + int active = 0; - if (llist_empty(&call_list)) { - LOGP(DMNCC, LOGL_INFO, "No call to answer\n"); + llist_for_each_entry(call, &call_list, entry) { + if (call->ring) + alerting = call; + if (!call->hold) + active = 1; + } + if (!alerting) { + LOGP(DMNCC, LOGL_INFO, "No call alerting\n"); + vty_notify(ms, NULL); + vty_notify(ms, "No alerting call\n"); return -EBUSY; } - call = llist_entry(call_list.next, struct gsm_call, entry); + if (active) { + LOGP(DMNCC, LOGL_INFO, "Answer but we have an active call\n"); + vty_notify(ms, NULL); + vty_notify(ms, "Please put active call on hold first!\n"); + return -EBUSY; + } + alerting->ring = 0; memset(&rsp, 0, sizeof(struct gsm_mncc)); - rsp.callref = call->callref; - mncc_set_cause(&rsp, GSM48_CAUSE_LOC_USER, - GSM48_CC_CAUSE_NORM_CALL_CLEAR); + rsp.callref = alerting->callref; return mncc_send(ms, MNCC_SETUP_RSP, &rsp); } +int mncc_hold(struct osmocom_ms *ms) +{ + struct gsm_call *call, *found = NULL; + struct gsm_mncc hold; + + llist_for_each_entry(call, &call_list, entry) { + if (!call->hold) { + found = call; + break; + } + } + if (!found) { + LOGP(DMNCC, LOGL_INFO, "No active call to hold\n"); + vty_notify(ms, NULL); + vty_notify(ms, "No active call\n"); + return -EINVAL; + } + + memset(&hold, 0, sizeof(struct gsm_mncc)); + hold.callref = found->callref; + return mncc_send(ms, MNCC_HOLD_REQ, &hold); +} + +int mncc_retrieve(struct osmocom_ms *ms, int number) +{ + struct gsm_call *call; + struct gsm_mncc retr; + int holdnum = 0, active = 0, i = 0; + + llist_for_each_entry(call, &call_list, entry) { + if (call->hold) + holdnum++; + if (!call->hold) + active = 1; + } + if (active) { + LOGP(DMNCC, LOGL_INFO, "Cannot retrieve during active call\n"); + vty_notify(ms, NULL); + vty_notify(ms, "Hold active call first!\n"); + return -EINVAL; + } + if (holdnum == 0) { + vty_notify(ms, NULL); + vty_notify(ms, "No call on hold!\n"); + return -EINVAL; + } + if (holdnum > 1 && number <= 0) { + vty_notify(ms, NULL); + vty_notify(ms, "Select call 1..%d\n", holdnum); + return -EINVAL; + } + if (holdnum == 1 && number <= 0) + number = 1; + if (number > holdnum) { + vty_notify(ms, NULL); + vty_notify(ms, "Given number %d out of range!\n", number); + vty_notify(ms, "Select call 1..%d\n", holdnum); + return -EINVAL; + } + + llist_for_each_entry(call, &call_list, entry) { + i++; + if (i == number) + break; + } + + memset(&retr, 0, sizeof(struct gsm_mncc)); + retr.callref = call->callref; + return mncc_send(ms, MNCC_RETRIEVE_REQ, &retr); +} + diff --git a/src/host/layer23/src/vty_interface.c b/src/host/layer23/src/vty_interface.c index 4651a7a..8e9f55f 100644 --- a/src/host/layer23/src/vty_interface.c +++ b/src/host/layer23/src/vty_interface.c @@ -38,6 +38,8 @@ int mncc_call(struct osmocom_ms *ms, char *number); int mncc_hangup(struct osmocom_ms *ms); int mncc_answer(struct osmocom_ms *ms); +int mncc_hold(struct osmocom_ms *ms); +int mncc_retrieve(struct osmocom_ms *ms, int number); extern struct llist_head ms_list; @@ -406,9 +408,10 @@ DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC", return CMD_SUCCESS; } -DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup)", +DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)", "Make a call\nName of MS (see \"show ms\")\nPhone number to call\n" - "Make an emergency call\nAnswer an incomming call\nHangup a call") + "Make an emergency call\nAnswer an incomming call\nHangup a call\n" + "Hold current active call\n") { struct osmocom_ms *ms; @@ -421,7 +424,10 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup)", mncc_answer(ms); break; case 'h': - mncc_hangup(ms); + if (argv[1][1] == 'a') + mncc_hangup(ms); + else + mncc_hold(ms); break; default: mncc_call(ms, (char *)argv[1]); @@ -430,6 +436,21 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup)", return CMD_SUCCESS; } +DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]", + "Make a call\nName of MS (see \"show ms\")\n" + "Retrieve call on hold\nNumber of call to retrieve") +{ + struct osmocom_ms *ms; + + ms = get_ms(argv[0], vty); + if (!ms) + return CMD_WARNING; + + mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0); + + return CMD_SUCCESS; +} + DEFUN(network_show, network_show_cmd, "network show MS_NAME", "Network ...\nShow results of network search (again)\n" "Name of MS (see \"show ms\")") @@ -519,6 +540,7 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) vty_out(vty, " imei-fixed%s", VTY_NEWLINE); vty_out(vty, " emergency-imsi %s%s", (ms->settings.emergency_imsi[0]) ? ms->settings.emergency_imsi : "none", VTY_NEWLINE); + vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE); vty_out(vty, " test-sim%s", VTY_NEWLINE); vty_out(vty, " imsi %s%s", ms->settings.test_imsi, VTY_NEWLINE); vty_out(vty, " %sbarred-access%s", (set->test_barr) ? "" : "no ", @@ -637,6 +659,26 @@ DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi (none|IMSI)", return CMD_SUCCESS; } +DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting", + "Disallow waiting calls") +{ + struct osmocom_ms *ms = vty->index; + + ms->settings.cw = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting", + "Allow waiting calls") +{ + struct osmocom_ms *ms = vty->index; + + ms->settings.cw = 1; + + return CMD_SUCCESS; +} + DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|test)", "Set sim card type when powering on\nNo sim interted\n" "Test sim inserted") @@ -789,6 +831,7 @@ int ms_vty_init(void) install_element(ENABLE_NODE, &network_show_cmd); install_element(ENABLE_NODE, &network_select_cmd); install_element(ENABLE_NODE, &call_cmd); + install_element(ENABLE_NODE, &call_retr_cmd); install_element(CONFIG_NODE, &cfg_ms_cmd); install_node(&ms_node, config_write_ms); @@ -798,6 +841,8 @@ int ms_vty_init(void) install_element(MS_NODE, &cfg_ms_imei_fixed_cmd); install_element(MS_NODE, &cfg_ms_imei_random_cmd); install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd); + install_element(MS_NODE, &cfg_ms_cw_cmd); + install_element(MS_NODE, &cfg_ms_no_cw_cmd); install_element(MS_NODE, &cfg_ms_sim_cmd); install_element(MS_NODE, &cfg_testsim_cmd);