Compare commits

..

42 Commits

Author SHA1 Message Date
Slava Monich
b3a18326e1 Merge branch 'pin' into 'master'
Don't expect that SIM changes state after pin change

See merge request !41
2016-02-29 13:44:38 +00:00
Slava Monich
93e564d5e5 [ril] Don't expect that SIM changes state after pin change. Fixes JB#34393 2016-02-29 15:26:10 +02:00
Slava Monich
42847e03b5 [ril] Fixed a memory leak in ril_sim_change_passwd 2016-02-29 15:08:34 +02:00
Slava Monich
2100a8d975 [ril] Removed incorrect asserts in ril_sim_info_handle_sim_state
It receives OFONO_SIM_STATE_NOT_PRESENT when SIM is removed
and there's nothing wrong with that.
2016-02-27 02:46:56 +02:00
Slava Monich
c393e63e4e [ril] Replaced G_INLINE_FUNC with 'static inline'
According to glib docs the use of this macro is strongly discouraged
2016-02-26 16:38:06 +02:00
Slava Monich
b24bc9761b Merge branch 'defaults' into 'master'
Try harder to pick the first SIM as the default

See merge request !39
2016-02-26 14:32:59 +00:00
Slava Monich
06daa7cf21 [ril] Try harder to pick the first SIM as the default. Contributes to JB#34203 2016-02-26 16:30:08 +02:00
Slava Monich
49215d60b2 Merge branch 'ussd' into 'master'
Complete ussd send requests immediately

Otherwise ofono ussd machinery may still be in the IDLE state when
the response arrives, breaking the workflow that involves user action.

See merge request !38
2016-02-22 14:50:13 +00:00
Slava Monich
f3f3b73d6f [ril] Complete ussd send requests immediately. Fixes JB#33891
Otherwise ofono ussd machinery may still be in the IDLE state
when the response arrives, breaking the workflow that involves
user action.
2016-02-22 15:15:45 +03:00
Slava Monich
113d9424b5 Merge branch 'power' into 'master'
See merge request !36
2016-02-18 12:33:12 +00:00
Slava Monich
2a8489c4d9 [ril] Don't power up the modem at startup. Fixes JB#34230
It's powered up when it goes online.
2016-02-18 13:21:57 +03:00
Slava Monich
c4f968b87a Merge branch 'nosimsettings' into 'master'
Remove org.nemomobile.ofono.SimSettings D-Bus interface

It's no longer being used. SIM name is stored in dconf and is of no use
to ofono, enable4G flag is useless - AvailableTechnologies property of
org.ofono.RadioSettings interface tells which radio technologies are
supported.

See merge request !35
2016-02-17 22:01:00 +00:00
Slava Monich
537c7ae8b4 Merge branch 'scan' into 'master'
Allow multiple Scan and (auto) Register requests.

While one of those requests is pending it makes no sense to block
other such requests.

See merge request !33
2016-02-17 22:00:00 +00:00
Slava Monich
b320fc7f59 [ril] Removed org.nemomobile.ofono.SimSettings D-Bus interface. Contributes to JB#34189
It's no longer being used. SIM name is stored in dconf and is of
no use to ofono, enable4G flag is useless - AvailableTechnologies
property of org.ofono.RadioSettings interface tells which radio
technologies are supported.
2016-02-11 22:00:29 +03:00
Slava Monich
edf49e6e99 [ril] Replaced assert with a comment 2016-02-10 12:24:53 +03:00
Slava Monich
b7985a1d67 Merge branch 'null' into 'master'
Fix crash on unexpected DATA_CALL_LIST payload

Debug trace didn't check pointers for NULL

See merge request !32
2016-02-08 11:35:24 +00:00
Slava Monich
bbb2c68a72 [ofono] network: Allow multiple Scan and (auto) Register requests.
While one of those requests is pending it makes no sense to
block other such requests.
2016-02-07 13:46:27 +03:00
Slava Monich
bd3f7f35eb [ril] Fixed crash on unexpected DATA_CALL_LIST payload
Debug trace didn't check pointers for NULL
2016-02-06 17:36:24 +03:00
Slava Monich
65bf1a24fa Merge branch 'sim_info' into 'master'
Slightly more generic handling of ofono watchlists

Without registering the free watch callback we can't be sure
whether the watchlist is still alive and that it's safe to call
the watch remove function (if the corresponding watchlist is
already deallocated, the ofono core may choose to crash). This
patch adds generic remove callback ril_sim_info_watch_done() for
all watches and fixes a few minor unrelated issues.

See merge request !31
2016-02-05 09:40:35 +00:00
Slava Monich
0c37015145 [ril] sim_info: Slightly more generic handling of ofono watchlists 2016-02-03 19:39:26 +02:00
Slava Monich
a8551cdce7 [ril] Housekeeping 2016-02-03 17:26:24 +02:00
Slava Monich
5bd2b96240 Merge branch 'mtu' into 'master'
MTU watcher

rild, modem driver or whatever is changing MTU of the mobile
data network interface without informing us. Since we don't
get any notifications from rild when that happens, the solution
that I came up with turned out to be slightly more complicated
than I hoped. But it works.

See merge request !30
2016-02-02 16:22:46 +00:00
Slava Monich
3bf309b887 [ofono] gprs: Took MTU management out of the ofono core
These changes have never been merged upstream and partially
duplicate MTU watcher (part of the RIL plugin).
2016-02-02 18:19:07 +02:00
Slava Monich
c14b9bbf93 [ril] MTU watcher. Fixes JB#33639
rild, modem driver or whatever is changing MTU of the mobile data
network interface without informing us. We don't want MTU to be
greater than 1280.
2016-02-02 18:19:07 +02:00
Slava Monich
568bd615cd Merge branch 'siminfo' into 'master'
org.nemomobile.ofono.SimInfo interface

Allows the client to fetch cached SubscriberIdentity and ServiceProviderName before the pin code is entered. ICCID
to IMSI map is stored in /var/lib/ofono/iccidmap, cached
SIM properties in /var/lib/ofono/IMSI/cache
2016-02-02 16:17:15 +00:00
Slava Monich
4d55f94015 [ril] Added org.nemomobile.ofono.SimInfo interface. Contributes to JB#34053
Allows the client to fetch cached SubscriberIdentity and
ServiceProviderName before the pin code is entered.
2016-01-31 17:08:27 +02:00
Slava Monich
95d06963cd [ofono] sim: Add iccid and imsi watches 2016-01-31 17:08:27 +02:00
Slava Monich
479458138a [ofono] watch: Ensure that watch id is non-zero 2016-01-31 17:08:27 +02:00
Slava Monich
c221d677d1 [rilmodem] Fixed compilation of the old rilmodem code 2016-01-31 16:48:06 +02:00
Slava Monich
a32da19192 [ril] Fixed possible crash on exit
==5482== Invalid free() / delete / delete[] / realloc()
==5482==    at 0x4840ABC: free (vg_replace_malloc.c:473)
==5482==    by 0x206E7: ril_data_call_setup_free (ril_data.c:727)
==5482==    by 0x1FE17: ril_data_call_request_free (ril_data.c:490)
==5482==    by 0x1FFC7: ril_data_call_request_cancel (ril_data.c:537)
==5482==    by 0x21707: ril_data_dispose (ril_data.c:1103)
==5482==    by 0x4A1EE57: g_object_unref (gobject.c:3160)
==5482==    by 0x21177: ril_data_unref (ril_data.c:971)
==5482==    by 0x2C32F: ril_plugin_shutdown_slot (ril_plugin.c:223)
==5482==    by 0x2EC2F: ril_plugin_delete_slot (ril_plugin.c:1023)
==5482==    by 0x2F077: ril_plugin_destroy_slot (ril_plugin.c:1127)
==5482==    by 0x4ACE9AF: g_slist_foreach (gslist.c:896)
==5482==    by 0x4ACE9C1: g_slist_free_full (gslist.c:179)
==5482==  Address 0x5bf1c40 is 0 bytes inside a block of size 48 free'd
==5482==    at 0x4840ABC: free (vg_replace_malloc.c:473)
==5482==    by 0x206E7: ril_data_call_setup_free (ril_data.c:727)
==5482==    by 0x1FE17: ril_data_call_request_free (ril_data.c:490)
==5482==    by 0x1FFC7: ril_data_call_request_cancel (ril_data.c:537)
==5482==    by 0x24A2B: ril_gprs_context_remove (ril_gprs_context.c:601)
==5482==    by 0x134803: gprs_context_remove (gprs.c:2841)
==5482==    by 0xDFD73: flush_atoms (modem.c:429)
==5482==    by 0xE002F: modem_change_state (modem.c:507)
==5482==    by 0xE0C7F: set_powered (modem.c:878)
==5482==    by 0xE3E5B: __ofono_modem_shutdown (modem.c:2207)
==5482==    by 0xDDDE7: signal_handler (main.c:77)
==5482==    by 0x4AB1B85: g_main_dispatch (gmain.c:3066)
==5482==    by 0x4AB1B85: g_main_context_dispatch (gmain.c:3642)
2016-01-31 03:24:25 +02:00
Slava Monich
a20da10621 [ril] Fixed assert in dbus library. Contributes to JB#28417
It doesn't like NULL strings so much that it terminates the app.
2016-01-30 00:37:50 +02:00
Slava Monich
64c754c3b9 [ril] Housekeeping
Use G_SOURCE_REMOVE instead of FALSE where appropriate
2016-01-29 17:48:13 +02:00
Slava Monich
d64fd7dca7 Merge branch 'enable4G' into 'master'
Remove Enable4GChanged signal from the introspection data

Enable4G flag never changes, therefore this signal is never sent.
    
Even though this flag it not being used by the UI anymore,
it still has to be kept it around to avoid breaking D-Bus API.

See merge request !28
2016-01-29 15:16:12 +00:00
Slava Monich
f608c0821a [ril] Remove Enable4GChanged signal from the introspection data
Enable4G flag never changes, therefore this signal is never sent.

Even though this flag it not being used by the UI anymore, it still
has to be kept it around to avoid breaking D-Bus API.
2016-01-29 12:43:01 +02:00
Slava Monich
7d29ef130a Housekeeping 2016-01-26 15:37:10 +02:00
Slava Monich
141eadee1d Merge branch 'mmssim' into 'master'
Add Get/SetMmsSim functionality

If MMS data SIM is different from the default data SIM, then MMS SIM
is selected for data and defaultDataModem is emptied, which tells
connman not to mess with mobile data while MMS is being transmitted.

SetMmsSim returns the path of the modem where the requested SIM is
or an empty string if there's no such SIM (or it's locked). This
information may or may not be useful to the client.
    
The behaviour gets reset back to default when IMSI of the MMS SIM is
set to empty string or the client which set it, exits. The client is
going to be mms-engine.

See merge request !26
2016-01-26 13:29:39 +00:00
Slava Monich
e84602d79c [ril] Add Get/SetMmsSim functionality. Contributes to #28417
If MMS data SIM is different from the default data SIM, then MMS SIM
is selected for data and defaultDataModem is emptied, which tells connman
not to mess with mobile data while MMS is being transmitted.

SetMmsSim returns the path of the modem where the requested SIM is
or an empty string if there's no such SIM (or it's locked).

The behaviour gets reset back to default when IMSI of the MMS SIM
is set to empty string or the client which set it, exits.
2016-01-26 02:10:07 +02:00
Slava Monich
b63b6355d5 [ril] Moved context setup and deactivation to ril_data. Contributes to JB#33358
This will allow to properly serialize the actions when switching
the data SIMs.
2016-01-26 02:10:07 +02:00
Slava Monich
f7f007a122 Merge branch 'EFspn' into 'master'
Add ServiceProviderName property to SimManager

Contains the service provider name fetched from the SIM card, if available.

See merge request !27
2016-01-25 23:57:21 +00:00
Slava Monich
5769656848 [ofono] sim: Add ServiceProviderName property to SimManager
Contains the service provider name fetched from the SIM card, if available.
2016-01-26 00:21:23 +02:00
Slava Monich
bbc276b4c7 [ril] Reduced the amount of debug trace produced by ril_radio.c 2016-01-23 18:53:05 +02:00
Slava Monich
4b79de53fe [gprs] Removed unnecessary debug trace 2016-01-21 14:05:11 +02:00
30 changed files with 3023 additions and 1052 deletions

View File

@@ -132,6 +132,7 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_gprs_context.c \
drivers/ril/ril_mce.c \
drivers/ril/ril_modem.c \
drivers/ril/ril_mtu.c \
drivers/ril/ril_netreg.c \
drivers/ril/ril_network.c \
drivers/ril/ril_oem_raw.c \
@@ -142,7 +143,8 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_radio_settings.c \
drivers/ril/ril_sim.c \
drivers/ril/ril_sim_card.c \
drivers/ril/ril_sim_dbus.c \
drivers/ril/ril_sim_info.c \
drivers/ril/ril_sim_info_dbus.c \
drivers/ril/ril_sms.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \

View File

@@ -93,6 +93,11 @@ Properties boolean Present [readonly]
Contains the IMSI of the SIM, if available.
string ServiceProviderName [readonly, optional]
Contains the service provider name fetched from the
SIM card, if available.
string MobileCountryCode [readonly, optional]
Contains the Mobile Country Code (MCC) of the home

View File

@@ -158,23 +158,54 @@ enum ril_radio_tech {
#define CALL_FAIL_FACILITY_REJECTED 29
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
};
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
/* See RIL_REQUEST_SETUP_DATA_CALL */
/* RIL_REQUEST_SETUP_DATA_CALL */
enum ril_data_profile {
RIL_DATA_PROFILE_DEFAULT = 0,
RIL_DATA_PROFILE_TETHERED = 1,
RIL_DATA_PROFILE_IMS = 2,
RIL_DATA_PROFILE_FOTA = 3,
RIL_DATA_PROFILE_CBS = 4,
RIL_DATA_PROFILE_OEM_BASE = 1000,
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
};
#define RIL_DATA_PROFILE_DEFAULT 0
#define RIL_DATA_PROFILE_TETHERED 1
#define RIL_DATA_PROFILE_IMS 2
#define RIL_DATA_PROFILE_FOTA 3 /* FOTA = Firmware Over the Air */
#define RIL_DATA_PROFILE_CBS 4
#define RIL_DATA_PROFILE_OEM_BASE 1000 /* Start of OEM-specific profiles */
#define RIL_AUTH_NONE 0
#define RIL_AUTH_PAP 1
#define RIL_AUTH_CHAP 2
#define RIL_AUTH_BOTH 3
enum ril_auth {
RIL_AUTH_NONE = 0,
RIL_AUTH_PAP = 1,
RIL_AUTH_CHAP = 2,
RIL_AUTH_BOTH = 3
};
#define RIL_CARD_MAX_APPS 8

