aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-05 18:38:41 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-01-18 18:20:41 +0100
commit9aa9991efe207f5c12bbcf655b0660e3466c02e0 (patch)
treebfcede6b6f4f7f0914a3b914f0368964e6537766
parentaf3d5c508c9ca3ebae9388d3e09c5d7726db4f5c (diff)
gprs: Use the cause value in GSUP error messages
Currently always a cause with the meaning of 'access denied' is assumed. gprs_subscr_handle_gsup_auth_err just clears the auth triplets and the authorized flag before calling the update function. gprs_subscr_handle_gsup_upd_loc_err only clears the authorized flag and calls the update function. This means, that an MS will not retry to attach even on temporary network errors. This patch changes these functions to use the GSUP error cause value to decide, whether to clear the corresponding subscriber fields, to just continue with the corresponding update function, or to log, ignore and not pass the cause to the MS in case the error is directly related to the GSUP protocol. The subscriber's error_cause field is updated, if the update function is going to be called. The error_cause fielt is reset on non-error GSUP messages. Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c110
1 files changed, 94 insertions, 16 deletions
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 2f3ae96de..fd16fa3ef 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -182,6 +182,7 @@ static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
}
sdata->auth_triplets_updated = 1;
+ sdata->error_cause = 0;
gprs_subscr_update_auth_info(subscr);
@@ -211,43 +212,119 @@ static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
}
subscr->authorized = 1;
+ subscr->sgsn_data->error_cause = 0;
gprs_subscr_update(subscr);
return 0;
}
+static int check_cause(int cause)
+{
+ switch (cause) {
+ case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
+ case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
+ return EACCES;
+
+ case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
+ return EAGAIN;
+
+ case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
+ default:
+ return EINVAL;
+ }
+}
+
static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
unsigned idx;
struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
+ int cause_err;
- LOGP(DGPRS, LOGL_INFO,
- "Send authentication info has failed for IMSI %s with cause %d\n",
- gsup_msg->imsi, gsup_msg->cause);
+ cause_err = check_cause(gsup_msg->cause);
- /* Clear auth tuples */
- memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
- for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
- sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
+ LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm,
+ "Send authentication info has failed with cause %d, "
+ "handled as: %s\n",
+ gsup_msg->cause, strerror(cause_err));
+
+ switch (cause_err) {
+ case EACCES:
+ LOGMMCTXP(LOGL_NOTICE, subscr->sgsn_data->mm,
+ "GPRS send auth info req failed, access denied, "
+ "GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ /* Clear auth tuples */
+ memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
+ for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
+ sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
- subscr->authorized = 0;
+ subscr->authorized = 0;
+ sdata->error_cause = gsup_msg->cause;
+ gprs_subscr_update_auth_info(subscr);
+ break;
- gprs_subscr_update_auth_info(subscr);
- return 0;
+ case EAGAIN:
+ LOGMMCTXP(LOGL_NOTICE, subscr->sgsn_data->mm,
+ "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ break;
+
+ default:
+ case EINVAL:
+ LOGMMCTXP(LOGL_ERROR, subscr->sgsn_data->mm,
+ "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ break;
+ }
+
+ return -gsup_msg->cause;
}
static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
- LOGP(DGPRS, LOGL_INFO,
- "Update location has failed for IMSI %s with cause %d\n",
- gsup_msg->imsi, gsup_msg->cause);
+ int cause_err;
- subscr->authorized = 0;
+ cause_err = check_cause(gsup_msg->cause);
- gprs_subscr_update(subscr);
- return 0;
+ LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm,
+ "Update location has failed with cause %d, handled as: %s\n",
+ gsup_msg->cause, strerror(cause_err));
+
+ switch (cause_err) {
+ case EACCES:
+ LOGMMCTXP(LOGL_NOTICE, subscr->sgsn_data->mm,
+ "GPRS update location failed, access denied, "
+ "GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+
+ subscr->authorized = 0;
+ subscr->sgsn_data->error_cause = gsup_msg->cause;
+ gprs_subscr_update_auth_info(subscr);
+ break;
+
+ case EAGAIN:
+ LOGMMCTXP(LOGL_NOTICE, subscr->sgsn_data->mm,
+ "GPRS update location failed, GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ break;
+
+ default:
+ case EINVAL:
+ LOGMMCTXP(LOGL_ERROR, subscr->sgsn_data->mm,
+ "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ break;
+ }
+
+ return -gsup_msg->cause;
}
int gprs_subscr_rx_gsup_message(struct msgb *msg)
@@ -286,6 +363,7 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
switch (gsup_msg.message_type) {
case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
+ subscr->sgsn_data->error_cause = 0;
gprs_subscr_put_and_cancel(subscr);
subscr = NULL;
break;