From 03fd8d014f9871896a86534432c8757d65a576fe Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 25 May 2011 13:54:02 -0400 Subject: Import upstream version 0.9.13 --- src/libmsc/silent_call.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/libmsc/silent_call.c (limited to 'src/libmsc/silent_call.c') diff --git a/src/libmsc/silent_call.c b/src/libmsc/silent_call.c new file mode 100644 index 000000000..64ebdfdb9 --- /dev/null +++ b/src/libmsc/silent_call.c @@ -0,0 +1,143 @@ +/* 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 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 Affero 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* paging of the requested subscriber has completed */ +static int paging_cb_silent(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *_conn, void *_data) +{ + struct gsm_subscriber_connection *conn = _conn; + struct scall_signal_data sigdata; + int rc = 0; + + if (hooknum != GSM_HOOK_RR_PAGING) + return -EINVAL; + + DEBUGP(DSMS, "paging_cb_silent: "); + + sigdata.conn = conn; + sigdata.data = _data; + + switch (event) { + case GSM_PAGING_SUCCEEDED: + DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n", + conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn); + conn->silent_call = 1; + /* increment lchan reference count */ + dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata); + break; + case GSM_PAGING_EXPIRED: + case GSM_PAGING_BUSY: + case GSM_PAGING_OOM: + DEBUGP(DSMS, "expired\n"); + dispatch_signal(SS_SCALL, S_SCALL_EXPIRED, &sigdata); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +/* receive a layer 3 message from a silent call */ +int silent_call_rx(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + /* FIXME: do something like sending it through a UDP port */ + return 0; +} + +struct msg_match { + u_int8_t pdisc; + u_int8_t msg_type; +}; + +/* list of messages that are handled inside OpenBSC, even in a silent call */ +static const struct msg_match silent_call_accept[] = { + { GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST }, + { GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_REQ }, +}; + +/* decide if we need to reroute a message as part of a silent call */ +int silent_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + u_int8_t pdisc = gh->proto_discr & 0x0f; + int i; + + /* if we're not part of a silent call, never reroute */ + if (!conn->silent_call) + return 0; + + /* check if we are a special message that is handled in openbsc */ + for (i = 0; i < ARRAY_SIZE(silent_call_accept); i++) { + if (silent_call_accept[i].pdisc == pdisc && + silent_call_accept[i].msg_type == gh->msg_type) + return 0; + } + + /* otherwise, reroute */ + return 1; +} + + +/* initiate a silent call with a given subscriber */ +int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type) +{ + int rc; + + rc = paging_request(subscr->net, subscr, type, + paging_cb_silent, data); + return rc; +} + +/* end a silent call with a given subscriber */ +int gsm_silent_call_stop(struct gsm_subscriber *subscr) +{ + struct gsm_subscriber_connection *conn; + + conn = connection_for_subscr(subscr); + if (!conn) + return -EINVAL; + + /* did we actually establish a silent call for this guy? */ + if (!conn->silent_call) + return -EINVAL; + + conn->silent_call = 0; + msc_release_connection(conn); + + return 0; +} -- cgit v1.2.3