aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2009-11-14 10:08:40 +0100
committerHarald Welte <laforge@netfilter.org>2009-11-14 10:08:40 +0100
commita148233b5e03935584b842250b2b511eee782839 (patch)
tree207e093f409c9d8b5951c265ecfaf2180932243f
parent98f9c75094fcb54f7e7318a4cbfca04a8db8112f (diff)
Add "silent call" feature to OpenBSC
This allows the administrator to use the vty interface to issue a silent call to a given subscriber by using "subscriber extension XXXX silent call start" and stopping that silent call with "subscriber extension XXXX silent call stop"
-rw-r--r--openbsc/include/openbsc/signal.h14
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/silent_call.c92
-rw-r--r--openbsc/src/vty_interface_layer3.c56
4 files changed, 162 insertions, 2 deletions
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 <laforge@gnumonks.org>
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <openbsc/msgb.h>
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <openbsc/paging.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/abis_rsl.h>
+
+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 <openbsc/gsm_utils.h>
#include <openbsc/db.h>
#include <openbsc/talloc.h>
+#include <openbsc/signal.h>
/* 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);