File diff suppressed because it is too large Load Diff

View File

@@ -17,24 +17,81 @@
#define RIL_DATA_H
#include "ril_types.h"
#include <ofono/gprs-context.h>
enum ril_data_call_active {
RIL_DATA_CALL_INACTIVE = 0,
RIL_DATA_CALL_LINK_DOWN = 1,
RIL_DATA_CALL_ACTIVE = 2
};
struct ril_data_call {
int cid;
enum ril_data_call_fail_cause status;
enum ril_data_call_active active;
enum ofono_gprs_proto prot;
int retry_time;
int mtu;
char *ifname;
char **dnses;
char **gateways;
char **addresses;
};
struct ril_data_call_list {
guint version;
guint num;
GSList *calls;
};
struct ril_data {
GObject object;
struct ril_data_priv *priv;
struct ril_data_call_list *data_calls;
};
struct ril_data_manager;
struct ril_data_manager *ril_data_manager_new(void);
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
void ril_data_manager_unref(struct ril_data_manager *dm);
struct ril_data *ril_data_new(struct ril_data_manager *dm, GRilIoChannel *io);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
int ril_status, const struct ril_data_call *call,
void *arg);
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,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
void ril_data_set_name(struct ril_data *data, const char *name);
void ril_data_allow(struct ril_data *data, gboolean allow);
gboolean ril_data_allowed(struct ril_data *data);
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
gulong ril_data_add_calls_changed_handler(struct ril_data *data,
ril_data_cb_t cb, void *arg);
void ril_data_remove_handler(struct ril_data *data, gulong id);
void ril_data_allow(struct ril_data *data, gboolean allow);
struct ril_data_call_request;
struct ril_data_call_request *ril_data_call_setup(struct ril_data *data,
const struct ofono_gprs_primary_context *ctx,
ril_data_call_setup_cb_t cb, void *arg);
struct ril_data_call_request *ril_data_call_deactivate(struct ril_data *data,
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
void ril_data_call_request_detach(struct ril_data_call_request *req);
void ril_data_call_request_cancel(struct ril_data_call_request *req);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
#endif /* RIL_DATA_H */
/*

View File

@@ -15,122 +15,46 @@
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_mtu.h"
#include "ril_log.h"
#include <gutil_strv.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "common.h"
#define PROTO_IP_STR "IP"
#define PROTO_IPV6_STR "IPV6"
#define PROTO_IPV4V6_STR "IPV4V6"
#define MIN_DATA_CALL_LIST_SIZE 8
#define MIN_DATA_CALL_REPLY_SIZE 36
#define SETUP_DATA_CALL_PARAMS 7
#define DATA_PROFILE_DEFAULT_STR "0"
#define DEACTIVATE_DATA_CALL_PARAMS 2
#define CTX_ID_NONE ((unsigned int)(-1))
enum data_call_state {
DATA_CALL_INACTIVE,
DATA_CALL_LINK_DOWN,
DATA_CALL_ACTIVE,
};
#define MAX_MTU 1280
enum ril_gprs_context_state {
STATE_IDLE,
STATE_ACTIVATING,
STATE_DEACTIVATING,
STATE_ACTIVE,
struct ril_gprs_context_call {
struct ril_data_call_request *req;
ofono_gprs_context_cb_t cb;
gpointer data;
};
struct ril_gprs_context {
struct ofono_gprs_context *gc;
struct ril_modem *modem;
struct ril_network *network;
GRilIoChannel *io;
GRilIoQueue *q;
struct ril_data *data;
guint active_ctx_cid;
enum ril_gprs_context_state state;
gulong regid;
struct ril_gprs_context_data_call *active_call;
struct ril_gprs_context_deactivate_req *deactivate_req;
gulong calls_changed_event_id;
struct ril_mtu_watch *mtu_watch;
struct ril_data_call *active_call;
struct ril_gprs_context_call activate;
struct ril_gprs_context_call deactivate;
};
struct ril_gprs_context_data_call {
guint status;
gint cid;
guint active;
int retry_time;
int prot;
gint mtu;
gchar *ifname;
gchar **dnses;
gchar **gateways;
gchar **addresses;
};
struct ril_gprs_context_data_call_list {
guint version;
guint num;
GSList *calls;
};
struct ril_gprs_context_cbd {
struct ril_gprs_context *gcd;
ofono_gprs_context_cb_t cb;
gpointer data;
};
struct ril_gprs_context_deactivate_req {
struct ril_gprs_context_cbd cbd;
gint cid;
};
#define ril_gprs_context_cbd_free g_free
#define ril_gprs_context_deactivate_req_free g_free
static inline struct ril_gprs_context *ril_gprs_context_get_data(
struct ofono_gprs_context *gprs)
{
return ofono_gprs_context_get_data(gprs);
}
static struct ril_gprs_context_cbd *ril_gprs_context_cbd_new(
struct ril_gprs_context *gcd, ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context_cbd *cbd =
g_new0(struct ril_gprs_context_cbd, 1);
cbd->gcd = gcd;
cbd->cb = cb;
cbd->data = data;
return cbd;
}
static struct ril_gprs_context_deactivate_req *
ril_gprs_context_deactivate_req_new(struct ril_gprs_context *gcd,
ofono_gprs_context_cb_t cb, void *data)
{
struct ril_gprs_context_deactivate_req *req =
g_new0(struct ril_gprs_context_deactivate_req, 1);
req->cbd.gcd = gcd;
req->cbd.cb = cb;
req->cbd.data = data;
req->cid = gcd->active_call->cid;
return req;
}
static char *ril_gprs_context_netmask(const char *address)
{
if (address) {
@@ -152,34 +76,6 @@ static char *ril_gprs_context_netmask(const char *address)
return g_strdup("255.255.255.0");
}
static const char *ril_gprs_ofono_protocol_to_ril(guint protocol)
{
switch (protocol) {
case OFONO_GPRS_PROTO_IPV6:
return PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return PROTO_IP_STR;
default:
return NULL;
}
}
static int ril_gprs_protocol_to_ofono(gchar *protocol_str)
{
if (protocol_str) {
if (!strcmp(protocol_str, PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(protocol_str, PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(protocol_str, PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
static void ril_gprs_context_set_ipv4(struct ofono_gprs_context *gc,
char * const *ip_addr)
{
@@ -209,34 +105,67 @@ static void ril_gprs_context_set_ipv6(struct ofono_gprs_context *gc,
}
}
static void ril_gprs_context_data_call_free(
struct ril_gprs_context_data_call *call)
static void ril_gprs_context_call_done(struct ril_gprs_context_call *call,
gboolean ok)
{
ofono_gprs_context_cb_t cb = call->cb;
gpointer data = call->data;
ril_data_call_request_cancel(call->req);
call->req = NULL;
call->cb = NULL;
call->data = NULL;
if (cb) {
struct ofono_error error;
cb(ok ? ril_error_ok(&error) : ril_error_failure(&error), data);
}
}
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
if (gcd->calls_changed_event_id) {
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
gcd->calls_changed_event_id = 0;
}
if (gcd->mtu_watch) {
ril_mtu_watch_free(gcd->mtu_watch);
gcd->mtu_watch = NULL;
}
}
static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
const struct ril_data_call *call)
{
if (call) {
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
g_free(call);
ril_data_call_free(gcd->active_call);
gcd->active_call = ril_data_call_dup(call);
if (!gcd->mtu_watch) {
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
}
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
} else {
ril_gprs_context_free_active_call(gcd);
}
}
static void ril_gprs_context_set_disconnected(struct ril_gprs_context *gcd)
{
gcd->state = STATE_IDLE;
if (gcd->active_call) {
if (gcd->deactivate_req &&
gcd->deactivate_req->cid == gcd->active_call->cid) {
/* Mark this request as done */
gcd->deactivate_req->cbd.gcd = NULL;
gcd->deactivate_req = NULL;
ril_gprs_context_free_active_call(gcd);
if (gcd->deactivate.req) {
ril_gprs_context_call_done(&gcd->deactivate, TRUE);
}
ril_gprs_context_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
if (gcd->active_ctx_cid != CTX_ID_NONE) {
guint id = gcd->active_ctx_cid;
gcd->active_ctx_cid = CTX_ID_NONE;
DBG("ofono context %u deactivated", id);
ofono_gprs_context_deactivated(gcd->gc, id);
}
}
@@ -316,57 +245,10 @@ static void ril_gprs_split_dns_by_protocol(char **dns_array, char ***dns_addr,
}
}
static gint ril_gprs_context_parse_data_call_compare(gconstpointer a,
gconstpointer b)
{
const struct ril_gprs_context_data_call *ca = a;
const struct ril_gprs_context_data_call *cb = b;
if (ca->cid < cb->cid) {
return -1;
} else if (ca->cid > cb->cid) {
return 1;
} else {
return 0;
}
}
static void ril_gprs_context_data_call_free1(gpointer data)
{
ril_gprs_context_data_call_free(data);
}
static void ril_gprs_context_data_call_list_free(
struct ril_gprs_context_data_call_list *list)
{
if (list) {
g_slist_free_full(list->calls, ril_gprs_context_data_call_free1);
g_free(list);
}
}
static struct ril_gprs_context_data_call *ril_gprs_context_data_call_find(
struct ril_gprs_context_data_call_list *list, gint cid)
{
if (list) {
GSList *entry;
for (entry = list->calls; entry; entry = entry->next) {
struct ril_gprs_context_data_call *call = entry->data;
if (call->cid == cid) {
return call;
}
}
}
return NULL;
}
/* Only compares the stuff that's important to us */
static gboolean ril_gprs_context_data_call_equal(
const struct ril_gprs_context_data_call *c1,
const struct ril_gprs_context_data_call *c2)
const struct ril_data_call *c1,
const struct ril_data_call *c2)
{
if (!c1 && !c2) {
return TRUE;
@@ -382,134 +264,58 @@ static gboolean ril_gprs_context_data_call_equal(
}
}
static struct ril_gprs_context_data_call *
ril_gprs_context_parse_data_call(int version, GRilIoParser *rilp)
static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
{
char *prot;
struct ril_gprs_context_data_call *call =
g_new0(struct ril_gprs_context_data_call, 1);
grilio_parser_get_uint32(rilp, &call->status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
grilio_parser_get_uint32(rilp, &call->active);
prot = grilio_parser_get_utf8(rilp);
call->ifname = grilio_parser_get_utf8(rilp);
call->addresses = grilio_parser_split_utf8(rilp, " ");
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
call->prot = ril_gprs_protocol_to_ofono(prot);
if (call->prot < 0) {
ofono_error("Invalid type(protocol) specified: %s", prot);
}
g_free(prot);
if (version >= 9) {
/* PCSCF */
grilio_parser_skip_string(rilp);
if (version >= 11) {
/* MTU */
grilio_parser_get_int32(rilp, &call->mtu);
}
}
return call;
}
static struct ril_gprs_context_data_call_list *
ril_gprs_context_parse_data_call_list(const void *data, guint len)
{
struct ril_gprs_context_data_call_list *reply =
g_new0(struct ril_gprs_context_data_call_list, 1);
GRilIoParser rilp;
unsigned int i, n;
grilio_parser_init(&rilp, data, len);
grilio_parser_get_uint32(&rilp, &reply->version);
grilio_parser_get_uint32(&rilp, &n);
DBG("version=%d,num=%d", reply->version, n);
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_gprs_context_data_call *call =
ril_gprs_context_parse_data_call(reply->version, &rilp);
DBG("%d [status=%d,retry=%d,cid=%d,"
"active=%d,type=%s,ifname=%s,mtu=%d,"
"address=%s, dns=%s %s,gateways=%s]",
i, call->status, call->retry_time,
call->cid, call->active,
ril_gprs_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu, call->addresses[0],
call->dnses[0],
(call->dnses[0] && call->dnses[1]) ?
call->dnses[1] : "",
call->gateways[0]);
reply->num++;
reply->calls = g_slist_insert_sorted(reply->calls, call,
ril_gprs_context_parse_data_call_compare);
}
return reply;
}
static void ril_gprs_context_call_list_changed(GRilIoChannel *io, guint event,
const void *data, guint len, void *user_data)
{
struct ril_gprs_context *gcd = user_data;
struct ril_gprs_context *gcd = arg;
struct ofono_gprs_context *gc = gcd->gc;
struct ril_gprs_context_data_call *call = NULL;
struct ril_gprs_context_data_call *prev_call;
struct ril_gprs_context_data_call_list *unsol =
ril_gprs_context_parse_data_call_list(data, len);
if (gcd->active_call) {
/* Find our call */
call = ril_gprs_context_data_call_find(unsol,
gcd->active_call->cid);
if (call) {
/* Check if the call have been disconnected */
if (call->active == DATA_CALL_INACTIVE) {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
call = NULL;
/*
* gcd->active_call can't be NULL here because this callback
* is only registered when we have the active call and released
* when active call is dropped.
*/
struct ril_data_call *prev_call = gcd->active_call;
const struct ril_data_call *call =
ril_data_call_find(data->data_calls, prev_call->cid);
/* Compare it agains the last known state */
} else if (ril_gprs_context_data_call_equal(call,
gcd->active_call)) {
DBG("call %u didn't change", call->cid);
call = NULL;
} else {
/* Steal it from the list */
DBG("call %u changed", call->cid);
unsol->calls = g_slist_remove(unsol->calls,
call);
}
} else {
if (call) {
/* Check if the call has been disconnected */
if (call->active == RIL_DATA_CALL_INACTIVE) {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
}
}
call = NULL;
/* We don't need the rest of the list anymore */
ril_gprs_context_data_call_list_free(unsol);
/* Compare it against the last known state */
} else if (ril_gprs_context_data_call_equal(call, prev_call)) {
DBG("call %u didn't change", call->cid);
call = NULL;
} else {
DBG("call %u changed", call->cid);
}
} else {
ofono_error("Clearing active context");
ril_gprs_context_set_disconnected(gcd);
}
if (!call) {
/* We are not interested */
return;
}
/* Store the updated call data */
prev_call = gcd->active_call;
gcd->active_call = call;
/*
* prev_call points to the previous active call, and it will
* be deallocated at the end of the this function. Clear the
* gcd->active_call pointer so that we don't deallocate it twice.
*/
gcd->active_call = NULL;
ril_gprs_context_set_active_call(gcd, call);
if (call->status != 0) {
if (call->status != PDP_FAIL_NONE) {
ofono_info("data call status: %d", call->status);
}
if (call->active == DATA_CALL_ACTIVE) {
if (call->active == RIL_DATA_CALL_ACTIVE) {
gboolean signal = FALSE;
if (call->ifname && g_strcmp0(call->ifname, prev_call->ifname)) {
@@ -605,51 +411,37 @@ static void ril_gprs_context_call_list_changed(GRilIoChannel *io, guint event,
}
}
ril_gprs_context_data_call_free(prev_call);
ril_data_call_free(prev_call);
}
static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
int ril_status, const struct ril_data_call *call,
void *user_data)
{
struct ril_gprs_context_cbd *cbd = user_data;
ofono_gprs_context_cb_t cb = cbd->cb;
struct ril_gprs_context *gcd = cbd->gcd;
struct ril_gprs_context *gcd = user_data;
struct ofono_gprs_context *gc = gcd->gc;
struct ofono_error error;
struct ril_gprs_context_data_call_list *reply = NULL;
struct ril_gprs_context_data_call *call;
char **split_ip_addr = NULL;
char **split_ipv6_addr = NULL;
char* ip_gw = NULL;
char* ipv6_gw = NULL;
char** dns_addr = NULL;
char** dns_ipv6_addr = NULL;
ofono_gprs_context_cb_t cb;
gpointer cb_data;
ofono_info("setting up data call");
ril_error_init_ok(&error);
if (status != RIL_E_SUCCESS) {
ril_error_init_failure(&error);
if (ril_status != RIL_E_SUCCESS) {
ofono_error("GPRS context: Reply failure: %s",
ril_error_to_string(status));
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = status;
ril_gprs_context_set_disconnected(gcd);
ril_error_to_string(ril_status));
goto done;
}
reply = ril_gprs_context_parse_data_call_list(data, len);
if (reply->num != 1) {
ofono_error("Number of data calls: %u", reply->num);
ril_error_init_failure(&error);
ril_gprs_context_set_disconnected(gcd);
goto done;
}
call = reply->calls->data;
if (call->status != 0) {
if (call->status != PDP_FAIL_NONE) {
ofono_error("Unexpected data call status %d", call->status);
error.type = OFONO_ERROR_TYPE_FAILURE;
error.type = OFONO_ERROR_TYPE_CMS;
error.error = call->status;
goto done;
}
@@ -657,9 +449,6 @@ static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
/* Must have interface */
if (!call->ifname) {
ofono_error("GPRS context: No interface");
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = EINVAL;
ril_gprs_context_set_disconnected(gcd);
goto done;
}
@@ -668,35 +457,25 @@ static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
&split_ipv6_addr);
if (!split_ip_addr && !split_ipv6_addr) {
ofono_error("GPRS context: No IP address");
error.type = OFONO_ERROR_TYPE_FAILURE;
error.error = EINVAL;
ril_gprs_context_set_disconnected(gcd);
goto done;
}
/* Steal the call data from the list */
g_slist_free(reply->calls);
reply->calls = NULL;
ril_gprs_context_data_call_free(gcd->active_call);
gcd->active_call = call;
gcd->state = STATE_ACTIVE;
ril_error_init_ok(&error);
ril_gprs_context_set_active_call(gcd, call);
GASSERT(!gcd->calls_changed_event_id);
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
gcd->calls_changed_event_id =
ril_data_add_calls_changed_handler(gcd->data,
ril_gprs_context_call_list_changed, gcd);
ofono_gprs_context_set_interface(gc, call->ifname);
ril_gprs_split_gw_by_protocol(call->gateways, &ip_gw, &ipv6_gw);
ril_gprs_split_dns_by_protocol(call->dnses, &dns_addr, &dns_ipv6_addr);
/* TODO:
* RILD can return multiple addresses; oFono only supports setting
* a single IPv4 and single IPV6 address. At this time, we only use
* the first address. It's possible that a RIL may just specify
* the end-points of the point-to-point connection, in which case this
* code will need to changed to handle such a device.
*/
if (split_ipv6_addr &&
(call->prot == OFONO_GPRS_PROTO_IPV6 ||
call->prot == OFONO_GPRS_PROTO_IPV4V6)) {
ril_gprs_context_set_ipv6(gc, split_ipv6_addr);
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
ofono_gprs_context_set_ipv6_dns_servers(gc,
@@ -713,7 +492,6 @@ static void ril_gprs_context_activate_primary_cb(GRilIoChannel *io, int status,
}
done:
ril_gprs_context_data_call_list_free(reply);
g_strfreev(split_ip_addr);
g_strfreev(split_ipv6_addr);
g_strfreev(dns_addr);
@@ -721,7 +499,17 @@ done:
g_free(ip_gw);
g_free(ipv6_gw);
cb(&error, cbd->data);
cb = gcd->activate.cb;
cb_data = gcd->activate.data;
GASSERT(gcd->activate.req);
memset(&gcd->activate, 0, sizeof(gcd->activate));
if (cb) {
if (error.type != OFONO_ERROR_TYPE_NO_ERROR) {
gcd->active_ctx_cid = CTX_ID_NONE;
}
cb(&error, cb_data);
}
}
static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
@@ -730,14 +518,11 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
const int rs = ofono_netreg_get_status(netreg);
const gchar *protocol_str;
GRilIoRequest* req;
int tech, auth;
/* Let's make sure that we aren't connecting when roaming not allowed */
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
if (!ofono_gprs_get_roaming_allowed(gprs) &&
ril_netreg_check_if_really_roaming(netreg, rs) ==
NETWORK_REGISTRATION_STATUS_ROAMING) {
@@ -750,135 +535,46 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
}
ofono_info("Activating context: %d", ctx->cid);
protocol_str = ril_gprs_ofono_protocol_to_ril(ctx->proto);
GASSERT(protocol_str);
/* ril.h has this to say about the radio tech parameter:
*
* ((const char **)data)[0] Radio technology to use: 0-CDMA,
* 1-GSM/UMTS, 2... for values above 2
* this is RIL_RadioTechnology + 2.
*
* Makes little sense but it is what it is.
*/
tech = gcd->network->data.ril_tech;
if (tech > 2) {
tech += 2;
} else {
/*
* This value used to be hardcoded, let's keep using it
* as the default.
*/
tech = RADIO_TECH_HSPA;
}
/*
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
* android/internal/telephony/dataconnection/DataConnection.java,
* onConnect(), and use authentication or not depending on whether
* the user field is empty or not.
*/
auth = (ctx->username && ctx->username[0]) ?
RIL_AUTH_BOTH : RIL_AUTH_NONE;
/*
* TODO: add comments about tethering, other non-public
* profiles...
*/
req = grilio_request_new();
grilio_request_append_int32(req, SETUP_DATA_CALL_PARAMS);
grilio_request_append_format(req, "%d", tech);
grilio_request_append_utf8(req, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(req, ctx->apn);
grilio_request_append_utf8(req, ctx->username);
grilio_request_append_utf8(req, ctx->password);
grilio_request_append_format(req, "%d", auth);
grilio_request_append_utf8(req, protocol_str);
GASSERT(!gcd->activate.req);
GASSERT(ctx->cid != CTX_ID_NONE);
gcd->active_ctx_cid = ctx->cid;
gcd->state = STATE_ACTIVATING;
grilio_queue_send_request_full(gcd->q, req, RIL_REQUEST_SETUP_DATA_CALL,
ril_gprs_context_activate_primary_cb, ril_gprs_context_cbd_free,
ril_gprs_context_cbd_new(gcd, cb, data));
grilio_request_unref(req);
gcd->activate.cb = cb;
gcd->activate.data = data;
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
ril_gprs_context_activate_primary_cb, gcd);
}
static void ril_gprs_context_deactivate_data_call_cb(GRilIoChannel *io, int err,
const void *data, guint len, void *user_data)
static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
int ril_status, void *user_data)
{
struct ril_gprs_context *gcd = user_data;
struct ofono_error error;
struct ril_gprs_context_deactivate_req *req = user_data;
struct ril_gprs_context *gcd = req->cbd.gcd;
ofono_gprs_context_cb_t cb;
gpointer cb_data;
if (!gcd) {
/*
* ril_gprs_context_remove() zeroes gcd pointer for the
* pending ril_gprs_context_deactivate_req. Or we may have
* received RIL_UNSOL_DATA_CALL_LIST_CHANGED event before
* RIL_REQUEST_DEACTIVATE_DATA_CALL completes, in which
* case gcd will also be NULL. In any case, it means that
* there's nothing left for us to do here. Just ignore it.
*/
DBG("late completion, cid: %d err: %d", req->cid, err);
if (ril_status == RIL_E_SUCCESS) {
GASSERT(gcd->active_call);
ril_error_init_ok(&error);
ofono_info("Deactivated data call");
} else {
ofono_gprs_context_cb_t cb = req->cbd.cb;
/* Mark it as done */
if (gcd->deactivate_req == req) {
gcd->deactivate_req = NULL;
}
if (err == RIL_E_SUCCESS) {
GASSERT(gcd->active_call &&
gcd->active_call->cid == req->cid);
ril_gprs_context_set_disconnected(gcd);
ofono_info("Deactivated data call");
if (cb) {
cb(ril_error_ok(&error), req->cbd.data);
}
} else {
ofono_error("Deactivate failure: %s",
ril_error_to_string(err));
if (cb) {
cb(ril_error_failure(&error), req->cbd.data);
}
}
ril_error_init_failure(&error);
ofono_error("Deactivate failure: %s",
ril_error_to_string(ril_status));
}
}
static void ril_gprs_context_deactivate_data_call(struct ril_gprs_context *gcd,
ofono_gprs_context_cb_t cb, void *data)
{
GRilIoRequest *req = grilio_request_new();
cb = gcd->deactivate.cb;
cb_data = gcd->deactivate.data;
GASSERT(gcd->deactivate.req);
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
/* Overlapping deactivate requests make no sense */
GASSERT(!gcd->deactivate_req);
if (gcd->deactivate_req) {
gcd->deactivate_req->cbd.gcd = NULL;
if (cb) {
ril_gprs_context_free_active_call(gcd);
cb(&error, cb_data);
} else {
/* Have to tell ofono that the call has been disconnected */
ril_gprs_context_set_disconnected(gcd);
}
gcd->deactivate_req =
ril_gprs_context_deactivate_req_new(gcd, cb, data);
/* Caller is responsible for checking gcd->active_call */
GASSERT(gcd->active_call);
grilio_request_append_int32(req, DEACTIVATE_DATA_CALL_PARAMS);
grilio_request_append_format(req, "%d", gcd->active_call->cid);
grilio_request_append_format(req, "%d",
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
/*
* Send it to GRilIoChannel so that it doesn't get cancelled
* by ril_gprs_context_remove()
*/
grilio_channel_send_request_full(gcd->io, req,
RIL_REQUEST_DEACTIVATE_DATA_CALL,
ril_gprs_context_deactivate_data_call_cb,
ril_gprs_context_deactivate_req_free,
gcd->deactivate_req);
grilio_request_unref(req);
gcd->state = STATE_DEACTIVATING;
}
static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
@@ -886,13 +582,16 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(cb);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
ofono_info("Deactivate primary");
if (gcd->active_call && gcd->active_ctx_cid == id) {
ril_gprs_context_deactivate_data_call(gcd, cb, data);
} else {
gcd->deactivate.cb = cb;
gcd->deactivate.data = data;
gcd->deactivate.req = ril_data_call_deactivate(gcd->data,
gcd->active_call->cid,
ril_gprs_context_deactivate_primary_cb, gcd);
} else if (cb) {
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
@@ -901,13 +600,8 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int id)
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
DBG("%d", id);
GASSERT(gcd->active_ctx_cid == id);
if (gcd->active_call && !gcd->deactivate_req) {
ril_gprs_context_deactivate_data_call(gcd, NULL, NULL);
}
ril_gprs_context_deactivate_primary(gc, id, NULL, NULL);
}
static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
@@ -920,12 +614,8 @@ static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
gcd->gc = gc;
gcd->modem = modem;
gcd->network = ril_network_ref(modem->network);
gcd->io = grilio_channel_ref(ril_modem_io(modem));
gcd->q = grilio_queue_new(gcd->io);
gcd->regid = grilio_channel_add_unsol_event_handler(gcd->io,
ril_gprs_context_call_list_changed,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, gcd);
ril_gprs_context_set_disconnected(gcd);
gcd->data = ril_data_ref(modem->data);
gcd->active_ctx_cid = CTX_ID_NONE;
ofono_gprs_context_set_data(gc, gcd);
return 0;
}
@@ -937,20 +627,21 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
DBG("");
ofono_gprs_context_set_data(gc, NULL);
if (gcd->active_call && !gcd->deactivate_req) {
ril_gprs_context_deactivate_data_call(gcd, NULL, NULL);
}
if (gcd->deactivate_req) {
gcd->deactivate_req->cbd.gcd = NULL;
ril_data_call_request_cancel(gcd->activate.req);
if (gcd->deactivate.req) {
/* Let it complete but we won't be around to be notified. */
ril_data_call_request_detach(gcd->deactivate.req);
} else if (gcd->active_call) {
ril_data_call_deactivate(gcd->data, gcd->active_call->cid,
NULL, NULL);
}
ril_data_remove_handler(gcd->data, gcd->calls_changed_event_id);
ril_data_unref(gcd->data);
ril_network_unref(gcd->network);
grilio_channel_remove_handler(gcd->io, gcd->regid);
grilio_channel_unref(gcd->io);
grilio_queue_cancel_all(gcd->q, FALSE);
grilio_queue_unref(gcd->q);
ril_gprs_context_data_call_free(gcd->active_call);
ril_data_call_free(gcd->active_call);
ril_mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}

View File

@@ -63,6 +63,9 @@ struct ril_modem_data {
ril_modem_cb_t removed_cb;
void *removed_cb_data;
ril_modem_online_cb_t online_cb;
void *online_cb_data;
struct ril_modem_online_request set_online;
struct ril_modem_online_request set_offline;
};
@@ -127,6 +130,15 @@ void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
md->removed_cb_data = data;
}
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data)
{
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
md->online_cb = cb;
md->online_cb_data = data;
}
static void ril_modem_check_devinfo(struct ril_modem_data *md)
{
/* devinfo driver assumes that IMEI is known */
@@ -208,7 +220,8 @@ static gboolean ril_modem_online_request_timeout(gpointer data)
req->data = NULL;
cb(ril_error_failure(&error), cb_data);
ril_modem_update_online_state(req->md);
return FALSE;
return G_SOURCE_REMOVE;
}
static gboolean ril_modem_online_check(gpointer data)
@@ -251,7 +264,7 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
GASSERT(md->modem.radio == radio);
ril_modem_update_radio_settings(md);
ril_modem_update_online_state(md);
};
}
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
@@ -320,6 +333,10 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
DBG("%s going %sline", ofono_modem_get_path(modem),
online ? "on" : "off");
if (md->online_cb) {
md->online_cb(&md->modem, online, md->online_cb_data);
}
if (online) {
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
req = &md->set_online;
@@ -449,7 +466,6 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io,
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
ril_radio_power_on(modem->radio, RADIO_POWER_TAG(md));
GASSERT(io->connected);
/*

223
ofono/drivers/ril/ril_mtu.c Normal file
View File

@@ -0,0 +1,223 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#include "ril_mtu.h"
#include "ril_log.h"
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct ril_mtu_watch {
int max_mtu;
char *ifname;
void *buf;
int bufsize;
GIOChannel *channel;
guint io_watch;
int fd;
};
static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0) {
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, self->ifname, IFNAMSIZ);
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ||
ifr.ifr_mtu > self->max_mtu) {
DBG("%s mtu %d => %d", self->ifname, ifr.ifr_mtu,
self->max_mtu);
ifr.ifr_mtu = self->max_mtu;
if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
ofono_error("Failed to set MTU");
}
}
close(fd);
}
}
static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
const struct rtattr *rta, int len)
{
int mtu = 0;
const char *ifname = NULL;
while (len > 0 && RTA_OK(rta, len) && (!mtu || !ifname)) {
switch (rta->rta_type) {
case IFLA_IFNAME:
ifname = RTA_DATA(rta);
break;
case IFLA_MTU:
mtu = *((int*)RTA_DATA(rta));
break;
}
rta = RTA_NEXT(rta, len);
}
if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
DBG("%s %d", ifname, mtu);
ril_mtu_watch_limit_mtu(self);
}
}
static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
const struct ifinfomsg *ifi, int len)
{
if (ifi->ifi_flags & IFF_UP) {
const struct rtattr *rta = IFLA_RTA(ifi);
ril_mtu_watch_handle_rtattr(self, rta,
len - ((char*)rta - (char*)ifi));
}
}
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
const struct nlmsghdr *hdr, int len)
{
while (len > 0 && NLMSG_OK(hdr, len)) {
if (hdr->nlmsg_type == RTM_NEWLINK) {
ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
IFLA_PAYLOAD(hdr));
}
hdr = NLMSG_NEXT(hdr, len);
}
}
static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
gpointer data)
{
struct ril_mtu_watch *self = data;
struct sockaddr_nl addr;
socklen_t addrlen = sizeof(addr);
ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
(struct sockaddr *)&addr, &addrlen);
if (result > 0) {
if (!addr.nl_pid) {
ril_mtu_watch_handle_nlmsg(self, self->buf, result);
}
return G_SOURCE_CONTINUE;
} else if (result == 0 || errno == EINTR || errno == EAGAIN) {
return G_SOURCE_CONTINUE;
} else {
DBG("%s error %d", self->ifname, errno);
self->io_watch = 0;
return G_SOURCE_REMOVE;
}
}
static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
{
GASSERT(self->fd < 0);
self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (self->fd >= 0) {
struct sockaddr_nl nl;
memset(&nl, 0, sizeof(nl));
nl.nl_pid = getpid();
nl.nl_family = AF_NETLINK;
nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
RTMGRP_LINK;
if (bind(self->fd, (struct sockaddr*)&nl, sizeof(nl)) >= 0) {
return TRUE;
}
close(self->fd);
self->fd = -1;
}
return FALSE;
}
static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
{
if (self->fd >= 0) {
return TRUE;
} else if (ril_mtu_watch_open_socket(self)) {
GASSERT(!self->channel);
GASSERT(!self->io_watch);
self->channel = g_io_channel_unix_new(self->fd);
if (self->channel) {
g_io_channel_set_encoding(self->channel, NULL, NULL);
g_io_channel_set_buffered(self->channel, FALSE);
self->io_watch = g_io_add_watch(self->channel,
G_IO_IN | G_IO_NVAL | G_IO_HUP,
ril_mtu_watch_event, self);
return TRUE;
}
close(self->fd);
self->fd = -1;
}
return FALSE;
}
static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
{
if (self->io_watch) {
g_source_remove(self->io_watch);
self->io_watch = 0;
}
if (self->channel) {
g_io_channel_shutdown(self->channel, TRUE, NULL);
g_io_channel_unref(self->channel);
self->channel = NULL;
}
if (self->fd >= 0) {
close(self->fd);
self->fd = -1;
}
}
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
{
struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
self->fd = -1;
self->max_mtu = max_mtu;
self->bufsize = 4096;
self->buf = g_malloc(self->bufsize);
return self;
}
void ril_mtu_watch_free(struct ril_mtu_watch *self)
{
if (self) {
ril_mtu_watch_stop(self);
g_free(self->ifname);
g_free(self->buf);
g_free(self);
}
}
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
{
if (self && g_strcmp0(self->ifname, ifname)) {
g_free(self->ifname);
if (ifname) {
self->ifname = g_strdup(ifname);
ril_mtu_watch_limit_mtu(self);
ril_mtu_watch_start(self);
} else {
self->ifname = NULL;
ril_mtu_watch_stop(self);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,33 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#ifndef RIL_MTU_H
#define RIL_MTU_H
#include "ril_types.h"
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
void ril_mtu_watch_free(struct ril_mtu_watch *mw);
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
#endif /* RIL_MTU_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -164,7 +164,13 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GASSERT(!nd->current_operator_id);
/*
* Calling ofono_netreg_status_notify() may result in
* ril_netreg_current_operator() being invoked even if one
* is already pending. Since ofono core doesn't associate
* any context with individual calls, we can safely assume
* that such a call essentially cancels the previous one.
*/
if (nd->current_operator_id) {
g_source_remove(nd->current_operator_id);
}

View File

@@ -51,7 +51,7 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
ril_network_cb_t cb, void *arg);
void ril_network_remove_handler(struct ril_network *net, gulong id);
#endif /* RIL_NETWORK */
#endif /* RIL_NETWORK_H */
/*
* Local Variables:

View File

@@ -15,6 +15,7 @@
#include "ril_plugin.h"
#include "ril_sim_card.h"
#include "ril_sim_info.h"
#include "ril_network.h"
#include "ril_radio.h"
#include "ril_data.h"
@@ -78,10 +79,12 @@ struct ril_plugin_priv {
struct ril_data_manager *data_manager;
GSList *slots;
ril_slot_info_ptr *slots_info;
struct ril_slot *data_slot;
struct ril_slot *voice_slot;
struct ril_slot *data_slot;
struct ril_slot *mms_slot;
char *default_voice_imsi;
char *default_data_imsi;
char *mms_imsi;
GKeyFile *storage;
};
@@ -95,15 +98,17 @@ struct ril_slot {
gint timeout; /* RIL timeout, in milliseconds */
int index;
int sim_flags;
gboolean online;
struct ril_slot_config config;
struct ril_plugin_priv *plugin;
struct ril_sim_dbus *sim_dbus;
struct ril_modem *modem;
struct ril_mce *mce;
struct ofono_sim *sim;
struct ril_radio *radio;
struct ril_network *network;
struct ril_sim_card *sim_card;
struct ril_sim_info *sim_info;
struct ril_sim_info_dbus *sim_info_dbus;
struct ril_data *data;
GRilIoChannel *io;
gulong io_event_id[IO_EVENT_COUNT];
@@ -121,7 +126,6 @@ static void ril_debug_trace_notify(struct ofono_debug_desc *desc);
static void ril_debug_dump_notify(struct ofono_debug_desc *desc);
static void ril_debug_grilio_notify(struct ofono_debug_desc *desc);
static void ril_plugin_retry_init_io(struct ril_slot *slot);
static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin);
GLOG_MODULE_DEFINE("rilmodem");
@@ -181,6 +185,7 @@ static void ril_plugin_shutdown_slot(struct ril_slot *slot, gboolean kill_io)
ofono_sim_remove_state_watch(slot->sim,
slot->sim_state_watch_id);
}
ril_sim_info_set_ofono_sim(slot->sim_info, NULL);
slot->sim = NULL;
}
@@ -321,6 +326,9 @@ static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
{
int mask = 0;
struct ril_slot *slot = NULL;
struct ril_slot *mms_slot = NULL;
struct ril_slot *old_data_slot = NULL;
struct ril_slot *new_data_slot = NULL;
/* Voice */
if (plugin->default_voice_imsi) {
@@ -373,23 +381,61 @@ static int ril_plugin_update_modem_paths(struct ril_plugin_priv *plugin)
slot = ril_plugin_find_slot_imsi(plugin->slots, NULL);
}
if (slot && !slot->online) {
slot = NULL;
}
if (plugin->mms_imsi) {
mms_slot = ril_plugin_find_slot_imsi(plugin->slots,
plugin->mms_imsi);
}
if (mms_slot && mms_slot != slot) {
/*
* Reset default data SIM if another SIM is
* temporarily selected for MMS.
*/
slot = NULL;
}
/* Are we actually switching data SIMs? */
old_data_slot = plugin->mms_slot ? plugin->mms_slot : plugin->data_slot;
new_data_slot = mms_slot ? mms_slot : slot;
if (plugin->data_slot != slot) {
mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
if (plugin->data_slot) {
/* Data no longer required for this slot */
ril_data_allow(plugin->data_slot->data, FALSE);
}
plugin->data_slot = slot;
if (slot) {
DBG("Default data SIM at %s", slot->path);
plugin->pub.default_data_path = slot->path;
ril_data_allow(slot->data, TRUE);
} else {
DBG("No default data SIM");
plugin->pub.default_data_path = NULL;
}
}
if (plugin->mms_slot != mms_slot) {
mask |= RIL_PLUGIN_SIGNAL_MMS_PATH;
plugin->mms_slot = mms_slot;
if (mms_slot) {
DBG("MMS data SIM at %s", mms_slot->path);
plugin->pub.mms_path = mms_slot->path;
} else {
DBG("No MMS data SIM");
plugin->pub.mms_path = NULL;
}
}
if (old_data_slot != new_data_slot) {
/* Yes we are switching data SIMs */
if (old_data_slot) {
ril_data_allow(old_data_slot->data, FALSE);
}
if (new_data_slot) {
ril_data_allow(new_data_slot->data, TRUE);
}
}
return mask;
}
@@ -400,22 +446,6 @@ static void ril_plugin_update_modem_paths_full(struct ril_plugin_priv *plugin)
ril_plugin_update_modem_paths(plugin));
}
static void ril_plugin_check_sim_state(struct ril_slot *slot)
{
const char *slot_imsi = ofono_sim_get_imsi(slot->sim);
const char *dbus_imsi = ril_sim_dbus_imsi(slot->sim_dbus);
if (!slot_imsi) {
if (slot->sim_dbus) {
ril_sim_dbus_free(slot->sim_dbus);
slot->sim_dbus = NULL;
}
} else if (g_strcmp0(slot_imsi, dbus_imsi)) {
ril_sim_dbus_free(slot->sim_dbus);
slot->sim_dbus = ril_sim_dbus_new(slot->modem);
}
}
static void ril_plugin_sim_state_changed(struct ril_sim_card *card, void *data)
{
struct ril_slot *slot = data;
@@ -455,11 +485,42 @@ static void ril_plugin_sim_state_watch(enum ofono_sim_state new_state,
void *data)
{
struct ril_slot *slot = data;
struct ril_plugin_priv *plugin = slot->plugin;
DBG("%s sim state %d", slot->path + 1, new_state);
slot->sim_state = new_state;
ril_plugin_check_sim_state(slot);
ril_plugin_update_modem_paths_full(slot->plugin);
if (new_state == OFONO_SIM_STATE_READY) {
struct ril_slot *voice_slot = plugin->voice_slot;
struct ril_slot *data_slot = plugin->data_slot;
int signal_mask;
/*
* OFONO_SIM_STATE_READY means that pin code has been
* entered (if necessary) and IMSI has been obtained.
*
* We want the first slot to be selected by default.
* However, things may become available in pretty much
* any order, so reset the slot pointers to NULL and let
* ril_plugin_update_modem_paths() to pick them again.
*
* Only affects the very first boot and first boot after
* the default voice SIM has been removed.
*/
plugin->voice_slot = NULL;
plugin->data_slot = NULL;
signal_mask = ril_plugin_update_modem_paths(plugin);
if (voice_slot != plugin->voice_slot) {
DBG("Voice slot changed");
signal_mask |= RIL_PLUGIN_SIGNAL_VOICE_PATH;
}
if (data_slot != plugin->data_slot) {
DBG("Data slot changed");
signal_mask |= RIL_PLUGIN_SIGNAL_DATA_PATH;
}
ril_plugin_dbus_signal(plugin->dbus, signal_mask);
} else {
ril_plugin_update_modem_paths_full(plugin);
}
}
static void ril_plugin_register_sim(struct ril_slot *slot, struct ofono_sim *sim)
@@ -468,11 +529,13 @@ static void ril_plugin_register_sim(struct ril_slot *slot, struct ofono_sim *sim
GASSERT(!slot->sim);
GASSERT(slot->sim_watch_id);
GASSERT(!slot->sim_state_watch_id);
slot->sim = sim;
slot->sim_state = ofono_sim_get_state(sim);
slot->sim_state_watch_id = ofono_sim_add_state_watch(sim,
ril_plugin_sim_state_watch, slot,
ril_plugin_sim_state_watch_done);
ril_sim_info_set_ofono_sim(slot->sim_info, sim);
}
static void ril_plugin_sim_watch(struct ofono_atom *atom,
@@ -485,10 +548,10 @@ static void ril_plugin_sim_watch(struct ofono_atom *atom,
ril_plugin_register_sim(slot, __ofono_atom_get_data(atom));
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
DBG("%s sim unregistered", slot->path + 1);
ril_sim_info_set_ofono_sim(slot->sim_info, NULL);
slot->sim = NULL;
}
ril_plugin_check_sim_state(slot);
ril_plugin_update_modem_paths_full(slot->plugin);
}
@@ -510,6 +573,19 @@ static void ril_plugin_slot_disconnected(GRilIoChannel *io, void *data)
ril_plugin_handle_error((struct ril_slot *)data);
}
static void ril_plugin_modem_online(struct ril_modem *modem, gboolean online,
void *data)
{
struct ril_slot *slot = data;
DBG("%s %d", slot->path + 1, online);
GASSERT(slot->modem);
GASSERT(slot->modem == modem);
slot->online = online;
ril_plugin_update_modem_paths_full(slot->plugin);
}
static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
{
struct ril_slot *slot = data;
@@ -518,14 +594,16 @@ static void ril_plugin_modem_removed(struct ril_modem *modem, void *data)
GASSERT(slot->modem);
GASSERT(slot->modem == modem);
if (slot->sim_dbus) {
ril_sim_dbus_free(slot->sim_dbus);
slot->sim_dbus = NULL;
if (slot->sim_info_dbus) {
ril_sim_info_dbus_free(slot->sim_info_dbus);
slot->sim_info_dbus = NULL;
}
slot->modem = NULL;
slot->online = FALSE;
ril_data_allow(slot->data, FALSE);
ril_plugin_update_modem_paths_full(slot->plugin);
ril_sim_info_set_ofono_sim(slot->sim_info, NULL);
}
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
@@ -629,7 +707,11 @@ static void ril_plugin_create_modem(struct ril_slot *slot)
ril_plugin_register_sim(slot, sim);
}
slot->sim_info_dbus = ril_sim_info_dbus_new(slot->modem,
slot->sim_info);
ril_modem_set_removed_cb(modem, ril_plugin_modem_removed, slot);
ril_modem_set_online_cb(modem, ril_plugin_modem_online, slot);
} else {
ril_plugin_shutdown_slot(slot, TRUE);
}
@@ -728,7 +810,8 @@ static void ril_plugin_slot_connected(struct ril_slot *slot)
slot->sim_card, ril_plugin_sim_state_changed, slot);
GASSERT(!slot->data);
slot->data = ril_data_new(slot->plugin->data_manager, slot->io);
slot->data = ril_data_new(slot->plugin->data_manager, slot->radio,
slot->network, slot->io);
if (ril_plugin_multisim(slot->plugin)) {
ril_data_set_name(slot->data, slot->path + 1);
@@ -792,7 +875,8 @@ static gboolean ril_plugin_retry_init_io_cb(gpointer data)
GASSERT(slot->retry_id);
slot->retry_id = 0;
ril_plugin_init_io(slot);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_plugin_retry_init_io(struct ril_slot *slot)
@@ -946,6 +1030,7 @@ static struct ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
static void ril_plugin_delete_slot(struct ril_slot *slot)
{
ril_plugin_shutdown_slot(slot, TRUE);
ril_sim_info_unref(slot->sim_info);
g_free(slot->path);
g_free(slot->imei);
g_free(slot->name);
@@ -1221,6 +1306,39 @@ void ril_plugin_set_default_data_imsi(struct ril_plugin *pub, const char *imsi)
}
}
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *pub, const char *imsi)
{
struct ril_plugin_priv *plugin = ril_plugin_cast(pub);
if (imsi && imsi[0]) {
if (g_strcmp0(plugin->mms_imsi, imsi)) {
if (ril_plugin_find_slot_imsi(plugin->slots, imsi)) {
DBG("MMS sim %s", imsi);
g_free(plugin->mms_imsi);
pub->mms_imsi = plugin->mms_imsi =
g_strdup(imsi);
ril_plugin_dbus_signal(plugin->dbus,
RIL_PLUGIN_SIGNAL_MMS_IMSI |
ril_plugin_update_modem_paths(plugin));
} else {
DBG("IMSI not found: %s", imsi);
return FALSE;
}
}
} else {
if (plugin->mms_imsi) {
DBG("No MMS sim");
g_free(plugin->mms_imsi);
pub->mms_imsi = plugin->mms_imsi = NULL;
ril_plugin_dbus_signal(plugin->dbus,
RIL_PLUGIN_SIGNAL_MMS_IMSI |
ril_plugin_update_modem_paths(plugin));
}
}
return TRUE;
}
static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
{
int i;
@@ -1237,6 +1355,7 @@ static void ril_plugin_init_slots(struct ril_plugin_priv *plugin)
slot->plugin = plugin;
slot->pub.path = slot->path;
slot->pub.config = &slot->config;
slot->sim_info = ril_sim_info_new(NULL);
}
*info = NULL;
@@ -1397,6 +1516,7 @@ static void ril_plugin_exit(void)
g_free(ril_plugin->slots_info);
g_free(ril_plugin->default_voice_imsi);
g_free(ril_plugin->default_data_imsi);
g_free(ril_plugin->mms_imsi);
g_free(ril_plugin);
ril_plugin = NULL;
}

