/* * (C) 2016 by Holger Hans Peter Freyther * (C) 2018 by Harald Welte * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include "vty.h" #include "app.h" #include "call.h" #include "mncc.h" #include #include extern void *tall_mncc_ctx; struct app_config g_app; static int mncc_vty_go_parent(struct vty *vty); static int mncc_vty_is_config_node(struct vty *vty, int node); static struct cmd_node sip_node = { SIP_NODE, "%s(config-sip)# ", 1, }; static struct cmd_node mncc_node = { MNCC_NODE, "%s(config-mncc)# ", 1, }; static struct cmd_node app_node = { APP_NODE, "%s(config-app)# ", 1, }; static struct vty_app_info vty_info = { .name = "OsmoSIPcon", .version = PACKAGE_VERSION, .go_parent_cb = mncc_vty_go_parent, .is_config_node = mncc_vty_is_config_node, .copyright = "GNU AGPLv3+\n", }; static int mncc_vty_go_parent(struct vty *vty) { switch (vty->node) { case SIP_NODE: case MNCC_NODE: case APP_NODE: vty->node = CONFIG_NODE; vty->index = NULL; break; default: if (mncc_vty_is_config_node(vty, vty->node)) vty->node = CONFIG_NODE; else vty->node = ENABLE_NODE; vty->index = NULL; break; } return vty->node; } static int mncc_vty_is_config_node(struct vty *vty, int node) { return node >= SIP_NODE; } static int config_write_sip(struct vty *vty) { vty_out(vty, "sip%s", VTY_NEWLINE); vty_out(vty, " local %s %d%s", g_app.sip.local_addr, g_app.sip.local_port, VTY_NEWLINE); vty_out(vty, " remote %s %d%s", g_app.sip.remote_addr, g_app.sip.remote_port, VTY_NEWLINE); vty_out(vty, " sofia-sip log-level %d%s", g_app.sip.sofia_log_level, VTY_NEWLINE); return CMD_SUCCESS; } static int config_write_mncc(struct vty *vty) { vty_out(vty, "mncc%s", VTY_NEWLINE); vty_out(vty, " socket-path %s%s", g_app.mncc.path, VTY_NEWLINE); return CMD_SUCCESS; } static int config_write_app(struct vty *vty) { vty_out(vty, "app%s", VTY_NEWLINE); if (g_app.use_imsi_as_id) vty_out(vty, " use-imsi%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN(cfg_sip, cfg_sip_cmd, "sip", "SIP related commands\n") { vty->node = SIP_NODE; return CMD_SUCCESS; } DEFUN(cfg_sip_local_addr, cfg_sip_local_addr_cmd, "local A.B.C.D <1-65534>", "Local information\nIPv4 bind address\nport\n") { talloc_free((char *) g_app.sip.local_addr); g_app.sip.local_addr = talloc_strdup(tall_mncc_ctx, argv[0]); g_app.sip.local_port = atoi(argv[1]); return CMD_SUCCESS; } DEFUN(cfg_sip_remote_addr, cfg_sip_remote_addr_cmd, "remote ADDR <1-65534>", "Remote information\nSIP hostname\nport\n") { talloc_free((char *) g_app.sip.remote_addr); g_app.sip.remote_addr = talloc_strdup(tall_mncc_ctx, argv[0]); g_app.sip.remote_port = atoi(argv[1]); return CMD_SUCCESS; } DEFUN(cfg_sip_sofia_log_level, cfg_sip_sofia_log_level_cmd, "sofia-sip log-level <0-9>", "sofia-sip library configuration\n" "global log-level for sofia-sip\n" "(0 = nothing, 9 = super-verbose)\n") { g_app.sip.sofia_log_level = atoi(argv[0]); su_log_set_level(su_log_default, g_app.sip.sofia_log_level); su_log_set_level(su_log_global, g_app.sip.sofia_log_level); return CMD_SUCCESS; } DEFUN(cfg_mncc, cfg_mncc_cmd, "mncc", "MNCC\n") { vty->node = MNCC_NODE; return CMD_SUCCESS; } DEFUN(cfg_mncc_path, cfg_mncc_path_cmd, "socket-path NAME", "MNCC filepath\nFilename\n") { talloc_free((char *) g_app.mncc.path); g_app.mncc.path = talloc_strdup(tall_mncc_ctx, argv[0]); return CMD_SUCCESS; } DEFUN(cfg_app, cfg_app_cmd, "app", "Application Handling\n") { vty->node = APP_NODE; return CMD_SUCCESS; } DEFUN(cfg_use_imsi, cfg_use_imsi_cmd, "use-imsi", "Use the IMSI for MO calling and MT called address\n") { g_app.use_imsi_as_id = 1; return CMD_SUCCESS; } DEFUN(cfg_no_use_imsi, cfg_no_use_imsi_cmd, "no use-imsi", NO_STR "Use the IMSI for MO calling and MT called address\n") { g_app.use_imsi_as_id = 0; return CMD_SUCCESS; } static void dump_leg(struct vty *vty, struct call_leg *leg, const char *kind) { struct sip_call_leg *sip; struct mncc_call_leg *mncc; if (!leg) return; vty_out(vty, " %s leg of type: %s%s", kind, get_value_string(call_type_vals, leg->type), VTY_NEWLINE); switch (leg->type) { case CALL_TYPE_SIP: sip = (struct sip_call_leg *) leg; vty_out(vty, " SIP nua_handle(%p)%s", sip->nua_handle, VTY_NEWLINE); vty_out(vty, " SIP state(%s)%s", get_value_string(sip_state_vals, sip->state), VTY_NEWLINE); vty_out(vty, " SIP dir(%s)%s", get_value_string(sip_dir_vals, sip->dir), VTY_NEWLINE); vty_out(vty, " SIP wanted_codec(%s)%s", sip->wanted_codec, VTY_NEWLINE); break; case CALL_TYPE_MNCC: mncc = (struct mncc_call_leg *) leg; vty_out(vty, " MNCC state(%s)%s", get_value_string(mncc_state_vals, mncc->state), VTY_NEWLINE); vty_out(vty, " MNCC dir(%s)%s", get_value_string(mncc_dir_vals, mncc->dir), VTY_NEWLINE); vty_out(vty, " MNCC callref(%u)%s", mncc->callref, VTY_NEWLINE); vty_out(vty, " MNCC called TON(%d) NPI(%d) NUM(%.32s)%s", mncc->called.type, mncc->called.plan, mncc->called.number, VTY_NEWLINE); vty_out(vty, " MNCC calling TON(%d) NPI(%d) NUM(%.32s)%s", mncc->calling.type, mncc->calling.plan, mncc->calling.number, VTY_NEWLINE); vty_out(vty, " MNCC imsi(%.16s)%s", mncc->imsi, VTY_NEWLINE); vty_out(vty, " MNCC timer pending(%d)%s", osmo_timer_pending(&mncc->cmd_timeout), VTY_NEWLINE); break; default: vty_out(vty, " Unhandled type: %d%s", leg->type, VTY_NEWLINE); break; } } DEFUN(show_calls, show_calls_cmd, "show calls", SHOW_STR "Current calls\n") { struct call *call; llist_for_each_entry(call, &g_call_list, entry) { vty_out(vty, "Call(%u) from %s to %s%s", call->id, call->source, call->dest, VTY_NEWLINE); dump_leg(vty, call->initial, "Initial"); dump_leg(vty, call->remote, "Remote"); } return CMD_SUCCESS; } DEFUN(show_calls_sum, show_calls_sum_cmd, "show calls summary", SHOW_STR "Current calls\nBrief overview\n") { /* don't print a table for zero active calls */ if(llist_empty(&g_call_list)) { vty_out(vty, "No active calls.%s", VTY_NEWLINE); return CMD_SUCCESS; } /* table head */ vty_out(vty, "ID From To State%s", VTY_NEWLINE); vty_out(vty, "----- -------------------------------- -------------------------------- ----------%s", VTY_NEWLINE); /* iterate over calls */ struct call *call; llist_for_each_entry(call, &g_call_list, entry) { /* only look at the initial=MNCC call */ if(call->initial->type == CALL_TYPE_MNCC) { struct mncc_call_leg *leg = (struct mncc_call_leg *) call->initial; /* table row */ char *called = talloc_strdup(tall_mncc_ctx, leg->called.number); char *calling = talloc_strdup(tall_mncc_ctx, leg->calling.number); char *state = talloc_strdup(tall_mncc_ctx, call_leg_state(call->initial)); vty_out(vty, "%5u %-32s %-32s %s%s", call->id, calling, called, state, VTY_NEWLINE); /* clean up */ talloc_free(called); talloc_free(calling); talloc_free(state); } } return CMD_SUCCESS; } DEFUN(show_mncc_conn, show_mncc_conn_cmd, "show mncc-connection", SHOW_STR "MNCC Connection state\n") { vty_out(vty, "MNCC connection to path '%s' is in state %s%s", g_app.mncc.path, get_value_string(mncc_conn_state_vals, g_app.mncc.conn.state), VTY_NEWLINE); return CMD_SUCCESS; } void mncc_sip_vty_init(void) { /* default values */ g_app.mncc.path = talloc_strdup(tall_mncc_ctx, "/tmp/msc_mncc"); g_app.sip.local_addr = talloc_strdup(tall_mncc_ctx, "127.0.0.1"); g_app.sip.local_port = 5060; g_app.sip.remote_addr = talloc_strdup(tall_mncc_ctx, "pbx"); g_app.sip.remote_port = 5060; vty_init(&vty_info); install_element(CONFIG_NODE, &cfg_sip_cmd); install_node(&sip_node, config_write_sip); install_element(SIP_NODE, &cfg_sip_local_addr_cmd); install_element(SIP_NODE, &cfg_sip_remote_addr_cmd); install_element(SIP_NODE, &cfg_sip_sofia_log_level_cmd); install_element(CONFIG_NODE, &cfg_mncc_cmd); install_node(&mncc_node, config_write_mncc); install_element(MNCC_NODE, &cfg_mncc_path_cmd); install_element(CONFIG_NODE, &cfg_app_cmd); install_node(&app_node, config_write_app); install_element(APP_NODE, &cfg_use_imsi_cmd); install_element(APP_NODE, &cfg_no_use_imsi_cmd); install_element_ve(&show_calls_cmd); install_element_ve(&show_calls_sum_cmd); install_element_ve(&show_mncc_conn_cmd); }