diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 1af849684..9e5511f6f 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -39,6 +39,7 @@ enum signal_subsystems { SS_NM, SS_LCHAN, SS_SUBSCR, + SS_SCALL, }; /* SS_PAGING signals */ @@ -85,6 +86,13 @@ enum signal_subscr { S_SUBSCR_DETACHED, }; +/* SS_SCALL signals */ +enum signal_scall { + S_SCALL_SUCCESS, + S_SCALL_EXPIRED, + S_SCALL_DETACHED, +}; + typedef int signal_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data); @@ -96,6 +104,12 @@ struct paging_signal_data { struct gsm_lchan *lchan; }; +struct scall_signal_data { + struct gsm_subscriber *subscr; + struct gsm_lchan *lchan; + void *data; +}; + /* Management */ int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 2f715bbaf..891a112aa 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -14,7 +14,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ - token_auth.c rrlp.c gsm_04_80.c ussd.c + token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c new file mode 100644 index 000000000..3161834c2 --- /dev/null +++ b/openbsc/src/silent_call.c @@ -0,0 +1,92 @@ +/* GSM silent call feature */ + +/* + * (C) 2009 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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int paging_cb_silent(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *_lchan, void *_data) +{ + struct gsm_lchan *lchan = _lchan; + struct scall_signal_data sigdata; + int rc; + + if (hooknum != GSM_HOOK_RR_PAGING) + return -EINVAL; + + DEBUGP(DSMS, "paging_cb_silent: "); + + sigdata.lchan = lchan; + sigdata.data = _data; + + switch (event) { + case GSM_PAGING_SUCCEEDED: + DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n", + lchan->ts->nr, lchan->ts->trx->arfcn); + /* increment lchan reference count */ + dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata); + use_lchan(lchan); + break; + case GSM_PAGING_EXPIRED: + DEBUGP(DSMS, "expired\n"); + dispatch_signal(SS_SCALL, S_SCALL_EXPIRED, &sigdata); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data) +{ + int rc; + + rc = paging_request(subscr->net, subscr, RSL_CHANNEED_TCH_F, + paging_cb_silent, data); + return rc; +} + +int gsm_silent_call_stop(struct gsm_subscriber *subscr) +{ + struct gsm_lchan *lchan; + + lchan = lchan_for_subscr(subscr); + if (!lchan) + return -EINVAL; + + /* FIXME: did we actually establish a silent call for this guy? */ + put_lchan(lchan); + + return 0; +} diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 53b596098..124a368f4 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -38,6 +38,7 @@ #include #include #include +#include /* forward declarations */ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr); @@ -55,7 +56,6 @@ static int dummy_config_write(struct vty *v) return CMD_SUCCESS; } - static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) { struct buffer *b = buffer_new(1024); @@ -259,6 +259,38 @@ DEFUN(subscriber_silent_sms, return rc; } +DEFUN(subscriber_silent_call, + subscriber_silent_call_cmd, + "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)", + "Send a silent call to a subscriber") +{ + struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); + int rc; + + if (!subscr) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1]); + return CMD_WARNING; + } + + if (!strcmp(argv[2], "start")) { + rc = gsm_silent_call_start(subscr, vty); + if (rc <= 0) { + vty_out(vty, "%% Subscriber not attached%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } else { + rc = gsm_silent_call_stop(subscr); + if (rc < 0) + return CMD_WARNING; + } + + subscr_put(subscr); + + return CMD_SUCCESS; +} + DEFUN(cfg_subscr_name, cfg_subscr_name_cmd, "name NAME", @@ -307,10 +339,31 @@ DEFUN(cfg_subscr_authorized, return CMD_SUCCESS; } +static int scall_cbfn(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct scall_signal_data *sigdata = signal_data; + struct vty *vty = sigdata->data; + + switch (signal) { + case S_SCALL_SUCCESS: + vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s", + sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr, + VTY_NEWLINE); + break; + case S_SCALL_EXPIRED: + vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE); + break; + } + return 0; +} + int bsc_vty_init_extra(struct gsm_network *net) { gsmnet = net; + register_signal_handler(SS_SCALL, scall_cbfn, NULL); + install_element(VIEW_NODE, &show_subscr_cmd); install_element(VIEW_NODE, &show_subscr_cache_cmd); @@ -318,6 +371,7 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &subscriber_send_sms_cmd); install_element(VIEW_NODE, &subscriber_silent_sms_cmd); + install_element(VIEW_NODE, &subscriber_silent_call_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write);