View File

@@ -60,6 +60,8 @@ struct ril_slot_info {
};
struct ril_plugin {
const char *mms_imsi;
const char *mms_path;
const char *default_voice_imsi;
const char *default_data_imsi;
const char *default_voice_path;
@@ -81,12 +83,17 @@ struct ril_modem {
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x10)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x20)
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
void *data);
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
const char *imsi);
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
@@ -96,6 +103,11 @@ struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *modem);
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus);
void ril_sim_dbus_free(struct ril_sim_dbus *dbus);
struct ril_sim_info_dbus;
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info);
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
@@ -115,6 +127,8 @@ struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
void *data);
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
void *data);
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-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
@@ -41,18 +41,21 @@ struct ril_plugin_dbus {
DBusConnection *conn;
gboolean block_imei_req;
GSList *blocked_imei_req;
guint mms_watch;
};
#define RIL_DBUS_PATH "/"
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
#define RIL_DBUS_INTERFACE_VERSION (3)
#define RIL_DBUS_INTERFACE_VERSION (4)
#define RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL "EnabledModemsChanged"
#define RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL "PresentSimsChanged"
#define RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL "DefaultVoiceSimChanged"
#define RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL "DefaultDataSimChanged"
#define RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL "DefaultVoiceModemChanged"
#define RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL "DefaultDataModemChanged"
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
#define RIL_DBUS_IMSI_AUTO "auto"
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
@@ -130,6 +133,12 @@ static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
dbus_message_iter_close_container(it, &array);
}
static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
{
if (!str) str = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
}
static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
{
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
@@ -170,12 +179,12 @@ static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
}
static inline void ril_plugin_dbus_signal_path(struct ril_plugin_dbus *dbus,
const char *name, const char *path)
static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
const char *name, const char *str)
{
if (!path) path = "";
if (!str) str = "";
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
name, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
}
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
@@ -183,29 +192,39 @@ void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
if (dbus) {
if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
dbus->plugin->default_voice_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
ril_plugin_dbus_signal_imsi(dbus,
RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
dbus->plugin->default_data_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
dbus->plugin->mms_imsi);
}
if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
ril_plugin_dbus_signal_path_array(dbus,
RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
ril_plugin_dbus_enabled);
}
if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
ril_plugin_dbus_signal_path(dbus,
RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL,
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
dbus->plugin->default_voice_path);
}
if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
ril_plugin_dbus_signal_path(dbus,
RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL,
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
dbus->plugin->default_data_path);
}
if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
ril_plugin_dbus_signal_string(dbus,
RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
dbus->plugin->mms_path);
}
}
}
@@ -214,7 +233,7 @@ void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
{
dbus_bool_t value = present;
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL,
RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
DBUS_TYPE_INT32, &index,
DBUS_TYPE_BOOLEAN, &value,
DBUS_TYPE_INVALID);
@@ -323,6 +342,14 @@ static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
}
static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
struct ril_plugin_dbus *dbus)
{
ril_plugin_dbus_append_all3(it, dbus);
ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
}
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -344,6 +371,13 @@ static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
ril_plugin_dbus_append_all3);
}
static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
ril_plugin_dbus_append_all4);
}
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -391,6 +425,17 @@ static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
ril_plugin_dbus_append_imei_array);
}
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_plugin_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
const char *imsi)
{
@@ -420,6 +465,14 @@ static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
dbus->plugin->default_voice_imsi);
}
static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
}
static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
const char *path)
{
@@ -449,6 +502,14 @@ static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn
dbus->plugin->default_voice_path);
}
static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_plugin_dbus *dbus = data;
return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
}
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -519,37 +580,111 @@ static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
ril_plugin_set_default_data_imsi);
}
static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
{
struct ril_plugin_dbus *dbus = data;
dbus->mms_watch = 0;
if (dbus->plugin->mms_imsi) {
DBG("MMS client is gone");
ril_plugin_set_mms_imsi(dbus->plugin, NULL);
}
}
static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessageIter iter;
struct ril_plugin_dbus *dbus = data;
GASSERT(conn == dbus->conn);
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
DBusBasicValue value;
const char *imsi;
dbus_message_iter_get_basic(&iter, &value);
imsi = value.str;
/*
* MMS IMSI is not persistent and has to be eventually
* reset by the client or cleaned up if the client
* unexpectedly disappears.
*/
if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
/*
* Clear the previous MMS owner
*/
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
dbus->mms_watch = 0;
}
if (dbus->plugin->mms_imsi &&
dbus->plugin->mms_imsi[0]) {
/*
* This client becomes the owner
*/
DBG("Owner: %s", dbus_message_get_sender(msg));
dbus->mms_watch =
g_dbus_add_disconnect_watch(dbus->conn,
dbus_message_get_sender(msg),
ril_plugin_dbus_mms_disconnect,
dbus, NULL);
}
return ril_plugin_dbus_reply_with_string(msg,
dbus->plugin->mms_path);
} else {
return __ofono_error_not_available(msg);
}
} else {
return __ofono_error_invalid_args(msg);
}
}
/*
* The client can call GetInterfaceVersion followed by the appropriate
* GetAllx call to get all settings in two steps. Alternatively, it can
* call GetAll followed by GetAllx based on the interface version returned
* by GetAll. In either case, two D-Bus calls are required, unless the
* client is willing to make the assumption about the ofono version it's
* talking to.
*/
#define RIL_DBUS_GET_ALL_ARGS \
{"version", "i" }, \
{"availableModems", "ao" }, \
{"enabledModems", "ao" }, \
{"defaultDataSim", "s" }, \
{"defaultVoiceSim", "s" }, \
{"defaultDataModem", "s" }, \
{"defaultVoiceModem" , "s"}
#define RIL_DBUS_GET_ALL2_ARGS \
RIL_DBUS_GET_ALL_ARGS, \
{"presentSims" , "ab"}
#define RIL_DBUS_GET_ALL3_ARGS \
RIL_DBUS_GET_ALL2_ARGS, \
{"imei" , "as"}
#define RIL_DBUS_GET_ALL4_ARGS \
RIL_DBUS_GET_ALL3_ARGS, \
{"mmsSim", "s" }, \
{"mmsModem" , "s"}
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetAll", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"}),
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
ril_plugin_dbus_get_all) },
{ GDBUS_METHOD("GetAll2", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"},
{"presentSims" , "ab"}),
{ GDBUS_METHOD("GetAll2",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
ril_plugin_dbus_get_all2) },
{ GDBUS_ASYNC_METHOD("GetAll3", NULL,
GDBUS_ARGS({"version", "i" },
{"availableModems", "ao" },
{"enabledModems", "ao" },
{"defaultDataSim", "s" },
{"defaultVoiceSim", "s" },
{"defaultDataModem", "s" },
{"defaultVoiceModem" , "s"},
{"presentSims" , "ab"},
{"imei" , "as"}),
{ GDBUS_ASYNC_METHOD("GetAll3",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
ril_plugin_dbus_get_all3) },
{ GDBUS_ASYNC_METHOD("GetAll4",
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
ril_plugin_dbus_get_all4) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_plugin_dbus_get_interface_version) },
@@ -571,12 +706,18 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("GetDefaultVoiceSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_default_voice_sim) },
{ GDBUS_METHOD("GetMmsSim",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_plugin_dbus_get_mms_sim) },
{ GDBUS_METHOD("GetDefaultDataModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_data_modem) },
{ GDBUS_METHOD("GetDefaultVoiceModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_default_voice_modem) },
{ GDBUS_METHOD("GetMmsModem",
NULL, GDBUS_ARGS({ "path", "s" }),
ril_plugin_dbus_get_mms_modem) },
{ GDBUS_METHOD("SetEnabledModems",
GDBUS_ARGS({ "modems", "ao" }), NULL,
ril_plugin_dbus_set_enabled_modems) },
@@ -586,22 +727,29 @@ static const GDBusMethodTable ril_plugin_dbus_methods[] = {
{ GDBUS_METHOD("SetDefaultVoiceSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_default_voice_sim) },
{ GDBUS_METHOD("SetMmsSim",
GDBUS_ARGS({ "imsi", "s" }), NULL,
ril_plugin_dbus_set_mms_sim) },
{ }
};
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_DBUS_ENABLED_MODEMS_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
GDBUS_ARGS({ "modems", "ao" })) },
{ GDBUS_SIGNAL(RIL_DBUS_PRESENT_SIMS_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
GDBUS_ARGS({"index", "i" },
{"present" , "b"})) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_DATA_SIM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_VOICE_SIM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_DATA_MODEM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_DEFAULT_VOICE_MODEM_CHANGED_SIGNAL,
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
GDBUS_ARGS({ "path", "s" })) },
{ }
};
@@ -626,6 +774,10 @@ struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
{
if (dbus) {
if (dbus->mms_watch) {
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
}
g_slist_free_full(dbus->blocked_imei_req,
ril_plugin_dbus_cancel_request);
g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,

View File

@@ -89,7 +89,8 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_radio_cancel_retry(struct ril_radio *self)
@@ -228,12 +229,15 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
{
if (G_LIKELY(self)) {
struct ril_radio_priv *priv = self->priv;
const gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on) {
ril_radio_power_request(self, TRUE, FALSE);
if (!g_hash_table_contains(priv->req_table, tag)) {
gboolean was_on = ril_radio_power_should_be_on(self);
DBG("%s%p", priv->log_prefix, tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on) {
ril_radio_power_request(self, TRUE, FALSE);
}
}
}
}
@@ -243,11 +247,12 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
if (G_LIKELY(self)) {
struct ril_radio_priv *priv = self->priv;
DBG("%s%p", priv->log_prefix, tag);
if (g_hash_table_remove(priv->req_table, tag) &&
!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
if (g_hash_table_remove(priv->req_table, tag)) {
DBG("%s%p", priv->log_prefix, tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
}
}
}
}

View File

@@ -39,7 +39,7 @@ gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
#endif /* RIL_RADIO */
#endif /* RIL_RADIO_H */
/*
* Local Variables:

View File

@@ -141,6 +141,7 @@ static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
static struct ril_sim_pin_cbd *ril_sim_pin_cbd_new(struct ril_sim *sd,
enum ofono_sim_password_type passwd_type,
gboolean state_change_expected,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim_pin_cbd *cbd = g_new0(struct ril_sim_pin_cbd, 1);
@@ -150,8 +151,11 @@ static struct ril_sim_pin_cbd *ril_sim_pin_cbd_new(struct ril_sim *sd,
cbd->data = data;
cbd->passwd_type = passwd_type;
cbd->card = ril_sim_card_ref(sd->card);
cbd->card_status_id = ril_sim_card_add_status_received_handler(sd->card,
if (state_change_expected) {
cbd->card_status_id =
ril_sim_card_add_status_received_handler(sd->card,
ril_sim_pin_cbd_state_event_count_cb, cbd);
}
return cbd;
}
@@ -752,7 +756,8 @@ static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
GASSERT(sd->query_passwd_state_cb);
sd->query_passwd_state_timeout_id = 0;
ril_sim_finish_passwd_state_query(sd, OFONO_SIM_PASSWORD_INVALID);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_sim_query_passwd_state(struct ofono_sim *sim,
@@ -795,7 +800,8 @@ static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd);
cbd->cb(ril_error_failure(&error), cbd->data);
ril_sim_pin_cbd_free(cbd);
return FALSE;
return G_SOURCE_REMOVE;
}
static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
@@ -841,7 +847,8 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
ril_status, cbd->passwd_type, retry_count);
cbd->ril_status = ril_status;
if (!cbd->state_event_count || ril_sim_app_in_transient_state(sd)) {
if (cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) {
GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
GASSERT(!cbd->timeout_id);
@@ -862,7 +869,7 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
} else {
struct ofono_error error;
/* Looks like the state has already changed */
/* It's either already changed or not expected at all */
if (ril_status == RIL_E_SUCCESS) {
cbd->cb(ril_error_ok(&error), cbd->data);
} else {
@@ -884,7 +891,8 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
DBG("%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN, cb, data));
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN,
TRUE, cb, data));
grilio_request_unref(req);
}
@@ -917,7 +925,7 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
if (req) {
id = grilio_queue_send_request_full(sd->q, req, code,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
grilio_request_unref(req);
}
@@ -979,7 +987,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SET_FACILITY_LOCK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, TRUE, cb, data));
grilio_request_unref(req);
}
@@ -1003,7 +1011,8 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
DBG("puk=%s,pin=%s,aid=%s", puk, passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PUK,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK, cb, data));
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK,
TRUE, cb, data));
grilio_request_unref(req);
}
@@ -1025,7 +1034,8 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
(passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2) ?
RIL_REQUEST_CHANGE_SIM_PIN2 : RIL_REQUEST_CHANGE_SIM_PIN,
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
ril_sim_pin_cbd_new(sd, passwd_type, cb, data));
ril_sim_pin_cbd_new(sd, passwd_type, FALSE, cb, data));
grilio_request_unref(req);
}
static gboolean ril_sim_register(gpointer user)

