aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_subscriber.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/gprs_subscriber.c')
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 9d79f0006..58203bab8 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -104,10 +104,27 @@ static void sgsn_subscriber_timeout_cb(void *subscr_)
LOGGSUBSCRP(LOGL_INFO, subscr,
"Expired, deleting subscriber entry\n");
+ subscr_get(subscr);
+
+ /* Check, whether to cleanup immediately */
+ if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE))
+ goto force_cleanup;
+
+ /* Send a 'purge MS' message to the HLR */
+ if (gprs_subscr_purge(subscr) < 0)
+ goto force_cleanup;
+
+ /* Purge request has been sent */
+
+ subscr_put(subscr);
+ return;
+
+force_cleanup:
/* Make sure, the timer is cleaned up */
subscr->keep_in_ram = 0;
gprs_subscr_stop_timer(subscr);
/* The subscr is freed now, if the timer was the last user */
+ subscr_put(subscr);
}
static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
@@ -169,6 +186,7 @@ void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
{
subscr->authorized = 0;
subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
+ subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
gprs_subscr_update(subscr);
@@ -258,6 +276,8 @@ static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
subscr->authorized = 1;
subscr->sgsn_data->error_cause = 0;
+ subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
+
gprs_subscr_update(subscr);
return 0;
}
@@ -377,6 +397,51 @@ static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
return -gsup_msg->cause;
}
+static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
+ struct gprs_gsup_message *gsup_msg)
+{
+ LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
+
+ /* Force silent cancellation */
+ subscr->sgsn_data->error_cause = 0;
+ gprs_subscr_put_and_cancel(subscr_get(subscr));
+
+ return 0;
+}
+
+static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
+ struct gprs_gsup_message *gsup_msg)
+{
+ LOGGSUBSCRP(LOGL_NOTICE, subscr,
+ "Purge MS has failed with cause '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+
+ /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
+ * the subscriber data is not removed if the request has failed. On the
+ * other hand, keeping the subscriber data in either error case
+ * (subscriber unknown, syntactical message error, connection error)
+ * doesn't seem to give any advantage, since the data will be restored
+ * on the next Attach Request anyway.
+ * This approach ensures, that the subscriber record will not stick if
+ * an error happens.
+ */
+
+ /* TODO: Check whether this behaviour is acceptable and either just
+ * remove this TODO-notice or change the implementation to not delete
+ * the subscriber data (eventually resetting the ENABLE_PURGE flag and
+ * restarting the expiry timer based on the cause).
+ *
+ * Subscriber Unknown: cancel subscr
+ * Temporary network problems: do nothing (handled by timer based retry)
+ * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
+ */
+
+ gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
+
+ return -gsup_msg->cause;
+}
+
int gprs_subscr_rx_gsup_message(struct msgb *msg)
{
uint8_t *data = msgb_l2(msg);
@@ -435,7 +500,13 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
break;
case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
+ rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
+ break;
+
case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
+ rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
+ break;
+
case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
LOGGSUBSCRP(LOGL_ERROR, subscr,
@@ -458,6 +529,16 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
return rc;
}
+int gprs_subscr_purge(struct gsm_subscriber *subscr)
+{
+ struct gprs_gsup_message gsup_msg = {0};
+
+ LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
+
+ gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
+ return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
+}
+
int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
@@ -514,6 +595,7 @@ struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mm
if (!subscr) {
subscr = gprs_subscr_get_or_create(mmctx->imsi);
subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
+ subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
}
if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {