Compare commits

...

14 Commits

Author SHA1 Message Date
Slava Monich
2520664c63 Merge branch 'gprs-picks' into 'master'
Couple of upstream picks

One of those eliminates a possible root cause of mobile data
becoming disabled under certain (fairly rare) circumstances.

See merge request !95
2016-11-07 09:43:04 +00:00
Slava Monich
445bbbd66f gprs: Check GPRS_FLAG_ATTACHED_UPDATE
... in pri_deactivate_callback

This prevents attached state from getting stuck at 0 like this:

1. Context deactivation is initiated over D-Bus, ctx->pending is set
2. Attached becomes FALSE, context is still marked as active
3. Attached becomes TRUE, gprs_attached_update sets GPRS_FLAG_ATTACHED_UPDATE
4. Deactivation completes, attached is 0, driver_attached is 1

Futher network status updates don't call gprs_attached_update because
driver_attached is still 1, so attached is staying 0 until we lose the
data registration again which may not happen for quite a long time.
2016-11-04 12:14:48 +03:00
Caiwen Zhang
08fc4b0d03 gprs: fix crash removing a context being activated
If remove the context before context activation is completed, it may
cause a crash.
2016-11-04 12:14:18 +03:00
Slava Monich
c82e94ffb4 Merge branch 'cancel' into 'master'
Make sure that data request completion callback is always called on cancel

See merge request !94
2016-10-31 16:12:52 +00:00
Slava Monich
fd3712940b [ril] Make sure data request completion callback is called on cancel. Contributes to JB#33640
Completion callback wasn't invoked if the data request was cancelled
before it was actually submitted to RIL.
2016-10-28 15:46:06 +03:00
Slava Monich
8410c985c9 Merge branch 'nitz' into 'master'
Handle NITZ information coming before MCC/MNC

See merge request !93
2016-10-27 09:26:05 +00:00
Slava Monich
0878decdc0 Merge branch 'prefmode' into 'master'
Preferred network mode, corner cases

See merge request !92
2016-10-27 09:25:18 +00:00
Slava Monich
cb69984722 [ril] Preferred network mode, corner cases. Fixes JB#36683
Really make sure that we don't try to set preferred network mode to LTE
for more than one slot at a time.
2016-10-26 17:30:01 +03:00
Slava Monich
1fe8701f1a [nettime] Handle NITZ information coming before MCC/MNC. Fixes MER#1680
Due to the order in which events are delivered and network registration
information requiring one extra query, NITZ information may be delivered
to ofono before MCC/MNC are known.
2016-10-26 16:56:30 +03:00
Slava Monich
c5286fee70 Merge branch 'rat' into 'master'
Check network mode after ril_data is created

Not sure if it completely fixes the issue but it could cause
repeating SET_PREFERRED_NETWORK_TYPE failures.

See merge request !91
2016-10-23 21:04:29 +00:00
Slava Monich
3c5f6f84e1 Merge branch 'data_calls' into 'master'
Make data call format configurable