View File

@@ -66,7 +66,7 @@ gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
/* Inline wrappers */
G_INLINE_FUNC enum ril_app_type
static inline enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }

View File

@@ -1,242 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#include "ril_plugin.h"
#include "ril_log.h"
#include <ofono/dbus.h>
#include <gdbus.h>
#include "ofono.h"
#include "storage.h"
struct ril_sim_dbus {
char *path;
char *imsi;
char *name;
char *default_name;
gboolean enable_4g;
GKeyFile *storage;
DBusConnection *conn;
struct ril_modem *md;
};
#define RIL_SIM_STORE "ril"
#define RIL_SIM_STORE_GROUP "Settings"
#define RIL_SIM_STORE_ENABLE_4G "Enable4G"
#define RIL_SIM_STORE_DISPLAY_NAME "DisplayName"
#define RIL_SIM_DBUS_INTERFACE "org.nemomobile.ofono.SimSettings"
#define RIL_SIM_DBUS_INTERFACE_VERSION (1)
#define RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL "DisplayNameChanged"
#define RIL_SIM_DBUS_ENABLE_4G_CHANGED_SIGNAL "Enable4GChanged"
static DBusMessage *ril_sim_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_DBUS_INTERFACE_VERSION;
dbus_bool_t enable_4g = dbus->enable_4g;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
return reply;
}
static DBusMessage *ril_sim_dbus_get_interface_version(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
return reply;
}
static DBusMessage *ril_sim_dbus_get_enable_4g(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_bool_t enable_4g = dbus->enable_4g;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &enable_4g);
return reply;
}
static DBusMessage *ril_sim_dbus_get_display_name(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus->name);
return reply;
}
static void ril_sim_dbus_update_display_name(struct ril_sim_dbus *dbus,
const char *name)
{
if (g_strcmp0(dbus->name, name)) {
g_free(dbus->name);
dbus->name = g_strdup(name);
g_key_file_set_string(dbus->storage, RIL_SIM_STORE_GROUP,
RIL_SIM_STORE_DISPLAY_NAME, name);
storage_sync(dbus->imsi, RIL_SIM_STORE, dbus->storage);
g_dbus_emit_signal(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE,
RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
}
}
static DBusMessage *ril_sim_dbus_set_display_name(DBusConnection *conn,
DBusMessage *msg, void *data)
{
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
struct ril_sim_dbus *dbus = data;
DBusBasicValue value;
const char *name;
dbus_message_iter_get_basic(&iter, &value);
name = value.str;
if (!name || !name[0]) name = dbus->default_name;
ril_sim_dbus_update_display_name(dbus, name);
return dbus_message_new_method_return(msg);
} else {
return __ofono_error_invalid_args(msg);
}
}
static const GDBusMethodTable ril_sim_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS({ "settings", "ibs" }),
ril_sim_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_sim_dbus_get_interface_version) },
{ GDBUS_METHOD("GetEnable4G",
NULL, GDBUS_ARGS({ "enable", "b" }),
ril_sim_dbus_get_enable_4g) },
{ GDBUS_METHOD("GetDisplayName",
NULL, GDBUS_ARGS({ "name", "s" }),
ril_sim_dbus_get_display_name) },
{ GDBUS_METHOD("SetDisplayName",
GDBUS_ARGS({ "name", "s" }), NULL,
ril_sim_dbus_set_display_name) },
{ }
};
static const GDBusSignalTable ril_sim_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_SIM_DBUS_DISPLAY_NAME_CHANGED_SIGNAL,
GDBUS_ARGS({ "name", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_DBUS_ENABLE_4G_CHANGED_SIGNAL,
GDBUS_ARGS({ "enabled", "b" })) },
{ }
};
const char *ril_sim_dbus_imsi(struct ril_sim_dbus *dbus)
{
return dbus ? dbus->imsi : NULL;
}
struct ril_sim_dbus *ril_sim_dbus_new(struct ril_modem *md)
{
const char *imsi = ofono_sim_get_imsi(ril_modem_ofono_sim(md));
if (imsi) {
GError *error = NULL;
const struct ril_slot_config *config = &md->config;
struct ril_sim_dbus *dbus = g_new0(struct ril_sim_dbus, 1);
DBG("%s", ril_modem_get_path(md));
dbus->md = md;
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->imsi = g_strdup(imsi);
dbus->default_name = g_strdup(config->default_name);
/* Load settings */
dbus->storage = storage_open(imsi, RIL_SIM_STORE);
dbus->enable_4g = g_key_file_get_boolean(dbus->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_ENABLE_4G, &error);
if (error) {
dbus->enable_4g = config->enable_4g;
g_error_free(error);
error = NULL;
}
dbus->name = g_key_file_get_string(dbus->storage,
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_DISPLAY_NAME, NULL);
if (!dbus->name) {
dbus->name = g_strdup(config->default_name);
GASSERT(dbus->name);
}
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE, ril_sim_dbus_methods,
ril_sim_dbus_signals, NULL, dbus, NULL)) {
ofono_modem_add_interface(md->ofono,
RIL_SIM_DBUS_INTERFACE);
return dbus;
} else {
ofono_error("RIL D-Bus register failed");
ril_sim_dbus_free(dbus);
}
}
return NULL;
}
void ril_sim_dbus_free(struct ril_sim_dbus *dbus)
{
if (dbus) {
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
RIL_SIM_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
g_key_file_free(dbus->storage);
g_free(dbus->path);
g_free(dbus->imsi);
g_free(dbus->name);
g_free(dbus->default_name);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,460 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#include "ril_sim_info.h"
#include "ril_log.h"
#include <ofono/sim.h>
#include "ofono.h"
#include "storage.h"
#define RIL_SIM_INFO_STORE "cache"
#define RIL_SIM_INFO_STORE_GROUP "sim"
#define RIL_SIM_INFO_STORE_SPN "spn"
/* ICCID -> IMSI map */
#define RIL_SIM_ICCID_MAP "iccidmap"
#define RIL_SIM_ICCID_MAP_IMSI "imsi"
typedef GObjectClass RilSimInfoClass;
typedef struct ril_sim_info RilSimInfo;
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim, unsigned int id);
typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
const char *value);
struct ril_sim_info_watch {
ril_sim_info_set_value_cb_t set_value;
ril_sim_info_remove_cb_t remove;
struct ril_sim_info *info;
unsigned int id;
};
struct ril_sim_info_priv {
char *iccid;
char *imsi;
char *spn;
struct ofono_sim *sim;
struct ril_sim_info_watch state_watch;
struct ril_sim_info_watch iccid_watch;
struct ril_sim_info_watch imsi_watch;
struct ril_sim_info_watch spn_watch;
gboolean update_imsi_cache;
gboolean update_iccid_map;
};
enum ril_sim_info_signal {
SIGNAL_ICCID_CHANGED,
SIGNAL_IMSI_CHANGED,
SIGNAL_SPN_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_ICCID_CHANGED_NAME "ril-sim-info-iccid-changed"
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-info-imsi-changed"
#define SIGNAL_SPN_CHANGED_NAME "ril-sim-info-spn-changed"
static guint ril_sim_info_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
#define RIL_SIMINFO_TYPE (ril_sim_info_get_type())
#define RIL_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_SIMINFO_TYPE, RilSimInfo))
#define NEW_SIGNAL(klass,name) \
ril_sim_info_signals[SIGNAL_##name##_CHANGED] = \
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
static void ril_sim_info_signal_emit(struct ril_sim_info *self,
enum ril_sim_info_signal id)
{
g_signal_emit(self, ril_sim_info_signals[id], 0);
}
static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
{
if (watch->id) {
struct ril_sim_info_priv *priv = watch->info->priv;
GASSERT(priv->sim);
if (priv->sim) {
watch->remove(priv->sim, watch->id);
GASSERT(!watch->id);
}
watch->id = 0;
}
if (watch->set_value) {
watch->set_value(watch->info, NULL);
}
}
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim, unsigned int id)
{
ofono_sim_remove_spn_watch(sim, &id);
}
static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
priv->spn && priv->spn[0]) {
const char *store = RIL_SIM_INFO_STORE;
GKeyFile *cache = storage_open(priv->imsi, store);
DBG("Updating " STORAGEDIR "/%s/%s", priv->imsi, store);
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
RIL_SIM_INFO_STORE_SPN, priv->spn);
storage_close(priv->imsi, store, cache, TRUE);
priv->update_imsi_cache = FALSE;
}
}
static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
priv->imsi && priv->imsi[0]) {
const char *store = RIL_SIM_ICCID_MAP;
GKeyFile *map = storage_open(NULL, store);
DBG("Updating " STORAGEDIR "/%s", store);
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
priv->iccid, priv->imsi);
storage_close(NULL, store, map, TRUE);
priv->update_iccid_map = FALSE;
}
}
static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->imsi, imsi)) {
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
priv->update_iccid_map = TRUE;
ril_sim_info_update_iccid_map(self);
ril_sim_info_update_imsi_cache(self);
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
}
}
static void ril_sim_info_set_spn(struct ril_sim_info *self, const char *spn)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->spn, spn)) {
g_free(priv->spn);
self->spn = priv->spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
ril_sim_info_update_imsi_cache(self);
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
}
}
static void ril_sim_info_load_cache(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = self->priv;
if (priv->iccid && priv->iccid[0]) {
GKeyFile *map = storage_open(NULL, RIL_SIM_ICCID_MAP);
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
priv->iccid, NULL);
g_key_file_free(map);
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
if (priv->imsi && priv->imsi[0]) {
/* Need to update ICCID -> IMSI map */
DBG("IMSI changed %s -> %s", priv->imsi, imsi);
priv->update_imsi_cache = TRUE;
}
g_free(priv->imsi);
self->imsi = priv->imsi = imsi;
DBG("imsi[%s] = %s", priv->iccid, imsi);
ril_sim_info_update_iccid_map(self);
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
} else if (imsi) {
g_free(imsi);
} else {
DBG("No imsi for iccid %s", priv->iccid);
}
}
if (priv->imsi && priv->imsi[0]) {
GKeyFile *cache = storage_open(priv->imsi, RIL_SIM_INFO_STORE);
char *spn = g_key_file_get_string(cache,
RIL_SIM_INFO_STORE_GROUP,
RIL_SIM_INFO_STORE_SPN, NULL);
g_key_file_free(cache);
if (spn && spn[0] && g_strcmp0(priv->spn, spn)) {
if (priv->spn && priv->spn[0]) {
/* Need to update the cache file */
DBG("spn changing %s -> %s", priv->spn, spn);
priv->update_imsi_cache = TRUE;
}
g_free(priv->spn);
self->spn = priv->spn = spn;
DBG("spn[%s] = \"%s\"", priv->imsi, spn);
ril_sim_info_update_imsi_cache(self);
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
} else if (spn) {
g_free(spn);
} else {
DBG("No spn for imsi %s", priv->imsi);
}
}
}
static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
{
struct ril_sim_info_priv *priv = self->priv;
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
ril_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
if (iccid) {
ril_sim_info_load_cache(self);
}
}
}
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
{
struct ril_sim_info_watch *watch = data;
DBG("%s", imsi);
ril_sim_info_set_imsi(watch->info, imsi);
}
static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
void *data)
{
struct ril_sim_info_watch *watch = data;
DBG("%s", spn);
ril_sim_info_set_spn(watch->info, spn);
}
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
{
struct ril_sim_info_watch *watch = data;
DBG("%s", iccid);
ril_sim_info_set_iccid(watch->info, iccid);
}
static void ril_sim_info_watch_done(void *data)
{
struct ril_sim_info_watch *watch = data;
GASSERT(watch->id);
watch->id = 0;
}
static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
enum ofono_sim_state state)
{
struct ril_sim_info_priv *priv = self->priv;
struct ril_sim_info_watch *watch;
DBG("%d", state);
switch (state) {
case OFONO_SIM_STATE_READY:
/* SPN */
watch = &priv->spn_watch;
if (!watch->id) {
ofono_sim_add_spn_watch(priv->sim, &watch->id,
ril_sim_info_spn_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(priv->spn_watch.id);
}
/* IMSI */
watch = &priv->imsi_watch;
if (!watch->id) {
watch->id = ofono_sim_add_imsi_watch(priv->sim,
ril_sim_info_imsi_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(watch->id);
}
/* no break */
case OFONO_SIM_STATE_INSERTED:
case OFONO_SIM_STATE_LOCKED_OUT:
/* ICCID */
watch = &priv->iccid_watch;
if (!watch->id) {
watch->id = ofono_sim_add_iccid_watch(priv->sim,
ril_sim_info_iccid_watch_cb, watch,
ril_sim_info_watch_done);
GASSERT(watch->id);
}
break;
case OFONO_SIM_STATE_NOT_PRESENT:
case OFONO_SIM_STATE_RESETTING:
ril_sim_info_watch_remove(&priv->spn_watch);
ril_sim_info_watch_remove(&priv->imsi_watch);
ril_sim_info_watch_remove(&priv->iccid_watch);
break;
}
}
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
void *data)
{
struct ril_sim_info_watch *watch = data;
ril_sim_info_handle_sim_state(watch->info, new_state);
}
struct ril_sim_info *ril_sim_info_new(struct ofono_sim *sim)
{
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
ril_sim_info_set_ofono_sim(self, sim);
return self;
}
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_SIMINFO(self));
return self;
} else {
return NULL;
}
}
void ril_sim_info_unref(struct ril_sim_info *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_SIMINFO(self));
}
}
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self, struct ofono_sim *sim)
{
if (G_LIKELY(self)) {
struct ril_sim_info_priv *priv = self->priv;
if (priv->sim != sim) {
ril_sim_info_watch_remove(&priv->state_watch);
ril_sim_info_watch_remove(&priv->iccid_watch);
ril_sim_info_watch_remove(&priv->imsi_watch);
ril_sim_info_watch_remove(&priv->spn_watch);
priv->update_imsi_cache = FALSE;
priv->update_iccid_map = FALSE;
priv->sim = sim;
if (sim) {
priv->state_watch.id =
ofono_sim_add_state_watch(sim,
ril_sim_info_state_watch_cb,
&priv->state_watch,
ril_sim_info_watch_done);
GASSERT(priv->state_watch.id);
DBG("Attached to sim");
ril_sim_info_handle_sim_state(self,
ofono_sim_get_state(sim));
}
}
}
}
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *self,
ril_sim_info_cb_t cb, void *arg)
{
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
}
void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
static void ril_sim_info_watch_init(struct ril_sim_info *self,
struct ril_sim_info_watch *watch,
ril_sim_info_set_value_cb_t set_value,
ril_sim_info_remove_cb_t remove)
{
watch->info = self;
watch->set_value = set_value;
watch->remove = remove;
}
static void ril_sim_info_init(struct ril_sim_info *self)
{
struct ril_sim_info_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
self->priv = priv;
ril_sim_info_watch_init(self, &priv->state_watch, NULL,
ofono_sim_remove_state_watch);
ril_sim_info_watch_init(self, &priv->iccid_watch, ril_sim_info_set_iccid,
ofono_sim_remove_iccid_watch);
ril_sim_info_watch_init(self, &priv->imsi_watch, ril_sim_info_set_imsi,
ofono_sim_remove_imsi_watch);
ril_sim_info_watch_init(self, &priv->spn_watch, ril_sim_info_set_spn,
ril_sim_info_remove_spn_watch);
}
static void ril_sim_info_dispose(GObject *object)
{
struct ril_sim_info *self = RIL_SIMINFO(object);
ril_sim_info_set_ofono_sim(self, NULL);
G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
}
static void ril_sim_info_class_init(RilSimInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->dispose = ril_sim_info_dispose;
g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
NEW_SIGNAL(klass, ICCID);
NEW_SIGNAL(klass, IMSI);
NEW_SIGNAL(klass, SPN);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,52 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#ifndef RIL_SIM_INFO_H
#define RIL_SIM_INFO_H
#include "ril_types.h"
struct ril_sim_info {
GObject object;
struct ril_sim_info_priv *priv;
const char *iccid;
const char *imsi;
const char *spn;
};
struct ofono_sim;
typedef void (*ril_sim_info_cb_t)(struct ril_sim_info *info, void *arg);
struct ril_sim_info *ril_sim_info_new(struct ofono_sim *sim);
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *info);
void ril_sim_info_unref(struct ril_sim_info *si);
void ril_sim_info_set_ofono_sim(struct ril_sim_info *si, struct ofono_sim *sim);
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *si,
ril_sim_info_cb_t cb, void *arg);
void ril_sim_info_remove_handler(struct ril_sim_info *si, gulong id);
#endif /* RIL_SIM_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,243 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* 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.
*/
#include "ril_plugin.h"
#include "ril_sim_info.h"
#include "ril_log.h"
#include <ofono/dbus.h>
#include <gdbus.h>
#include "ofono.h"
#include "storage.h"
enum sim_info_event_id {
SIM_INFO_EVENT_ICCID,
SIM_INFO_EVENT_IMSI,
SIM_INFO_EVENT_SPN,
SIM_INFO_EVENT_COUNT
};
struct ril_sim_info_dbus {
struct ril_modem *md;
struct ril_sim_info *info;
DBusConnection *conn;
char *path;
gulong handler_id[SIM_INFO_EVENT_COUNT];
};
#define RIL_SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
#define RIL_SIM_INFO_DBUS_INTERFACE_VERSION (1)
#define RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
#define RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
#define RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
static void ril_sim_info_dbus_append_string(DBusMessageIter *it, const char *s)
{
if (!s) s = "";
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &s);
}
static DBusMessage *ril_sim_info_dbus_reply_with_string(DBusMessage *msg,
const char *str)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
ril_sim_info_dbus_append_string(&iter, str);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_all(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
struct ril_sim_info *info = dbus->info;
DBusMessage *reply = dbus_message_new_method_return(msg);
const dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
ril_sim_info_dbus_append_string(&iter, info->iccid);
ril_sim_info_dbus_append_string(&iter, info->imsi);
ril_sim_info_dbus_append_string(&iter, info->spn);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_version(DBusConnection *dc,
DBusMessage *msg, void *data)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
DBusMessageIter iter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
return reply;
}
static DBusMessage *ril_sim_info_dbus_get_iccid(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
}
static DBusMessage *ril_sim_info_dbus_get_imsi(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
}
static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ril_sim_info_dbus *dbus = data;
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
}
static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
{ GDBUS_METHOD("GetAll",
NULL, GDBUS_ARGS({"version", "i" },
{"iccid", "s" },
{"imsi", "s" },
{"spn" , "s"}),
ril_sim_info_dbus_get_all) },
{ GDBUS_METHOD("GetInterfaceVersion",
NULL, GDBUS_ARGS({ "version", "i" }),
ril_sim_info_dbus_get_version) },
{ GDBUS_METHOD("GetCardIdentifier",
NULL, GDBUS_ARGS({ "iccid", "s" }),
ril_sim_info_dbus_get_iccid) },
{ GDBUS_METHOD("GetSubscriberIdentity",
NULL, GDBUS_ARGS({ "imsi", "s" }),
ril_sim_info_dbus_get_imsi) },
{ GDBUS_METHOD("GetServiceProviderName",
NULL, GDBUS_ARGS({ "spn", "s" }),
ril_sim_info_dbus_get_spn) },
{ }
};
static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
GDBUS_ARGS({ "iccid", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
GDBUS_ARGS({ "imsi", "s" })) },
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
GDBUS_ARGS({ "spn", "s" })) },
{ }
};
static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
const char *signal, const char *value)
{
const char *arg = value;
if (!arg) arg = "";
g_dbus_emit_signal(dbus->conn, dbus->path, RIL_SIM_INFO_DBUS_INTERFACE,
signal, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
}
static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
info->iccid);
}
static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
info->imsi);
}
static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
{
struct ril_sim_info_dbus *dbus = arg;
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
info->spn);
}
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
struct ril_sim_info *info)
{
struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
DBG("%s", ril_modem_get_path(md));
dbus->md = md;
dbus->path = g_strdup(ril_modem_get_path(md));
dbus->info = ril_sim_info_ref(info);
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
/* Register D-Bus interface */
if (g_dbus_register_interface(dbus->conn, dbus->path,
RIL_SIM_INFO_DBUS_INTERFACE, ril_sim_info_dbus_methods,
ril_sim_info_dbus_signals, NULL, dbus, NULL)) {
ofono_modem_add_interface(md->ofono,
RIL_SIM_INFO_DBUS_INTERFACE);
dbus->handler_id[SIM_INFO_EVENT_ICCID] =
ril_sim_info_add_iccid_changed_handler(info,
ril_sim_info_dbus_iccid_cb, dbus);
dbus->handler_id[SIM_INFO_EVENT_IMSI] =
ril_sim_info_add_imsi_changed_handler(info,
ril_sim_info_dbus_imsi_cb, dbus);
dbus->handler_id[SIM_INFO_EVENT_SPN] =
ril_sim_info_add_spn_changed_handler(info,
ril_sim_info_dbus_spn_cb, dbus);
return dbus;
} else {
ofono_error("RIL D-Bus register failed");
ril_sim_info_dbus_free(dbus);
return NULL;
}
}
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
{
if (dbus) {
unsigned int i;
DBG("%s", dbus->path);
g_dbus_unregister_interface(dbus->conn, dbus->path,
RIL_SIM_INFO_DBUS_INTERFACE);
ofono_modem_remove_interface(dbus->md->ofono,
RIL_SIM_INFO_DBUS_INTERFACE);
dbus_connection_unref(dbus->conn);
for (i=0; i<G_N_ELEMENTS(dbus->handler_id); i++) {
ril_sim_info_remove_handler(dbus->info,
dbus->handler_id[i]);
}
ril_sim_info_unref(dbus->info);
g_free(dbus->path);
g_free(dbus);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -43,6 +43,7 @@ struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_sim_info;
struct ril_plugin_dbus;
#endif /* RIL_TYPES_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015 Jolla Ltd.
* Copyright (C) 2015-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
@@ -9,7 +9,7 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
@@ -101,11 +101,10 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
}
grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length);
grilio_queue_send_request_full(ud->q, req,
RIL_REQUEST_SEND_USSD, ril_ussd_cb,
ril_ussd_cbd_free,
ril_ussd_cbd_new(cb, data));
grilio_queue_send_request(ud->q, req,
RIL_REQUEST_SEND_USSD);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return;
}
}

