aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h1
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c39
-rw-r--r--openbsc/src/libmsc/gsm_subscriber.c110
3 files changed, 115 insertions, 35 deletions
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 0628d1f47..601aeb259 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -71,6 +71,7 @@ struct gsm_subscriber {
/* pending requests */
int is_paging;
+ struct osmo_timer_list paging_timeout;
struct llist_head requests;
/* GPRS/SGSN related fields */
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 8c9328703..5e86dcfa3 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1249,6 +1249,30 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m
return rc;
}
+static int handle_paging_resp(struct msgb *msg,
+ struct gsm_subscriber_connection *conn,
+ struct gsm_subscriber *subscr)
+{
+ if (!conn->subscr) {
+ conn->subscr = subscr;
+ } else if (conn->subscr != subscr) {
+ LOGP(DPAG, LOGL_ERROR,
+ "Connection already owned by another subscriber?\n");
+ subscr_put(subscr);
+ return -EINVAL;
+ } else {
+ DEBUGP(DPAG, "Connection already owned by the subscriber\n");
+ subscr_put(subscr);
+ subscr = conn->subscr;
+ }
+
+ /* TODO: count successful paging *in MSC*, similarly to BSC:
+ * rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED]); */
+#warning "missing rate counter for paging on MSC level"
+
+ return subscr_rx_paging_response(msg, conn);
+}
+
/* Receive a PAGING RESPONSE message from the MS */
static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
@@ -1292,14 +1316,7 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m
/* We received a paging */
conn->expire_timer_stopped = 1;
-#if 0
- TODO implement paging response in libmsc!
- Excluding this to be able to link without libbsc:
- rc = gsm48_handle_paging_resp(conn, msg, subscr);
- return rc;
-#else
- return -ENOTSUP;
-#endif
+ return handle_paging_resp(msg, conn, subscr);
}
static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct msgb *msg)
@@ -3581,12 +3598,12 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
trans_free(trans);
return 0;
}
- /* store setup informations until paging was successfull */
+ /* store setup information until paging succeeds */
memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
/* Request a channel */
- trans->paging_request = subscr_request_channel(subscr,
- RSL_CHANNEED_TCH_F, setup_trig_pag_evt,
+ trans->paging_request = subscr_request_conn(subscr,
+ setup_trig_pag_evt,
trans);
if (!trans->paging_request) {
LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index 41a8236e2..534b09353 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -59,23 +59,33 @@ static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
return subscr;
}
-/*
- * We got the channel assigned and can now hand this channel
- * over to one of our callbacks.
- */
+/* A connection is established and the paging callbacks may run now. */
static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *data, void *param)
+ struct msgb *msg, void *data, void *param)
{
struct subscr_request *request, *tmp;
struct gsm_subscriber_connection *conn = data;
struct gsm_subscriber *subscr = param;
struct paging_signal_data sig_data;
- OSMO_ASSERT(subscr->is_paging);
+ OSMO_ASSERT(hooknum == GSM_HOOK_RR_PAGING);
+ OSMO_ASSERT(subscr);
+ OSMO_ASSERT(!(conn && (conn->subscr != subscr)));
+ OSMO_ASSERT(!((event == GSM_PAGING_SUCCEEDED) && !conn));
+
+ LOGP(DPAG, LOGL_DEBUG, "Paging %s for %s (event=%d)\n",
+ event == GSM_PAGING_SUCCEEDED ? "success" : "failure",
+ subscr_name(subscr), event);
+
+ if (!subscr->is_paging) {
+ LOGP(DPAG, LOGL_ERROR,
+ "Paging Response received for subscriber"
+ " that is not paging.\n");
+ return -EINVAL;
+ }
/* Inform parts of the system we don't know */
sig_data.subscr = subscr;
- sig_data.bts = conn ? conn->bts : NULL;
sig_data.conn = conn;
sig_data.paging_result = event;
osmo_signal_dispatch(
@@ -87,38 +97,75 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
llist_del(&request->entry);
- request->cbfn(hooknum, event, msg, data, request->param);
+ if (request->cbfn) {
+ LOGP(DPAG, LOGL_DEBUG, "Calling paging cbfn.\n");
+ request->cbfn(hooknum, event, msg, data, request->param);
+ } else
+ LOGP(DPAG, LOGL_DEBUG, "Paging without action.\n");
talloc_free(request);
}
/* balanced with the moment we start paging */
subscr->is_paging = 0;
+
+ /* balanced with the moment we receive a paging response */
subscr_put(subscr);
return 0;
}
+static void paging_timeout_release(struct gsm_subscriber *subscr)
+{
+ DEBUGP(DPAG, "Paging timeout released for %s\n", subscr_name(subscr));
+ osmo_timer_del(&subscr->paging_timeout);
+}
+
+static void paging_timeout(void *data)
+{
+ struct gsm_subscriber *subscr = data;
+ DEBUGP(DPAG, "Paging timeout reached for %s\n", subscr_name(subscr));
+ paging_timeout_release(subscr);
+ subscr_paging_dispatch(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
+ NULL, NULL, subscr);
+}
+
+static void paging_timeout_start(struct gsm_subscriber *subscr)
+{
+ DEBUGP(DPAG, "Starting paging timeout for %s\n", subscr_name(subscr));
+ subscr->paging_timeout.data = subscr;
+ subscr->paging_timeout.cb = paging_timeout;
+ osmo_timer_schedule(&subscr->paging_timeout, 10, 0);
+ /* TODO: configurable timeout duration? */
+}
+
+
static int subscr_paging_sec_cb(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param)
{
int rc;
+ struct gsm_subscriber_connection *conn = data;
+ OSMO_ASSERT(conn);
switch (event) {
case GSM_SECURITY_AUTH_FAILED:
- /* Dispatch as paging failure */
+ LOGP(DPAG, LOGL_ERROR,
+ "Dropping Paging Response:"
+ " authorization failed for subscriber %s\n",
+ subscr_name(conn->subscr));
rc = subscr_paging_dispatch(
GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
- msg, data, param);
+ msg, conn, conn->subscr);
break;
case GSM_SECURITY_NOAVAIL:
case GSM_SECURITY_SUCCEEDED:
- /* Dispatch as paging failure */
rc = subscr_paging_dispatch(
GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
- msg, data, param);
+ msg, conn, conn->subscr);
break;
default:
+ LOGP(DPAG, LOGL_FATAL,
+ "Invalid authorization event: %d\n", event);
rc = -EINVAL;
}
@@ -135,6 +182,8 @@ int subscr_rx_paging_response(struct msgb *msg,
gh = msgb_l3(msg);
pr = (struct gsm48_pag_resp *)gh->data;
+ paging_timeout_release(conn->subscr);
+
/* Secure the connection */
if (subscr_authorized(conn->subscr))
return gsm48_secure_channel(conn, pr->key_seq,
@@ -146,32 +195,45 @@ int subscr_rx_paging_response(struct msgb *msg,
return -1;
}
-struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
- int channel_type, gsm_cbfn *cbfn, void *param)
+static int msc_paging_request(struct gsm_subscriber *subscr)
+{
+ /* The subscriber was last seen in subscr->lac. Find out which
+ * BSCs/RNCs are responsible and send them a paging request via open
+ * SCCP connections (if any). */
+ /* TODO Implementing only RNC paging, since this is code on the iu branch.
+ * Need to add BSC paging at some point. */
+ return iu_page_cs(subscr->imsi,
+ subscr->tmsi == GSM_RESERVED_TMSI?
+ NULL : &subscr->tmsi,
+ subscr->lac);
+}
+
+struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr,
+ gsm_cbfn *cbfn, void *param)
{
int rc;
struct subscr_request *request;
/* Start paging.. we know it is async so we can do it before */
if (!subscr->is_paging) {
- LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
+ LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet, start paging.\n",
subscr_name(subscr));
-#if 0
- TODO implement paging response in libmsc!
- Excluding this to be able to link without libbsc:
- rc = paging_request(subscr->group->net, subscr, channel_type,
- subscr_paging_cb, subscr);
-#else
- rc = -ENOTSUP;
-#endif
+ rc = msc_paging_request(subscr);
if (rc <= 0) {
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
subscr_name(subscr), rc);
return NULL;
}
- /* reduced on the first paging callback */
+ /* reduced in subscr_rx_paging_response() */
subscr_get(subscr);
subscr->is_paging = 1;
+ LOGP(DMM, LOGL_DEBUG, "Paged subscriber %s.\n",
+ subscr_name(subscr));
+ paging_timeout_start(subscr);
+ }
+ else {
+ LOGP(DMM, LOGL_DEBUG, "Subscriber %s already paged.\n",
+ subscr_name(subscr));
}
/* TODO: Stop paging in case of memory allocation failure */