forked from sailfishos/ofono
		
	[ril] Workaround for data call status 55. JB#40162
With some networks we sometimes start getting error 55 (Multiple PDN connections for a given APN not allowed) when trying to setup an LTE data call and this error doesn't go away until we successfully establish a data call over 3G. Then we can switch back to LTE.
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Copyright (C) 2013 Canonical Ltd.
 | 
			
		||||
 *  Copyright (C) 2013-2019 Jolla Ltd.
 | 
			
		||||
 *  Copyright (C) 2013-2020 Jolla Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
@@ -205,10 +205,44 @@ enum ril_data_call_fail_cause {
 | 
			
		||||
	PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
 | 
			
		||||
	PDP_FAIL_NSAPI_IN_USE = 0x23,
 | 
			
		||||
	PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
 | 
			
		||||
	PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
 | 
			
		||||
	PDP_FAIL_NETWORK_FAILURE = 0x26,
 | 
			
		||||
	PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
 | 
			
		||||
	PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
 | 
			
		||||
	PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
 | 
			
		||||
	PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
 | 
			
		||||
	PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
 | 
			
		||||
	PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
 | 
			
		||||
	PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
 | 
			
		||||
	PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
 | 
			
		||||
	PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
 | 
			
		||||
	PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
 | 
			
		||||
	PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
 | 
			
		||||
	PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
 | 
			
		||||
	PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
 | 
			
		||||
	PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
 | 
			
		||||
	PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
 | 
			
		||||
	PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
 | 
			
		||||
	PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
 | 
			
		||||
	PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
 | 
			
		||||
	PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
 | 
			
		||||
	PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
 | 
			
		||||
	PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
 | 
			
		||||
	PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
 | 
			
		||||
	PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
 | 
			
		||||
	PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
 | 
			
		||||
	PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
 | 
			
		||||
	PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
 | 
			
		||||
	PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
 | 
			
		||||
	PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
 | 
			
		||||
	PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
 | 
			
		||||
	PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
 | 
			
		||||
	PDP_FAIL_IFACE_MISMATCH = 0x75,
 | 
			
		||||
	PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
 | 
			
		||||
	PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
 | 
			
		||||
	PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
 | 
			
		||||
	PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
 | 
			
		||||
	PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
 | 
			
		||||
	PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
 | 
			
		||||
	PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
 | 
			
		||||
	PDP_FAIL_SIGNAL_LOST = -3,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  oFono - Open Source Telephony - RIL-based devices
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2016-2019 Jolla Ltd.
 | 
			
		||||
 *  Copyright (C) 2016-2020 Jolla Ltd.
 | 
			
		||||
 *  Copyright (C) 2019 Open Mobile Platform LLC.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -29,6 +29,8 @@
 | 
			
		||||
#include <grilio_parser.h>
 | 
			
		||||
#include <grilio_request.h>
 | 
			
		||||
 | 
			
		||||
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
 | 
			
		||||
 | 
			
		||||
/* Yes, it does sometimes take minutes in roaming */
 | 
			
		||||
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
 | 
			
		||||
 | 
			
		||||
@@ -115,6 +117,7 @@ struct ril_data_priv {
 | 
			
		||||
	gulong io_event_id[IO_EVENT_COUNT];
 | 
			
		||||
	gulong settings_event_id[SETTINGS_EVENT_COUNT];
 | 
			
		||||
	GHashTable* grab;
 | 
			
		||||
	gboolean downgraded_tech; /* Status 55 workaround */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ril_data_signal {
 | 
			
		||||
@@ -815,6 +818,31 @@ static gboolean ril_data_call_setup_retry(void *user_data)
 | 
			
		||||
	return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean ril_data_call_retry(struct ril_data_request_setup *setup)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_data_request *req = &setup->req;
 | 
			
		||||
	const struct ril_data_options *options = &req->data->priv->options;
 | 
			
		||||
 | 
			
		||||
	if (setup->retry_count < options->data_call_retry_limit) {
 | 
			
		||||
		req->pending_id = 0;
 | 
			
		||||
		GASSERT(!setup->retry_delay_id);
 | 
			
		||||
		if (!setup->retry_count) {
 | 
			
		||||
			/* No delay first time */
 | 
			
		||||
			setup->retry_count++;
 | 
			
		||||
			DBG("silent retry %u out of %u", setup->retry_count,
 | 
			
		||||
					options->data_call_retry_limit);
 | 
			
		||||
			req->submit(req);
 | 
			
		||||
		} else {
 | 
			
		||||
			const guint ms = options->data_call_retry_delay_ms;
 | 
			
		||||
			DBG("silent retry scheduled in %u ms", ms);
 | 
			
		||||
			setup->retry_delay_id = g_timeout_add(ms,
 | 
			
		||||
					ril_data_call_setup_retry, setup);
 | 
			
		||||
		}
 | 
			
		||||
		return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
 | 
			
		||||
				const void *data, guint len, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
@@ -839,33 +867,49 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
 | 
			
		||||
		setup->retry_count < priv->options.data_call_retry_limit) {
 | 
			
		||||
	if (call) {
 | 
			
		||||
		switch (call->status) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * According to the comment from ril.h we should silently
 | 
			
		||||
		 * retry. First time we retry immediately and if that doedsn't
 | 
			
		||||
		 * retry. First time we retry immediately and if that doesn't
 | 
			
		||||
		 * work, then after certain delay.
 | 
			
		||||
		 */
 | 
			
		||||
		req->pending_id = 0;
 | 
			
		||||
		GASSERT(!setup->retry_delay_id);
 | 
			
		||||
		if (!setup->retry_count) {
 | 
			
		||||
			setup->retry_count++;
 | 
			
		||||
			DBG("silent retry %u out of %u", setup->retry_count,
 | 
			
		||||
					priv->options.data_call_retry_limit);
 | 
			
		||||
			req->submit(req);
 | 
			
		||||
		} else {
 | 
			
		||||
			guint ms = priv->options.data_call_retry_delay_ms;
 | 
			
		||||
			DBG("silent retry scheduled in %u ms", ms);
 | 
			
		||||
			setup->retry_delay_id = g_timeout_add(ms,
 | 
			
		||||
					ril_data_call_setup_retry, setup);
 | 
			
		||||
		case PDP_FAIL_ERROR_UNSPECIFIED:
 | 
			
		||||
			if (ril_data_call_retry(setup)) {
 | 
			
		||||
				ril_data_call_list_free(list);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		/*
 | 
			
		||||
		 * With some networks we sometimes start getting error 55
 | 
			
		||||
		 * (Multiple PDN connections for a given APN not allowed)
 | 
			
		||||
		 * when trying to setup an LTE data call and this error
 | 
			
		||||
		 * doesn't go away until we successfully establish a data
 | 
			
		||||
		 * call over 3G. Then we can switch back to LTE.
 | 
			
		||||
		 */
 | 
			
		||||
		case PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED:
 | 
			
		||||
			if (priv->network->data.access_tech ==
 | 
			
		||||
					ACCESS_TECHNOLOGY_EUTRAN &&
 | 
			
		||||
						!priv->downgraded_tech) {
 | 
			
		||||
				DBG("downgrading preferred technology");
 | 
			
		||||
				priv->downgraded_tech = TRUE;
 | 
			
		||||
				ril_data_manager_check_network_mode(priv->dm);
 | 
			
		||||
				/* And let this call fail */
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		ril_data_call_list_free(list);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ril_data_request_completed(req);
 | 
			
		||||
 | 
			
		||||
	if (call && call->status == PDP_FAIL_NONE) {
 | 
			
		||||
		if (priv->downgraded_tech) {
 | 
			
		||||
			DBG("done with status 55 workaround");
 | 
			
		||||
			priv->downgraded_tech = FALSE;
 | 
			
		||||
			ril_data_manager_check_network_mode(priv->dm);
 | 
			
		||||
		}
 | 
			
		||||
		if (ril_data_call_list_move_calls(self->data_calls, list) > 0) {
 | 
			
		||||
			DBG("data call(s) added");
 | 
			
		||||
			ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED);
 | 
			
		||||
@@ -1151,6 +1195,11 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * ril_data
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
 | 
			
		||||
{
 | 
			
		||||
	return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
 | 
			
		||||
						OFONO_RADIO_ACCESS_MODE_ANY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
 | 
			
		||||
						ril_data_cb_t cb, void *arg)
 | 
			
		||||
@@ -1684,7 +1733,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
 | 
			
		||||
 | 
			
		||||
			ril_network_set_max_pref_mode(network,
 | 
			
		||||
					(network == lte_network) ?
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_ANY :
 | 
			
		||||
					ril_data_max_mode(data) :
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_GSM,
 | 
			
		||||
					FALSE);
 | 
			
		||||
		}
 | 
			
		||||
@@ -1694,7 +1743,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
 | 
			
		||||
		for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
			struct ril_data *data = l->data;
 | 
			
		||||
			ril_network_set_max_pref_mode(data->priv->network,
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
 | 
			
		||||
					ril_data_max_mode(data), FALSE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1723,7 +1772,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
 | 
			
		||||
 | 
			
		||||
	if (ril_data_manager_handover(self)) {
 | 
			
		||||
		ril_network_set_max_pref_mode(priv->network,
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
 | 
			
		||||
					ril_data_max_mode(data), TRUE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user