View File

@@ -58,14 +58,6 @@ struct netreg_data {
int corestatus; /* Registration status previously reported to core */
};
/* 27.007 Section 7.3 <stat> */
enum operator_status {
OPERATOR_STATUS_UNKNOWN = 0,
OPERATOR_STATUS_AVAILABLE = 1,
OPERATOR_STATUS_CURRENT = 2,
OPERATOR_STATUS_FORBIDDEN = 3,
};
struct ofono_netreg *current_netreg;
static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)

View File

@@ -215,6 +215,22 @@ ofono_bool_t ofono_sim_add_spn_watch(struct ofono_sim *sim, unsigned int *id,
ofono_bool_t ofono_sim_remove_spn_watch(struct ofono_sim *sim, unsigned int *id);
typedef void (*ofono_sim_iccid_event_cb_t)(const char *iccid, void *data);
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy);
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id);
typedef void (*ofono_sim_imsi_event_cb_t)(const char *imsi, void *data);
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
ofono_sim_imsi_event_cb_t cb, void *data,
ofono_destroy_func destroy);
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id);
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted);
struct ofono_sim_context *ofono_sim_context_create(struct ofono_sim *sim);

View File

@@ -57,8 +57,6 @@
#define MAX_MESSAGE_CENTER_LENGTH 255
#define MAX_CONTEXTS 256
#define SUSPEND_TIMEOUT 8
#define MAX_MMS_MTU 1280
#define MAX_GPRS_MTU 1280
struct ofono_gprs {
GSList *contexts;
@@ -790,31 +788,6 @@ static void pri_reset_context_settings(struct pri_context *ctx)
g_free(interface);
}
static void pri_limit_mtu(const char *interface, int max_mtu)
{
struct ifreq ifr;
int sk;
if (interface == NULL)
return;
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
return;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
if (ioctl(sk, SIOCGIFMTU, &ifr) < 0 || ifr.ifr_mtu > max_mtu) {
ifr.ifr_mtu = max_mtu;
if (ioctl(sk, SIOCSIFMTU, &ifr) < 0)
ofono_error("Failed to set MTU");
}
close(sk);
}
static void pri_update_mms_context_settings(struct pri_context *ctx)
{
struct ofono_gprs_context *gc = ctx->context_driver;
@@ -832,8 +805,6 @@ static void pri_update_mms_context_settings(struct pri_context *ctx)
if (ctx->proxy_host)
pri_setproxy(settings->interface, ctx->proxy_host);
pri_limit_mtu(settings->interface, MAX_MMS_MTU);
}
static gboolean pri_str_changed(const char *val, const char *newval)
@@ -844,8 +815,6 @@ static gboolean pri_str_changed(const char *val, const char *newval)
static gboolean pri_str_update(char *val, const char *newval,
const int maxlen)
{
DBG("oldval: %s, newval: %s, mmaxlen: %d", val, newval, maxlen);
if (newval) {
if (strcmp(val, newval)) {
strncpy(val, newval, maxlen);
@@ -1132,9 +1101,6 @@ static void pri_activate_callback(const struct ofono_error *error, void *data)
pri_context_signal_settings(ctx, gc->settings->ipv4 != NULL,
gc->settings->ipv6 != NULL);
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET)
pri_limit_mtu(gc->settings->interface, MAX_GPRS_MTU);
}
value = ctx->active;

View File

@@ -62,6 +62,8 @@ struct ofono_netreg {
struct ofono_network_registration_ops *ops;
int flags;
DBusMessage *pending;
GSList *pending_auto;
GSList *pending_list;
int signal_strength;
struct sim_spdi *spdi;
struct sim_eons *eons;
@@ -599,7 +601,7 @@ static DBusMessage *network_operator_register(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_auto || netreg->pending_list)
return __ofono_error_busy(msg);
if (netreg->driver->register_manual == NULL)
@@ -854,6 +856,44 @@ static DBusMessage *network_get_properties(DBusConnection *conn,
return reply;
}
static void network_reply_ok(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, dbus_message_new_method_return(msg));
}
static void network_reply_failed(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_failed(msg));
}
static void network_reply_canceled(gpointer data)
{
DBusMessage *msg = data;
__ofono_dbus_pending_reply(&msg, __ofono_error_canceled(msg));
}
static void register_auto_callback(const struct ofono_error *error, void *data)
{
struct ofono_netreg *netreg = data;
if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
g_slist_free_full(netreg->pending_auto, network_reply_ok);
else
g_slist_free_full(netreg->pending_auto, network_reply_failed);
netreg->pending_auto = NULL;
if (netreg->driver->registration_status)
netreg->driver->registration_status(netreg,
registration_status_callback,
netreg);
}
static DBusMessage *network_register(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -862,17 +902,19 @@ static DBusMessage *network_register(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_list)
return __ofono_error_busy(msg);
if (netreg->driver->register_auto == NULL)
return __ofono_error_not_implemented(msg);
netreg->pending = dbus_message_ref(msg);
netreg->driver->register_auto(netreg, register_callback, netreg);
set_registration_mode(netreg, NETWORK_REGISTRATION_MODE_AUTO);
netreg->pending_auto = g_slist_append(netreg->pending_auto,
dbus_message_ref(msg));
if (!netreg->pending_auto->next) {
netreg->driver->register_auto(netreg, register_auto_callback,
netreg);
set_registration_mode(netreg, NETWORK_REGISTRATION_MODE_AUTO);
}
return NULL;
}
@@ -972,26 +1014,15 @@ static void network_signal_operators_changed(struct ofono_netreg *netreg)
g_dbus_send_message(conn, signal);
}
static void operator_list_callback(const struct ofono_error *error, int total,
const struct ofono_network_operator *list,
void *data)
static void operator_list_reply(gpointer data, gpointer user_data)
{
struct ofono_netreg *netreg = data;
struct ofono_netreg *netreg = user_data;
DBusMessage *msg = data;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter array;
gboolean changed;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error occurred during operator list");
__ofono_dbus_pending_reply(&netreg->pending,
__ofono_error_failed(netreg->pending));
return;
}
changed = update_operator_list(netreg, total, list);
reply = dbus_message_new_method_return(netreg->pending);
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &iter);
@@ -1008,12 +1039,31 @@ static void operator_list_callback(const struct ofono_error *error, int total,
append_operator_struct_list(netreg, &array);
dbus_message_iter_close_container(&iter, &array);
__ofono_dbus_pending_reply(&netreg->pending, reply);
__ofono_dbus_pending_reply(&msg, reply);
}
DBG("operator list %schanged", changed ? "" : "not ");
static void operator_list_callback(const struct ofono_error *error, int total,
const struct ofono_network_operator *list,
void *data)
{
struct ofono_netreg *netreg = data;
if (changed)
network_signal_operators_changed(netreg);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error occurred during operator list");
g_slist_free_full(netreg->pending_list, network_reply_failed);
} else {
gboolean changed = update_operator_list(netreg, total, list);
g_slist_foreach(netreg->pending_list, operator_list_reply,
netreg);
g_slist_free(netreg->pending_list);
DBG("operator list %schanged", changed ? "" : "not ");
if (changed)
network_signal_operators_changed(netreg);
}
netreg->pending_list = NULL;
}
static DBusMessage *network_scan(DBusConnection *conn,
@@ -1024,16 +1074,17 @@ static DBusMessage *network_scan(DBusConnection *conn,
if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
return __ofono_error_access_denied(msg);
if (netreg->pending)
if (netreg->pending || netreg->pending_auto)
return __ofono_error_busy(msg);
if (netreg->driver->list_operators == NULL)
return __ofono_error_not_implemented(msg);
netreg->pending = dbus_message_ref(msg);
netreg->driver->list_operators(netreg, operator_list_callback, netreg);
netreg->pending_list = g_slist_append(netreg->pending_list,
dbus_message_ref(msg));
if (!netreg->pending_list->next)
netreg->driver->list_operators(netreg, operator_list_callback,
netreg);
return NULL;
}
@@ -1898,6 +1949,15 @@ static void netreg_remove(struct ofono_atom *atom)
if (netreg->driver != NULL && netreg->driver->remove != NULL)
netreg->driver->remove(netreg);
if (netreg->pending) {
__ofono_dbus_pending_reply(&netreg->pending,
__ofono_error_canceled(netreg->pending));
} else if (netreg->pending_auto) {
g_slist_free_full(netreg->pending_auto, network_reply_canceled);
} else if (netreg->pending_list) {
g_slist_free_full(netreg->pending_list, network_reply_canceled);
}
sim_eons_free(netreg->eons);
sim_spdi_free(netreg->spdi);

View File

@@ -53,6 +53,7 @@ struct ofono_sim {
/* Contents of the SIM file system, in rough initialization order */
char *iccid;
struct ofono_watchlist *iccid_watches;
char **language_prefs;
unsigned char *efli;
@@ -80,6 +81,7 @@ struct ofono_sim {
char *imsi;
char mcc[OFONO_MAX_MCC_LENGTH + 1];
char mnc[OFONO_MAX_MNC_LENGTH + 1];
struct ofono_watchlist *imsi_watches;
GSList *own_numbers;
GSList *new_numbers;
@@ -340,6 +342,94 @@ static void call_state_watches(struct ofono_sim *sim)
}
}
static unsigned int add_watch_item(struct ofono_watchlist *watchlist,
void *notify, void *notify_data,
ofono_destroy_func destroy)
{
struct ofono_watchlist_item *item;
item = g_new0(struct ofono_watchlist_item, 1);
item->notify = notify;
item->notify_data = notify_data;
item->destroy = destroy;
return __ofono_watchlist_add_item(watchlist, item);
}
static void iccid_watch_cb(gpointer data, gpointer user_data)
{
struct ofono_watchlist_item *item = data;
struct ofono_sim *sim = user_data;
ofono_sim_iccid_event_cb_t cb = item->notify;
cb(sim->iccid, item->notify_data);
}
static inline void iccid_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->iccid_watches->items, iccid_watch_cb, sim);
}
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
unsigned int watch_id;
DBG("%p", sim);
if (sim == NULL)
return 0;
watch_id = add_watch_item(sim->iccid_watches, cb, data, destroy);
if (sim->iccid)
cb(sim->iccid, data);
return watch_id;
}
void ofono_sim_remove_iccid_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->iccid_watches, id);
}
static void imsi_watch_cb(gpointer data, gpointer user_data)
{
struct ofono_watchlist_item *item = data;
struct ofono_sim *sim = user_data;
ofono_sim_imsi_event_cb_t cb = item->notify;
cb(sim->imsi, item->notify_data);
}
static inline void imsi_watches_notify(struct ofono_sim *sim)
{
g_slist_foreach(sim->imsi_watches->items, imsi_watch_cb, sim);
}
unsigned int ofono_sim_add_imsi_watch(struct ofono_sim *sim,
ofono_sim_imsi_event_cb_t cb, void *data,
ofono_destroy_func destroy)
{
unsigned int watch_id;
DBG("%p", sim);
if (sim == NULL)
return 0;
watch_id = add_watch_item(sim->imsi_watches, cb, data, destroy);
if (sim->imsi)
cb(sim->imsi, data);
return watch_id;
}
void ofono_sim_remove_imsi_watch(struct ofono_sim *sim, unsigned int id)
{
__ofono_watchlist_remove_item(sim->imsi_watches, id);
}
static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -380,6 +470,10 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
ofono_dbus_dict_append(&dict, "SubscriberIdentity",
DBUS_TYPE_STRING, &sim->imsi);
if (sim->spn)
ofono_dbus_dict_append(&dict, "ServiceProviderName",
DBUS_TYPE_STRING, &sim->spn);
fdn = sim->fixed_dialing;
ofono_dbus_dict_append(&dict, "FixedDialing", DBUS_TYPE_BOOLEAN, &fdn);
@@ -1483,6 +1577,7 @@ static void sim_imsi_obtained(struct ofono_sim *sim, const char *imsi)
DBUS_TYPE_STRING, &str);
}
imsi_watches_notify(sim);
sim_set_ready(sim);
}
@@ -1856,6 +1951,7 @@ static void sim_initialize_after_pin(struct ofono_sim *sim)
{
sim->context = ofono_sim_context_create(sim);
sim->spn_watches = __ofono_watchlist_new(g_free);
sim->imsi_watches = __ofono_watchlist_new(g_free);
ofono_sim_read(sim->context, SIM_EFPHASE_FILEID,
OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
@@ -2085,6 +2181,7 @@ static void sim_iccid_read_cb(int ok, int length, int record,
"CardIdentifier",
DBUS_TYPE_STRING,
&sim->iccid);
iccid_watches_notify(sim);
}
static void sim_iccid_changed(int id, void *userdata)
@@ -2467,6 +2564,11 @@ static void sim_free_main_state(struct ofono_sim *sim)
sim_spn_close(sim);
if (sim->imsi_watches) {
__ofono_watchlist_free(sim->imsi_watches);
sim->imsi_watches = NULL;
}
if (sim->context) {
ofono_sim_context_free(sim->context);
sim->context = NULL;
@@ -2570,6 +2672,9 @@ static inline void spn_watches_notify(struct ofono_sim *sim)
static void sim_spn_set(struct ofono_sim *sim, const void *data, int length,
const unsigned char *dc)
{
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
g_free(sim->spn);
sim->spn = NULL;
@@ -2611,6 +2716,12 @@ static void sim_spn_set(struct ofono_sim *sim, const void *data, int length,
sim->spn_dc = g_memdup(dc, 1);
notify:
if (sim->spn)
ofono_dbus_signal_property_changed(conn, path,
OFONO_SIM_MANAGER_INTERFACE,
"ServiceProviderName",
DBUS_TYPE_STRING, &sim->spn);
spn_watches_notify(sim);
}
@@ -2885,6 +2996,9 @@ static void sim_unregister(struct ofono_atom *atom)
__ofono_modem_remove_atom_watch(modem, sim->hfp_watch);
__ofono_watchlist_free(sim->iccid_watches);
sim->iccid_watches = NULL;
__ofono_watchlist_free(sim->state_watches);
sim->state_watches = NULL;
@@ -3017,6 +3131,7 @@ void ofono_sim_register(struct ofono_sim *sim)
ofono_modem_add_interface(modem, OFONO_SIM_MANAGER_INTERFACE);
sim->state_watches = __ofono_watchlist_new(g_free);
sim->iccid_watches = __ofono_watchlist_new(g_free);
sim->simfs = sim_fs_new(sim, sim->driver);
__ofono_atom_register(sim->atom, sim_unregister);

View File

@@ -41,6 +41,9 @@ unsigned int __ofono_watchlist_add_item(struct ofono_watchlist *watchlist,
{
item->id = ++watchlist->next_id;
if (item->id == 0)
item->id = ++watchlist->next_id;
watchlist->items = g_slist_prepend(watchlist->items, item);
return item->id;