Different RILs use different data call structures which don't
necessarily match the format specified in the data list header.
The header may have version 9 but the list may contain 
RIL_Data_Call_Response_v6` structures, list version 10 may
contain RIL_Data_Call_Response_v11 and so on. By default ofono
assumes that the version from the list header matches the contents
but sometimes you have to explicitly tell ofono which one to use.

Possible values are 6, 9, 11 and auto.

See merge request !90
2016-10-23 21:03:52 +00:00
Slava Monich
8b87b55e8d [ril] Check network mode after ril_data is created. Contributes to JB#36683 2016-10-20 14:41:29 +03:00
Slava Monich
bce34cbff3 [ril] Housekeeping
Removed unnecessary forward declaration
2016-10-20 14:38:04 +03:00
Slava Monich
f8351cacf1 [ril] Made data call format configurable. Contributes to MER#1679
This commit adds dataCallFormat configuration option to
ril_subscriptuion.conf which allows to select which data
call format to use. There are quite a few rils where version
provided in the data call list header doesn't match the contents.
2016-10-19 12:30:13 +03:00
7 changed files with 400 additions and 156 deletions

View File

@@ -100,6 +100,7 @@ struct ril_data_priv {
struct ril_data_request *pending_req;
enum ril_data_allow_data_opt allow_data;
enum ril_data_call_format data_call_format;
char *log_prefix;
guint query_id;
gulong io_event_id;
@@ -172,7 +173,6 @@ struct ril_data_request_2g {
gulong handler_id;
};
static gboolean ril_data_manager_handover(struct ril_data_manager *dm);
static void ril_data_manager_check_data(struct ril_data_manager *dm);
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
@@ -272,7 +272,8 @@ static int ril_data_protocol_to_ofono(gchar *str)
return -1;
}
static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp)
static struct ril_data_call *ril_data_call_parse(int version,
GRilIoParser *rilp)
{
int prot;
char *prot_str;
@@ -280,6 +281,7 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
guint32 active = RIL_DATA_CALL_INACTIVE;
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
/* RIL_Data_Call_Response_v6 (see ril.h) */
grilio_parser_get_uint32(rilp, &status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
@@ -299,15 +301,13 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
call->status = status;
call->active = active;
/* RIL_Data_Call_Response_v9 */
if (version >= 9) {
/* PCSCF */
grilio_parser_skip_string(rilp);
/*
* All known rils that report version 10 are using
* RIL_Data_Call_Response_v11 (FairPhone 2, Nexus 4)
*/
if (version >= 10) {
/* RIL_Data_Call_Response_v11 */
if (version >= 11) {
/* MTU */
grilio_parser_get_int32(rilp, &call->mtu);
}
@@ -317,7 +317,8 @@ static struct ril_data_call *ril_data_call_parse(int version, GRilIoParser *rilp
return call;
}
struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, enum ril_data_call_format format)
{
unsigned int version, n, i;
GRilIoParser rilp;
@@ -328,8 +329,13 @@ struct ril_data_call_list *ril_data_call_list_parse(const void *data, guint len)
struct ril_data_call_list *list =
g_new0(struct ril_data_call_list, 1);
DBG("version=%u,num=%u", version, n);
list->version = version;
if (format == RIL_DATA_CALL_FORMAT_AUTO || format == version) {
DBG("version=%u,num=%u", version, n);
list->version = version;
} else {
DBG("version=%u(%d),num=%u", version, format, n);
list->version = format;
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call =
@@ -499,7 +505,8 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
priv->query_id = 0;
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -511,7 +518,8 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
GASSERT(priv->query_id);
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len));
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->data_call_format));
}
}
@@ -586,11 +594,11 @@ static gboolean ril_data_request_do_cancel(struct ril_data_request *req)
struct ril_data_priv *priv = req->data->priv;
DBG_(req->data, "canceling %s request %p", req->name, req);
if (req->cancel) {
req->cancel(req);
}
if (priv->pending_req == req) {
/* Request has been submitted already */
if (req->cancel) {
req->cancel(req);
}
priv->pending_req = NULL;
} else if (priv->req_queue == req) {
/* It's the first one in the queue */
@@ -673,14 +681,11 @@ static void ril_data_request_queue(struct ril_data_request *req)
static void ril_data_call_setup_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.setup(req->data, GRILIO_STATUS_CANCELLED,
NULL, req->arg);
}
ril_data_request_cancel_io(req);
if (req->cb.setup) {
ril_data_call_setup_cb_t cb = req->cb.setup;
req->cb.setup = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, NULL, req->arg);
}
}
@@ -690,11 +695,13 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
struct ril_data_request_setup *setup = user_data;
struct ril_data_request *req = &setup->req;
struct ril_data *self = req->data;
struct ril_data_priv *priv = self->priv;
struct ril_data_call_list *list = NULL;
struct ril_data_call *call = NULL;
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len);
list = ril_data_call_list_parse(data, len,
priv->data_call_format);
}
if (list) {
@@ -844,14 +851,11 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
static void ril_data_call_deact_cancel(struct ril_data_request *req)
{
if (req->pending_id) {
grilio_queue_cancel_request(req->data->priv->q,
req->pending_id, FALSE);
req->pending_id = 0;
if (req->cb.setup) {
req->cb.deact(req->data, GRILIO_STATUS_CANCELLED,
req->arg);
}
ril_data_request_cancel_io(req);
if (req->cb.deact) {
ril_data_call_deactivate_cb_t cb = req->cb.deact;
req->cb.deact = NULL;
cb(req->data, GRILIO_STATUS_CANCELLED, req->arg);
}
}
@@ -1024,8 +1028,9 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
}
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt)
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt allow_data,
enum ril_data_call_format data_call_format)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
@@ -1034,10 +1039,10 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_sim_settings *settings = network->settings;
GRilIoRequest *req = grilio_request_new();
switch (opt) {
switch (allow_data) {
case RIL_ALLOW_DATA_ON:
case RIL_ALLOW_DATA_OFF:
priv->allow_data = opt;
priv->allow_data = allow_data;
break;
default:
/*
@@ -1049,6 +1054,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
break;
}
priv->data_call_format = data_call_format;
priv->log_prefix = (name && name[0]) ?
g_strconcat(name, " ", NULL) : g_strdup("");
@@ -1077,6 +1083,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
grilio_request_unref(req);
dm->data_list = g_slist_append(dm->data_list, self);
ril_data_manager_check_network_mode(dm);
return self;
}
return NULL;
@@ -1379,6 +1386,16 @@ void ril_data_manager_unref(struct ril_data_manager *self)
}
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static gboolean ril_data_manager_requests_pending(struct ril_data_manager *self)
{
GSList *l;
@@ -1462,16 +1479,6 @@ static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
return NULL;
}
static gboolean ril_data_manager_handover(struct ril_data_manager *self)
{
/*
* The 3G/LTE handover thing only makes sense if we are managing
* more than one SIM slot. Otherwise leave things where they are.
*/
return (self->data_list && self->data_list->next &&
(self->flags & RIL_DATA_MANAGER_3GLTE_HANDOVER));
}
static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
struct ril_data *data)
{

View File

@@ -60,6 +60,13 @@ enum ril_data_allow_data_opt {
RIL_ALLOW_DATA_OFF
};
enum ril_data_call_format {
RIL_DATA_CALL_FORMAT_AUTO,
RIL_DATA_CALL_FORMAT_6 = 6,
RIL_DATA_CALL_FORMAT_9 = 9,
RIL_DATA_CALL_FORMAT_11 = 11
};
enum ril_data_role {
RIL_DATA_ROLE_NONE, /* Data not allowed */
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
@@ -79,8 +86,9 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
int ril_status, void *arg);
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt opt);
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, enum ril_data_allow_data_opt allow_data,
enum ril_data_call_format data_call_format);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);

View File

@@ -436,9 +436,30 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
{
struct ril_sim_settings *settings = self->settings;
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = priv->max_pref_mode ?
MIN(settings->pref_mode, priv->max_pref_mode) :
settings->pref_mode;
/*
* On dual-SIM phones such as Jolla C only one slot at a time
* is allowed to use LTE. Even if the slot which has been using
* LTE gets powered off, we still need to explicitely set its
* preferred mode to GSM, to make LTE machinery available to
* the other slot. This sort of behaviour might not be necessary
* on some hardware and can (should) be made configurable when
* it becomes necessary.
*/
const enum ofono_radio_access_mode max_pref_mode =
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
OFONO_RADIO_ACCESS_MODE_GSM;
/*
* OFONO_RADIO_ACCESS_MODE_ANY is zero. If both pref_mode
* and max_pref_mode are not ANY, we pick the smallest value.
* Otherwise we take any non-zero value if there is one.
*/
const enum ofono_radio_access_mode pref_mode =
(settings->pref_mode && max_pref_mode) ?
MIN(settings->pref_mode, max_pref_mode) :
settings->pref_mode ? settings->pref_mode :
max_pref_mode;
return ril_network_mode_to_rat(self, pref_mode);
}
@@ -555,6 +576,31 @@ static int ril_network_parse_pref_resp(const void *data, guint len)
return pref;
}
static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
int status, const void *data, guint len, void *user_data)
{
if (status == RIL_E_SUCCESS) {
struct ril_network *self = RIL_NETWORK(user_data);
struct ril_network_priv *priv = self->priv;
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
priv->rat = ril_network_parse_pref_resp(data, len);
self->pref_mode = ril_network_rat_to_mode(priv->rat);
DBG_(self, "rat mode %d (%s)", priv->rat,
ofono_radio_access_mode_to_string(self->pref_mode));
if (self->pref_mode != pref_mode) {
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
}
/*
* Unlike ril_network_query_pref_mode_cb, this one always
* checks the preferred mode.
*/
ril_network_check_pref_mode(self, FALSE);
}
}
static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
@@ -661,8 +707,11 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
{
struct ril_network *self = RIL_NETWORK(data);
ril_network_check_pref_mode(self, FALSE);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(RIL_NETWORK(data));
ril_network_poll_state(self);
}
}
@@ -753,7 +802,9 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
* Query the initial state. Querying network state before the radio
* has been turned on makes RIL unhappy.
*/
ril_network_query_pref_mode(self);
grilio_queue_send_request_full(priv->q, NULL,
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
ril_network_startup_query_pref_mode_cb, NULL, self);
if (radio->state == RADIO_STATE_ON) {
ril_network_poll_state(self);
}

View File

@@ -54,6 +54,7 @@
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
#define RILMODEM_DEFAULT_EMPTY_PIN_QUERY TRUE /* optimistic */
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
@@ -71,6 +72,7 @@
#define RILCONF_ECCLIST_FILE "ecclistFile"
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
#define RIL_STORE "ril"
#define RIL_STORE_GROUP "Settings"
@@ -123,6 +125,7 @@ struct ril_slot {
int index;
int sim_flags;
enum ril_data_allow_data_opt allow_data_opt;
enum ril_data_call_format data_call_format;
struct ril_slot_config config;
struct ril_plugin_priv *plugin;
struct ril_modem *modem;
@@ -969,7 +972,8 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
GASSERT(!slot->data);
slot->data = ril_data_new(slot->plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, slot->allow_data_opt);
slot->radio, slot->network, slot->io, slot->allow_data_opt,
slot->data_call_format);
GASSERT(!slot->cell_info);
if (slot->io->ril_version > 8) {
@@ -1064,6 +1068,7 @@ static struct ril_slot *ril_plugin_slot_new(const char *sockpath,
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
slot->allow_data_opt = RILMODEM_DEFAULT_DATA_OPT;
slot->data_call_format = RILMODEM_DEFAULT_DATA_CALL_FORMAT;
return slot;
}
@@ -1153,6 +1158,7 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
strval = ril_config_get_string(file, group,
RILCONF_ALLOW_DATA_REQ);
if (strval) {
strval = g_strstrip(strval);
slot->allow_data_opt =
!strcasecmp(strval, "on") ? RIL_ALLOW_DATA_ON :
!strcasecmp(strval, "off")? RIL_ALLOW_DATA_OFF :
@@ -1164,6 +1170,27 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
g_free(strval);
}
strval = ril_config_get_string(file, group,
RILCONF_DATA_CALL_FORMAT);
if (strval) {
strval = g_strstrip(strval);
slot->data_call_format =
!strcmp(strval, "6") ? RIL_DATA_CALL_FORMAT_6:
!strcmp(strval, "9") ? RIL_DATA_CALL_FORMAT_9:
!strcmp(strval, "11")? RIL_DATA_CALL_FORMAT_11:
RIL_DATA_CALL_FORMAT_AUTO;
if (slot->data_call_format ==
RIL_DATA_CALL_FORMAT_AUTO) {
DBG("%s: %s auto", group,
RILCONF_DATA_CALL_FORMAT);
} else {
DBG("%s: %s %d", group,
RILCONF_DATA_CALL_FORMAT,
slot->data_call_format);
}
g_free(strval);
}
slot->ecclist_file = ril_config_get_string(file, group,
RILCONF_ECCLIST_FILE);
if (slot->ecclist_file && slot->ecclist_file[0]) {

View File

@@ -113,3 +113,15 @@ socket=/dev/socket/rild
# Default is true
#
#emptyPinQuery=true
# Different RILs use different data call structures which don't necessarily
# match the format specified in the data list header. The header may have
# version 9 but the list may contain RIL_Data_Call_Response_v6 structures,
# list version 10 may contain RIL_Data_Call_Response_v11 and so on. By default
# ofono assumes that the version from the list header matches the contents
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default is auto
#
#dataCallFormat=auto

View File

@@ -1,8 +1,7 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2012-2015 Jolla Ltd.
* Copyright (C) 2012-2016 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
@@ -12,11 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
@@ -35,9 +29,34 @@
#include "ofono.h"
#define NTD_WAIT_TIMEOUT (500) /* ms */
/*
* There are 3 distinct states here:
*
* 1. !valid
*
* Initial state, no time/timezone information whatsoever.
*
* 2. valid && !mccmnc
*
* Time/timezone information has been received from the network,
* but no MCC and MNC yet.
*
* 3. valid && mccmnc
*
* Time/timezone information is fully available.
*
*/
struct nt_data {
struct ofono_modem *modem;
struct ofono_netreg *netreg;
unsigned int netreg_watch_id;
unsigned int netreg_status_watch_id;
guint mccmnc_wait_id;
gboolean time_available;
gboolean time_pending;
gboolean valid;
time_t nw_time_utc;
time_t received;
@@ -47,27 +66,11 @@ struct nt_data {
char *mcc;
char *mnc;
char* path;
DBusConnection *conn;
};
static struct nt_data *nettime_new(const char *path)
{
struct nt_data *ntd = g_new0(struct nt_data, 1);
ntd->path = g_strdup(path);
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
return ntd;
}
static void nettime_free(struct nt_data *ntd)
{
dbus_connection_unref(ntd->conn);
g_free(ntd->path);
g_free(ntd->mcc);
g_free(ntd->mnc);
g_free(ntd);
}
#define DBG_(ntd,fmt,args...) \
DBG("%s " fmt, ofono_modem_get_path((ntd)->modem), ##args)
static gboolean nettime_encode_time_format(struct tm *tm,
const struct ofono_network_time *time)
@@ -110,7 +113,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"{sv}",
&iter_array);
if (ntd->time_pending) {
if (ntd->valid && ntd->mcc && ntd->mnc) {
if (ntd->time_available) {
utc_long = (dbus_int64_t) ntd->nw_time_utc;
ofono_dbus_dict_append(&iter_array,
@@ -145,7 +148,7 @@ static int nettime_fill_time_notification(DBusMessage *msg, struct nt_data *ntd)
DBUS_TYPE_STRING,
&ntd->mnc);
} else {
DBG("fill_time_notification: time not available");
DBG_(ntd, "time not available");
}
dbus_message_iter_close_container(&iter, &iter_array);
@@ -177,23 +180,209 @@ static const GDBusSignalTable nettime_signals[] = {
{ }
};
static void nettime_send_signal(struct nt_data *ntd)
{
DBusMessage *signal =
dbus_message_new_signal(ofono_modem_get_path(ntd->modem),
OFONO_NETWORK_TIME_INTERFACE, "NetworkTimeChanged");
DBG_(ntd, "");
nettime_fill_time_notification(signal, ntd);
g_dbus_send_message(ntd->conn, signal);
}
static void nettime_set_mcc_mnc(struct nt_data *ntd, const char *mcc,
const char *mnc)
{
if (g_strcmp0(ntd->mcc, mcc)) {
g_free(ntd->mcc);
ntd->mcc = g_strdup(mcc);
}
if (g_strcmp0(ntd->mnc, mnc)) {
g_free(ntd->mnc);
ntd->mnc = g_strdup(mnc);
}
if (ntd->mcc && ntd->mnc) {
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
if (ntd->mccmnc_wait_id) {
/* We have been waiting for MCC and MNC */
g_source_remove(ntd->mccmnc_wait_id);
ntd->mccmnc_wait_id = 0;
nettime_send_signal(ntd);
}
}
}
static void nettime_netreg_status_watch_cb(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc,
void *userdata)
{
nettime_set_mcc_mnc(userdata, mcc, mnc);
}
static void nettime_netreg_status_watch_done(void *userdata)
{
struct nt_data *ntd = userdata;
DBG_(ntd, "");
ntd->netreg_status_watch_id = 0;
}
static void nettime_set_netreg(struct nt_data *ntd,
struct ofono_netreg *netreg)
{
if (ntd->netreg != netreg) {
ntd->valid = FALSE;
ntd->netreg = netreg;
if (netreg) {
nettime_set_mcc_mnc(ntd,
ofono_netreg_get_mcc(netreg),
ofono_netreg_get_mnc(netreg));
ntd->netreg_status_watch_id =
__ofono_netreg_add_status_watch(netreg,
nettime_netreg_status_watch_cb, ntd,
nettime_netreg_status_watch_done);
} else {
g_free(ntd->mcc);
g_free(ntd->mnc);
ntd->mcc = NULL;
ntd->mnc = NULL;
ntd->netreg_status_watch_id = 0;
}
}
}
static void nettime_netreg_watch_cb(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *userdata)
{
struct nt_data *ntd = userdata;
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
DBG_(ntd, "registered");
nettime_set_netreg(ntd, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG_(ntd, "unregistered");
nettime_set_netreg(ntd, NULL);
}
}
static void nettime_netreg_watch_done(void *userdata)
{
struct nt_data *ntd = userdata;
DBG_(ntd, "");
ntd->netreg_watch_id = 0;
}
static gboolean nettime_timeout_cb(gpointer data)
{
struct nt_data *ntd = data;
DBG_(ntd, "timed out");
ntd->mccmnc_wait_id = 0;
ntd->valid = FALSE;
return G_SOURCE_REMOVE;
}
static struct nt_data *nettime_new(struct ofono_modem *modem)
{
struct nt_data *ntd = g_new0(struct nt_data, 1);
struct ofono_atom *netreg_atom = __ofono_modem_find_atom(modem,
OFONO_ATOM_TYPE_NETREG);
ntd->modem = modem;
ntd->conn = dbus_connection_ref(ofono_dbus_get_connection());
ntd->netreg_watch_id = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_NETREG, nettime_netreg_watch_cb,
ntd, nettime_netreg_watch_done);
if (netreg_atom) {
nettime_set_netreg(ntd, __ofono_atom_get_data(netreg_atom));
}
return ntd;
}
static void nettime_free(struct nt_data *ntd)
{
if (ntd->mccmnc_wait_id)
g_source_remove(ntd->mccmnc_wait_id);
if (ntd->netreg_status_watch_id)
__ofono_netreg_remove_status_watch(ntd->netreg,
ntd->netreg_status_watch_id);
if (ntd->netreg_watch_id)
__ofono_modem_remove_atom_watch(ntd->modem,
ntd->netreg_watch_id);
dbus_connection_unref(ntd->conn);
g_free(ntd->mcc);
g_free(ntd->mnc);
g_free(ntd);
}
static void nettime_info_received(struct ofono_nettime_context *context,
struct ofono_network_time *info)
{
struct nt_data *ntd = context->data;
struct tm t;
if (!ntd)
return;
ntd->received = nettime_get_monotonic_time();
ntd->valid = TRUE;
ntd->dst = info->dst;
ntd->time_zone = info->utcoff;
ntd->time_available = nettime_encode_time_format(&t, info);
if (ntd->time_available) {
ntd->nw_time_utc = timegm(&t);
}
DBG_(ntd, "time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
info->year, info->mon, info->mday, info->hour,
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
info->dst);
DBG_(ntd, "UTC timestamp: %li, Received (monotonic time): %li",
ntd->nw_time_utc, ntd->received);
if (ntd->mcc && ntd->mnc) {
DBG_(ntd, "MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
nettime_send_signal(ntd);
} else {
DBG_(ntd, "no MCC/MNC yet");
if (ntd->mccmnc_wait_id)
g_source_remove(ntd->mccmnc_wait_id);
ntd->mccmnc_wait_id = g_timeout_add(NTD_WAIT_TIMEOUT,
nettime_timeout_cb, ntd);
}
}
static int nettime_probe(struct ofono_nettime_context *context)
{
struct nt_data *ntd = nettime_new(ofono_modem_get_path(context->modem));
struct nt_data *ntd = nettime_new(context->modem);
const char *path = ofono_modem_get_path(context->modem);
DBG("Network time probe for modem: %p (%s)", context->modem, ntd->path);
if (g_dbus_register_interface(ntd->conn, ntd->path,
DBG("Network time probe for modem: %p (%s)", context->modem, path);
if (g_dbus_register_interface(ntd->conn, path,
OFONO_NETWORK_TIME_INTERFACE, nettime_methods,
nettime_signals, NULL, ntd, NULL)) {
context->data = ntd;
ofono_info("Registered interface %s, path %s",
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
OFONO_NETWORK_TIME_INTERFACE, path);
ofono_modem_add_interface(context->modem,
OFONO_NETWORK_TIME_INTERFACE);
return 0;
} else {
ofono_error("Could not register interface %s, path %s",
OFONO_NETWORK_TIME_INTERFACE, ntd->path);
OFONO_NETWORK_TIME_INTERFACE, path);
nettime_free(ntd);
return 1;
}
@@ -202,77 +391,16 @@ static int nettime_probe(struct ofono_nettime_context *context)
static void nettime_remove(struct ofono_nettime_context *context)
{
struct nt_data *ntd = context->data;
const char *path = ofono_modem_get_path(context->modem);
DBG("Network time remove for modem: %p (%s)", context->modem,
ofono_modem_get_path(context->modem));
DBG("Network time remove for modem: %p (%s)", context->modem, path);
ofono_modem_remove_interface(context->modem,
OFONO_NETWORK_TIME_INTERFACE);
if (!g_dbus_unregister_interface(ntd->conn, ntd->path,
OFONO_NETWORK_TIME_INTERFACE)) {
ofono_error("Network time: could not unregister interface %s"
" for %s", OFONO_NETWORK_TIME_INTERFACE, ntd->path);
}
g_dbus_unregister_interface(ntd->conn, path,
OFONO_NETWORK_TIME_INTERFACE);
nettime_free(ntd);
}
static void nettime_send_signal(struct nt_data *ntd)
{
DBusMessage *signal = dbus_message_new_signal(ntd->path,
OFONO_NETWORK_TIME_INTERFACE,
"NetworkTimeChanged");
nettime_fill_time_notification(signal, ntd);
g_dbus_send_message(ntd->conn, signal);
}
static void nettime_info_received(struct ofono_nettime_context *context,
struct ofono_network_time *info)
{
struct nt_data *ntd = context->data;
struct ofono_netreg *netreg;
const char *mcc;
const char *mnc;
struct tm t;
if (!ntd)
return;
netreg = __ofono_atom_get_data(__ofono_modem_find_atom(
context->modem, OFONO_ATOM_TYPE_NETREG));
mcc = ofono_netreg_get_mcc(netreg);
mnc = ofono_netreg_get_mnc(netreg);
if (!mcc || !mnc) {
DBG("Incomplete network time received, ignoring");
return;
}
g_free(ntd->mcc);
g_free(ntd->mnc);
ntd->mcc = g_strdup(mcc);
ntd->mnc = g_strdup(mnc);
ntd->received = nettime_get_monotonic_time();
ntd->time_pending = TRUE;
ntd->dst = info->dst;
ntd->time_zone = info->utcoff;
ntd->time_available = nettime_encode_time_format(&t, info);
if (ntd->time_available) {
ntd->nw_time_utc = timegm(&t);
}
nettime_send_signal(ntd);
DBG("modem: %p (%s)", context->modem, ntd->path);
DBG("time: %04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d (DST=%d)",
info->year, info->mon, info->mday, info->hour,
info->min, info->sec, info->utcoff > 0 ? '+' : '-',
abs(info->utcoff) / 3600, (abs(info->utcoff) % 3600) / 60,
info->dst);
DBG("UTC timestamp: %li, Received (monotonic time): %li",
ntd->nw_time_utc, ntd->received);
DBG("MCC: %s, MNC: %s", ntd->mcc, ntd->mnc);
}
static struct ofono_nettime_driver driver = {
.name = "Network Time",
.probe = nettime_probe,

View File

@@ -135,6 +135,7 @@ struct pri_context {
struct ofono_gprs *gprs;
};
static void gprs_attached_update(struct ofono_gprs *gprs);
static void gprs_netreg_update(struct ofono_gprs *gprs);
static void gprs_deactivate_next(struct ofono_gprs *gprs);
static void write_context_settings(struct ofono_gprs *gprs,
@@ -1148,6 +1149,16 @@ static void pri_deactivate_callback(const struct ofono_error *error, void *data)
ofono_dbus_signal_property_changed(conn, ctx->path,
OFONO_CONNECTION_CONTEXT_INTERFACE,
"Active", DBUS_TYPE_BOOLEAN, &value);
/*
* If "Attached" property was about to be signalled as TRUE but there
* were still active contexts, try again to signal "Attached" property
* to registered applications after active contexts have been released.
*/
if (ctx->gprs->flags & GPRS_FLAG_ATTACHED_UPDATE) {
ctx->gprs->flags &= ~GPRS_FLAG_ATTACHED_UPDATE;
gprs_attached_update(ctx->gprs);
}
}
static void pri_read_settings_callback(const struct ofono_error *error,
@@ -2358,13 +2369,13 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
if (ctx == NULL)
return __ofono_error_not_found(msg);
/* This context is already being messed with */
if (ctx->pending)
return __ofono_error_busy(msg);
if (ctx->active) {
struct ofono_gprs_context *gc = ctx->context_driver;
/* This context is already being messed with */
if (ctx->pending)
return __ofono_error_busy(msg);
gprs->pending = dbus_message_ref(msg);
gc->driver->deactivate_primary(gc, ctx->context.cid,
gprs_deactivate_for_remove, ctx);