mirror of
https://github.com/sailfishos/ofono
synced 2025-11-28 05:21:05 +08:00
Compare commits
14 Commits
mer/1.18+g
...
mer/1.18+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2520664c63 | ||
|
|
445bbbd66f | ||
|
|
08fc4b0d03 | ||
|
|
c82e94ffb4 | ||
|
|
fd3712940b | ||
|
|
8410c985c9 | ||
|
|
0878decdc0 | ||
|
|
cb69984722 | ||
|
|
1fe8701f1a | ||
|
|
c5286fee70 | ||
|
|
3c5f6f84e1 | ||
|
|
8b87b55e8d | ||
|
|
bce34cbff3 | ||
|
|
f8351cacf1 |
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user