diff options
-rw-r--r-- | openbsc/include/openbsc/gsm_subscriber.h | 1 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 39 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_subscriber.c | 110 |
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 */ |