mirror of
https://github.com/sailfishos/ofono
synced 2025-11-23 19:09:44 +08:00
Compare commits
158 Commits
mer/1.22+g
...
mer/1.23+g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef5ee98508 | ||
|
|
4220e7d5e8 | ||
|
|
33c067a75f | ||
|
|
29616c04d0 | ||
|
|
beb997d914 | ||
|
|
cefc03e5ed | ||
|
|
85d99536ee | ||
|
|
ea36baa4c1 | ||
|
|
b95a089c00 | ||
|
|
c8dbf5494b | ||
|
|
cfb75f473d | ||
|
|
edd91c94eb | ||
|
|
af0ab142e1 | ||
|
|
dffc04d404 | ||
|
|
97b5fcbd87 | ||
|
|
d7e740347f | ||
|
|
1116ca2481 | ||
|
|
3d147843c4 | ||
|
|
c01dc63cbc | ||
|
|
297926ed24 | ||
|
|
6ef1174ea8 | ||
|
|
4ad02792db | ||
|
|
eddcb88af4 | ||
|
|
f91df7f0fd | ||
|
|
9d220ff9be | ||
|
|
deefa2c454 | ||
|
|
80224b283d | ||
|
|
07e07b6ddc | ||
|
|
bd836b4499 | ||
|
|
6c289b1432 | ||
|
|
296e46487f | ||
|
|
09e98234aa | ||
|
|
0f4cdba932 | ||
|
|
870bac93e9 | ||
|
|
246cd4e1d2 | ||
|
|
ca20b65098 | ||
|
|
8e35a047da | ||
|
|
2b4b5a224d | ||
|
|
50a5f2547e | ||
|
|
d682fcd5fe | ||
|
|
5799320480 | ||
|
|
3eea7c868e | ||
|
|
4844fc6cf9 | ||
|
|
6976366051 | ||
|
|
d3d776837b | ||
|
|
f56c8a33b0 | ||
|
|
ed2f625b8b | ||
|
|
ed62d38632 | ||
|
|
3f433c97c5 | ||
|
|
86d8149c79 | ||
|
|
f3eb9b868b | ||
|
|
4e067fa827 | ||
|
|
2ee5e4c827 | ||
|
|
1366e426be | ||
|
|
586c9b9262 | ||
|
|
83554e071a | ||
|
|
dc41c2d003 | ||
|
|
550d41ae37 | ||
|
|
60e4246d93 | ||
|
|
50619607b0 | ||
|
|
98b357f365 | ||
|
|
56c488d10c | ||
|
|
944cd603e8 | ||
|
|
77be0d5e98 | ||
|
|
d8dd20092c | ||
|
|
c7faa21172 | ||
|
|
98ffc61a03 | ||
|
|
f2b1625872 | ||
|
|
2d5a22284e | ||
|
|
9d742180ab | ||
|
|
f8b0ccc1b4 | ||
|
|
7a54bb8cbe | ||
|
|
56e0923dc3 | ||
|
|
6dfce4b5e9 | ||
|
|
4ec3568d71 | ||
|
|
9b2b7127ef | ||
|
|
1053577376 | ||
|
|
22197b5e04 | ||
|
|
3a358ddc9d | ||
|
|
53929f9f1a | ||
|
|
08bae57a2b | ||
|
|
1915aeda76 | ||
|
|
51bfb17cbc | ||
|
|
a83b553032 | ||
|
|
ec00abd62d | ||
|
|
80924d5787 | ||
|
|
2bdd05aa31 | ||
|
|
544f02e5a2 | ||
|
|
6d4638f9bf | ||
|
|
6584919e9d | ||
|
|
34fb44f4eb | ||
|
|
c98d2f41c5 | ||
|
|
b279be4528 | ||
|
|
a7912fea39 | ||
|
|
f291cea905 | ||
|
|
68f7d30b77 | ||
|
|
890a2697fe | ||
|
|
9568c8449b | ||
|
|
cf91be9742 | ||
|
|
087771dc0f | ||
|
|
645dfe47e5 | ||
|
|
68e8b02d3b | ||
|
|
aa4309e8cb | ||
|
|
cb6b24d950 | ||
|
|
6d1ab13c74 | ||
|
|
45424a3f96 | ||
|
|
4f7398e39d | ||
|
|
cd118ce70b | ||
|
|
99d4ce538e | ||
|
|
9b2c4bcf76 | ||
|
|
0122db04a3 | ||
|
|
021db194cb | ||
|
|
e0a0896205 | ||
|
|
49d0bbbb28 | ||
|
|
9193d06b77 | ||
|
|
b0cd3e4544 | ||
|
|
29cce6969b | ||
|
|
b87f666e4b | ||
|
|
1c1e4fa28b | ||
|
|
f597119845 | ||
|
|
633888932d | ||
|
|
a37f325d4a | ||
|
|
0afceac554 | ||
|
|
109751bcc0 | ||
|
|
30dfbf8fd7 | ||
|
|
c7aab2e790 | ||
|
|
412a2a0e7f | ||
|
|
f1aeedd113 | ||
|
|
639fce8eca | ||
|
|
9cfd0a195e | ||
|
|
cf2d8488cc | ||
|
|
ab0ac10abd | ||
|
|
b2df7de223 | ||
|
|
b56930a87f | ||
|
|
f65e8dd5af | ||
|
|
f2439243b2 | ||
|
|
93ff644856 | ||
|
|
08f8555d51 | ||
|
|
04b2a9b0f9 | ||
|
|
4d513b68d2 | ||
|
|
36f971dc78 | ||
|
|
8ba2d96cff | ||
|
|
a76f50be67 | ||
|
|
43227086c0 | ||
|
|
e40811fbc6 | ||
|
|
8c543b054a | ||
|
|
53233b4dc8 | ||
|
|
4458fbf844 | ||
|
|
542a086d93 | ||
|
|
1176662a81 | ||
|
|
ae29a08a76 | ||
|
|
af1a569430 | ||
|
|
a75558031b | ||
|
|
139fff2e5d | ||
|
|
12614d377a | ||
|
|
463f4f183e | ||
|
|
0ba7505f1e | ||
|
|
c1156320ac |
3
ofono/.gitignore
vendored
3
ofono/.gitignore
vendored
@@ -45,9 +45,11 @@ unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-dbus-access
|
||||
unit/test-dbus-clients
|
||||
unit/test-dbus-queue
|
||||
unit/test-gprs-filter
|
||||
unit/test-ril_config
|
||||
unit/test-ril_ecclist
|
||||
unit/test-ril_util
|
||||
unit/test-ril_vendor
|
||||
unit/test-ril-transport
|
||||
@@ -61,6 +63,7 @@ unit/test-sailfish_cell_info_dbus
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-sailfish_sim_info_dbus
|
||||
unit/test-config
|
||||
unit/test-watch
|
||||
unit/test-sms-filter
|
||||
unit/test-voicecall-filter
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
ver 1.23:
|
||||
Fix issue with handling SIM AID sessions.
|
||||
Add support for QMI LTE bearer handling.
|
||||
Add support for memory location dialing.
|
||||
|
||||
ver 1.22:
|
||||
Fix issue with GPIO handling and Nokia modems.
|
||||
Fix issue with SIM state callback and AT modems.
|
||||
|
||||
@@ -26,17 +26,12 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
include/sms-filter.h include/gprs-filter.h \
|
||||
include/voicecall-filter.h include/dbus-access.h \
|
||||
include/ril-constants.h include/ril-transport.h \
|
||||
include/watch.h gdbus/gdbus.h \
|
||||
include/watch.h gdbus/gdbus.h include/dbus-clients.h \
|
||||
include/netmon.h include/lte.h include/ims.h \
|
||||
include/storage.h
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
$(nodist_pkginclude_HEADERS), \
|
||||
include/ofono/$(notdir $(file)))
|
||||
@@ -156,8 +151,10 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_devinfo.c \
|
||||
drivers/ril/ril_devmon.c \
|
||||
drivers/ril/ril_devmon_auto.c \
|
||||
drivers/ril/ril_devmon_combine.c \
|
||||
drivers/ril/ril_devmon_ds.c \
|
||||
drivers/ril/ril_devmon_ss.c \
|
||||
drivers/ril/ril_devmon_ur.c \
|
||||
drivers/ril/ril_ecclist.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
@@ -310,6 +307,7 @@ builtin_sources += $(qmi_sources) \
|
||||
drivers/qmimodem/ussd.c \
|
||||
drivers/qmimodem/gprs.c \
|
||||
drivers/qmimodem/gprs-context.c \
|
||||
drivers/qmimodem/lte.c \
|
||||
drivers/qmimodem/radio-settings.c \
|
||||
drivers/qmimodem/location-reporting.c \
|
||||
drivers/qmimodem/netmon.c
|
||||
@@ -777,7 +775,8 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/handsfree-audio.c src/bluetooth.h \
|
||||
src/sim-mnclength.c src/voicecallagent.c \
|
||||
src/sms-filter.c src/gprs-filter.c \
|
||||
src/dbus-queue.c src/dbus-access.c \
|
||||
src/dbus-clients.c src/dbus-queue.c \
|
||||
src/dbus-access.c src/config.c \
|
||||
src/voicecall-filter.c src/ril-transport.c \
|
||||
src/hfp.h src/siri.c src/watchlist.c \
|
||||
src/netmon.c src/lte.c src/ims.c \
|
||||
@@ -808,7 +807,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
|
||||
|
||||
AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
|
||||
-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril
|
||||
-I$(srcdir)/btio -I$(srcdir)/gril \
|
||||
-I$(srcdir)/plugins/sailfish_manager
|
||||
|
||||
doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
|
||||
doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
|
||||
@@ -972,8 +972,7 @@ if SAILFISH_MANAGER
|
||||
|
||||
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-Iplugins/sailfish_manager
|
||||
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
|
||||
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info
|
||||
@@ -983,10 +982,10 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
|
||||
unit/fake_sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
gdbus/object.c src/dbus-clients.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
|
||||
@DBUS_GLIB_CFLAGS@
|
||||
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_cell_info_dbus
|
||||
@@ -996,7 +995,7 @@ unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info
|
||||
@@ -1008,8 +1007,7 @@ unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
|
||||
gdbus/object.c \
|
||||
src/dbus.c src/storage.c src/watchlist.c src/log.c
|
||||
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
|
||||
-Iplugins/sailfish_manager
|
||||
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_sim_info_dbus
|
||||
@@ -1021,7 +1019,7 @@ unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
@@ -1029,13 +1027,20 @@ unit_tests += unit/test-sailfish_manager
|
||||
unit_test_watch_SOURCES = unit/test-watch.c src/watch.c \
|
||||
src/log.c src/watchlist.c
|
||||
unit_test_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
-DSTORAGEDIR='"/tmp/ofono"'
|
||||
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_watch_OBJECTS)
|
||||
unit_tests += unit/test-watch
|
||||
|
||||
endif
|
||||
|
||||
unit_test_config_SOURCES = unit/test-config.c drivers/ril/ril_util.c \
|
||||
src/config.c src/log.c
|
||||
unit_test_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_config_OBJECTS)
|
||||
unit_tests += unit/test-config
|
||||
|
||||
if SAILFISH_ACCESS
|
||||
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
|
||||
plugins/sailfish_access.c src/dbus-access.c src/log.c
|
||||
@@ -1062,6 +1067,13 @@ unit_test_ril_config_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_config_OBJECTS)
|
||||
unit_tests += unit/test-ril_config
|
||||
|
||||
unit_test_ril_ecclist_SOURCES = unit/test-ril_ecclist.c \
|
||||
drivers/ril/ril_ecclist.c src/log.c
|
||||
unit_test_ril_ecclist_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_ecclist_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_ecclist_OBJECTS)
|
||||
unit_tests += unit/test-ril_ecclist
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
@@ -1153,6 +1165,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
|
||||
src/dbus-clients.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_dbus_clients_OBJECTS)
|
||||
unit_tests += unit/test-dbus-clients
|
||||
|
||||
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
|
||||
src/dbus-queue.c gdbus/object.c \
|
||||
src/dbus.c src/log.c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(ofono, 1.22)
|
||||
AC_INIT(ofono, 1.23)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
@@ -189,8 +189,8 @@ CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
|
||||
if (test "${enable_sailfish_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.35, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.35 is required))
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.38, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.38 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib >= 1.0.6 is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
|
||||
@@ -278,6 +278,13 @@ Properties boolean Active [readwrite]
|
||||
via this proxy. All other values are left
|
||||
out in this case.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
dict IPv6.Settings [readonly, optional]
|
||||
|
||||
Holds all the IPv6 network settings
|
||||
@@ -304,6 +311,13 @@ Properties boolean Active [readwrite]
|
||||
|
||||
Holds the gateway IP for this connection.
|
||||
|
||||
array{string} ProxyCSCF [readonly, optional]
|
||||
|
||||
Holds the list of P-CSCF (SIP proxy) for this
|
||||
context. Only used by IMS connections.
|
||||
|
||||
This is a Sailfish OS specific extension.
|
||||
|
||||
string MessageProxy [readwrite, MMS only]
|
||||
|
||||
Holds the MMS Proxy setting.
|
||||
|
||||
@@ -95,6 +95,13 @@ Properties boolean Powered [readwrite]
|
||||
String representing the software version number of the
|
||||
modem device.
|
||||
|
||||
string SystemPath [readonly, optional]
|
||||
|
||||
String representing the system path for the modem
|
||||
device.
|
||||
For modems detected by udev events, this corresponds to
|
||||
the modem sysfs path.
|
||||
|
||||
array{string} Features [readonly]
|
||||
|
||||
List of currently enabled features. It uses simple
|
||||
|
||||
@@ -69,6 +69,17 @@ Methods dict GetProperties()
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
object DialMemory(string memory position, string hide_callerid)
|
||||
|
||||
Initiates a new outgoing call to the number in the given memory
|
||||
position/favourite. For callerid see the Dial method.
|
||||
|
||||
Possible Errors: [service].Error.InProgress
|
||||
[service].Error.InvalidArguments
|
||||
[service].Error.InvalidFormat
|
||||
[service].Error.NotImplemented
|
||||
[service].Error.Failed
|
||||
|
||||
void Transfer()
|
||||
|
||||
Joins the currently Active (or Outgoing, depending
|
||||
|
||||
@@ -422,6 +422,28 @@ static void hfp_dial_last(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
|
||||
}
|
||||
|
||||
static void hfp_dial_memory(struct ofono_voicecall *vc,
|
||||
unsigned int memory_location,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct voicecall_data *vd = ofono_voicecall_get_data(vc);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
char buf[256];
|
||||
|
||||
cbd->user = vc;
|
||||
DBG("Calling memory location %d\n", memory_location);
|
||||
snprintf(buf, sizeof(buf), "ATD>%d;", memory_location);
|
||||
|
||||
if (g_at_chat_send(vd->chat, buf, none_prefix,
|
||||
atd_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
g_free(cbd);
|
||||
DBG("at_chat_failed");
|
||||
CALLBACK_WITH_FAILURE(cb, data);
|
||||
}
|
||||
|
||||
static void hfp_template(const char *cmd, struct ofono_voicecall *vc,
|
||||
GAtResultFunc result_cb, unsigned int affected_types,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
@@ -1287,6 +1309,7 @@ static struct ofono_voicecall_driver driver = {
|
||||
.remove = hfp_voicecall_remove,
|
||||
.dial = hfp_dial,
|
||||
.dial_last = hfp_dial_last,
|
||||
.dial_memory = hfp_dial_memory,
|
||||
.answer = hfp_answer,
|
||||
.hangup_active = hfp_hangup,
|
||||
.hold_all_active = hfp_hold_all_active,
|
||||
|
||||
@@ -29,12 +29,16 @@
|
||||
|
||||
#include "qmi.h"
|
||||
#include "nas.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "src/common.h"
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct gprs_data {
|
||||
struct qmi_device *dev;
|
||||
struct qmi_service *nas;
|
||||
struct qmi_service *wds;
|
||||
unsigned int last_auto_context_id;
|
||||
};
|
||||
|
||||
static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
@@ -64,8 +68,124 @@ static bool extract_ss_info(struct qmi_result *result, int *status, int *tech)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
char *apn = NULL;
|
||||
uint16_t error;
|
||||
uint8_t iptype;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Failed to query LTE attach params: %hd", error);
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
/* APN */
|
||||
apn = qmi_result_get_string(result, 0x10);
|
||||
if (!apn) {
|
||||
DBG("Default profile has no APN setting");
|
||||
goto noapn;
|
||||
}
|
||||
|
||||
if (qmi_result_get_uint8(result, 0x11, &iptype))
|
||||
ofono_info("LTE attach IP type: %hhd", iptype);
|
||||
|
||||
ofono_gprs_cid_activated(gprs, data->last_auto_context_id, apn);
|
||||
g_free(apn);
|
||||
|
||||
return;
|
||||
|
||||
noapn:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_gprs* gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
data->last_auto_context_id = index;
|
||||
|
||||
/* Get LTE Attach Parameters */
|
||||
if (qmi_service_send(data->wds, 0x85, NULL,
|
||||
get_lte_attach_param_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
error:
|
||||
data->last_auto_context_id = 0;
|
||||
ofono_error("LTE bearer established but APN not set");
|
||||
}
|
||||
|
||||
/*
|
||||
* Query the settings in effect on the default bearer. These may be
|
||||
* implicit or may even be something other than requested as the gateway
|
||||
* is allowed to override whatever was requested by the user.
|
||||
*/
|
||||
static void get_lte_attach_params(struct ofono_gprs* gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
struct qmi_param *param;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (data->last_auto_context_id != 0)
|
||||
return; /* Established or in progress */
|
||||
|
||||
/* Set query in progress */
|
||||
data->last_auto_context_id = -1;
|
||||
|
||||
/* First we query the default profile in order to find out which
|
||||
* context the modem has activated.
|
||||
*/
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(data->wds, 0x49, param,
|
||||
get_default_profile_cb, gprs, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_warn("Unable to query LTE APN... will not activate context");
|
||||
}
|
||||
|
||||
static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
{
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
int status;
|
||||
int tech;
|
||||
|
||||
@@ -74,17 +194,20 @@ static int handle_ss_info(struct qmi_result *result, struct ofono_gprs *gprs)
|
||||
if (!extract_ss_info(result, &status, &tech))
|
||||
return -1;
|
||||
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED)
|
||||
if (status == NETWORK_REGISTRATION_STATUS_REGISTERED) {
|
||||
if (tech == ACCESS_TECHNOLOGY_EUTRAN) {
|
||||
/* On LTE we are effectively always attached; and
|
||||
* the default bearer is established as soon as the
|
||||
* network is joined.
|
||||
* network is joined. We just need to query the
|
||||
* parameters in effect on the default bearer and
|
||||
* let the ofono core know about the activated
|
||||
* context.
|
||||
*/
|
||||
/* FIXME: query default profile number and APN
|
||||
* instead of assuming profile 1 and ""
|
||||
*/
|
||||
ofono_gprs_cid_activated(gprs, 1 , "automatic");
|
||||
get_lte_attach_params(gprs);
|
||||
}
|
||||
} else {
|
||||
data->last_auto_context_id = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -198,7 +321,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
|
||||
g_free(cbd);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
@@ -206,12 +329,12 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
data->wds = qmi_service_ref(service);
|
||||
|
||||
/*
|
||||
* First get the SS info - the modem may already be connected,
|
||||
@@ -228,6 +351,25 @@ static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
ofono_gprs_register(gprs);
|
||||
}
|
||||
|
||||
static void create_nas_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_gprs *gprs = user_data;
|
||||
struct gprs_data *data = ofono_gprs_get_data(gprs);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request NAS service");
|
||||
ofono_gprs_remove(gprs);
|
||||
return;
|
||||
}
|
||||
|
||||
data->nas = qmi_service_ref(service);
|
||||
|
||||
qmi_service_create_shared(data->dev, QMI_SERVICE_WDS,
|
||||
create_wds_cb, gprs, NULL);
|
||||
}
|
||||
|
||||
static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
unsigned int vendor, void *user_data)
|
||||
{
|
||||
@@ -240,6 +382,8 @@ static int qmi_gprs_probe(struct ofono_gprs *gprs,
|
||||
|
||||
ofono_gprs_set_data(gprs, data);
|
||||
|
||||
data->dev = device;
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_NAS,
|
||||
create_nas_cb, gprs, NULL);
|
||||
|
||||
@@ -254,6 +398,9 @@ static void qmi_gprs_remove(struct ofono_gprs *gprs)
|
||||
|
||||
ofono_gprs_set_data(gprs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->wds);
|
||||
qmi_service_unref(data->wds);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
264
ofono/drivers/qmimodem/lte.c
Normal file
264
ofono/drivers/qmimodem/lte.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018 Jonas Bonn. All rights reserved.
|
||||
* Copyright (C) 2018 Norrbonn AB. All rights reserved.
|
||||
* Copyright (C) 2018 Data Respons ASA. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/lte.h>
|
||||
|
||||
#include "qmi.h"
|
||||
#include "wds.h"
|
||||
|
||||
#include "qmimodem.h"
|
||||
|
||||
struct lte_data {
|
||||
struct qmi_service *wds;
|
||||
uint8_t default_profile;
|
||||
};
|
||||
|
||||
static void modify_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct cb_data *cbd = user_data;
|
||||
ofono_lte_cb_t cb = cbd->cb;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
DBG("Failed to modify profile: %d", error);
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
return;
|
||||
}
|
||||
|
||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void qmimodem_lte_set_default_attach_info(const struct ofono_lte *lte,
|
||||
const struct ofono_lte_default_attach_info *info,
|
||||
ofono_lte_cb_t cb, void *data)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct cb_data *cbd = cb_data_new(cb, data);
|
||||
struct qmi_param* param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
p.index = ldd->default_profile;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* WDS APN Name */
|
||||
qmi_param_append(param, QMI_WDS_PARAM_APN,
|
||||
strlen(info->apn), info->apn);
|
||||
|
||||
/* Modify profile */
|
||||
if (qmi_service_send(ldd->wds, 0x28, param,
|
||||
modify_profile_cb, cbd, g_free) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||
}
|
||||
|
||||
static void reset_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
uint16_t error;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error))
|
||||
ofono_error("Reset profile error: %hd", error);
|
||||
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static void get_default_profile_cb(struct qmi_result *result, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
uint16_t error;
|
||||
uint8_t index;
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} __attribute__((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (qmi_result_set_error(result, &error)) {
|
||||
ofono_error("Get default profile error: %hd", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Profile index */
|
||||
if (!qmi_result_get_uint8(result, 0x01, &index)) {
|
||||
ofono_error("Failed query default profile");
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG("Default profile index: %hhd", index);
|
||||
|
||||
ldd->default_profile = index;
|
||||
|
||||
p.index = index;
|
||||
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile selector */
|
||||
qmi_param_append(param, 0x01, sizeof(p), &p);
|
||||
|
||||
/* Reset profile */
|
||||
if (qmi_service_send(ldd->wds, 0x4b, param,
|
||||
reset_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to reset profile %hhd", index);
|
||||
ofono_lte_remove(lte);
|
||||
}
|
||||
|
||||
static void create_wds_cb(struct qmi_service *service, void *user_data)
|
||||
{
|
||||
struct ofono_lte *lte = user_data;
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
struct qmi_param *param;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t family;
|
||||
} __attribute((packed)) p = {
|
||||
.type = 0, /* 3GPP */
|
||||
.family = 0, /* embedded */
|
||||
};
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!service) {
|
||||
ofono_error("Failed to request WDS service");
|
||||
ofono_lte_remove(lte);
|
||||
return;
|
||||
}
|
||||
|
||||
ldd->wds = qmi_service_ref(service);
|
||||
|
||||
/* Query the default profile */
|
||||
param = qmi_param_new();
|
||||
if (!param)
|
||||
goto error;
|
||||
|
||||
/* Profile type */
|
||||
qmi_param_append(param, 0x1, sizeof(p), &p);
|
||||
|
||||
/* Get default profile */
|
||||
if (qmi_service_send(ldd->wds, 0x49, param,
|
||||
get_default_profile_cb, lte, NULL) > 0)
|
||||
return;
|
||||
|
||||
qmi_param_free(param);
|
||||
|
||||
error:
|
||||
ofono_error("Failed to query default profile");
|
||||
ofono_lte_register(lte);
|
||||
}
|
||||
|
||||
static int qmimodem_lte_probe(struct ofono_lte *lte, void *data)
|
||||
{
|
||||
struct qmi_device *device = data;
|
||||
struct lte_data *ldd;
|
||||
|
||||
DBG("qmimodem lte probe");
|
||||
|
||||
ldd = g_try_new0(struct lte_data, 1);
|
||||
if (!ldd)
|
||||
return -ENOMEM;
|
||||
|
||||
ofono_lte_set_data(lte, ldd);
|
||||
|
||||
qmi_service_create_shared(device, QMI_SERVICE_WDS,
|
||||
create_wds_cb, lte, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qmimodem_lte_remove(struct ofono_lte *lte)
|
||||
{
|
||||
struct lte_data *ldd = ofono_lte_get_data(lte);
|
||||
|
||||
DBG("");
|
||||
|
||||
ofono_lte_set_data(lte, NULL);
|
||||
|
||||
qmi_service_unregister_all(ldd->wds);
|
||||
|
||||
qmi_service_unref(ldd->wds);
|
||||
|
||||
g_free(ldd);
|
||||
}
|
||||
|
||||
static struct ofono_lte_driver driver = {
|
||||
.name = "qmimodem",
|
||||
.probe = qmimodem_lte_probe,
|
||||
.remove = qmimodem_lte_remove,
|
||||
.set_default_attach_info = qmimodem_lte_set_default_attach_info,
|
||||
};
|
||||
|
||||
void qmi_lte_init(void)
|
||||
{
|
||||
ofono_lte_driver_register(&driver);
|
||||
}
|
||||
|
||||
void qmi_lte_exit(void)
|
||||
{
|
||||
ofono_lte_driver_unregister(&driver);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ static int qmimodem_init(void)
|
||||
qmi_ussd_init();
|
||||
qmi_gprs_init();
|
||||
qmi_gprs_context_init();
|
||||
qmi_lte_init();
|
||||
qmi_radio_settings_init();
|
||||
qmi_location_reporting_init();
|
||||
qmi_netmon_init();
|
||||
@@ -51,6 +52,7 @@ static void qmimodem_exit(void)
|
||||
qmi_netmon_exit();
|
||||
qmi_location_reporting_exit();
|
||||
qmi_radio_settings_exit();
|
||||
qmi_lte_exit();
|
||||
qmi_gprs_context_exit();
|
||||
qmi_gprs_exit();
|
||||
qmi_ussd_exit();
|
||||
|
||||
@@ -48,6 +48,9 @@ extern void qmi_gprs_exit(void);
|
||||
extern void qmi_gprs_context_init(void);
|
||||
extern void qmi_gprs_context_exit(void);
|
||||
|
||||
extern void qmi_lte_init(void);
|
||||
extern void qmi_lte_exit(void);
|
||||
|
||||
extern void qmi_radio_settings_init(void);
|
||||
extern void qmi_radio_settings_exit(void);
|
||||
|
||||
|
||||
@@ -277,6 +277,9 @@ static void qmi_radio_settings_remove(struct ofono_radio_settings *rs)
|
||||
|
||||
ofono_radio_settings_set_data(rs, NULL);
|
||||
|
||||
qmi_service_unregister_all(data->dms);
|
||||
qmi_service_unref(data->dms);
|
||||
|
||||
qmi_service_unregister_all(data->nas);
|
||||
|
||||
qmi_service_unref(data->nas);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -24,6 +24,7 @@ struct ril_cbs {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
guint register_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
@@ -51,6 +52,12 @@ static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static gboolean ril_cbs_retry(GRilIoRequest *request, int ril_status,
|
||||
const void *resp_data, guint resp_len, void *user_data)
|
||||
{
|
||||
return ril_status == RIL_E_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
gboolean activate, GRilIoChannelResponseFunc response,
|
||||
GDestroyNotify destroy, void* user_data)
|
||||
@@ -61,6 +68,9 @@ static void ril_cbs_request_activation(struct ril_cbs *cd,
|
||||
grilio_request_append_int32(req, activate ? 0 :1);
|
||||
|
||||
DBG_(cd, "%sactivating CB", activate ? "" : "de");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
|
||||
response, destroy, user_data);
|
||||
@@ -97,6 +107,9 @@ static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
|
||||
}
|
||||
|
||||
DBG_(cd, "configuring CB");
|
||||
grilio_request_set_retry_func(req, ril_cbs_retry);
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
|
||||
response, destroy, user_data);
|
||||
@@ -144,27 +157,41 @@ static void ril_cbs_notify(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
GRilIoParser rilp;
|
||||
guint32 pdu_len;
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
|
||||
DBG_(cd, "%u bytes", len);
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &pdu_len)) {
|
||||
const void* pdu = grilio_parser_get_bytes(&rilp, pdu_len);
|
||||
|
||||
/*
|
||||
* By default assume that it's a length followed by the
|
||||
* binary PDU data.
|
||||
*/
|
||||
if (pdu && grilio_parser_bytes_remaining(&rilp) < 4) {
|
||||
DBG_(cd, "%u bytes", pdu_len);
|
||||
ofono_cbs_notify(cd->cbs, pdu, pdu_len);
|
||||
} else {
|
||||
/*
|
||||
* But I've seen cell broadcasts arriving without
|
||||
* the length, simply as a blob.
|
||||
*/
|
||||
ofono_cbs_notify(cd->cbs, data, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
static gboolean ril_cbs_register(void *user_data)
|
||||
{
|
||||
struct ril_cbs *cd = user_data;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
|
||||
cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
} else {
|
||||
DBG_(cd, "failed to query CB config");
|
||||
ofono_cbs_remove(cd->cbs);
|
||||
}
|
||||
DBG_(cd, "registering for CB");
|
||||
cd->register_id = 0;
|
||||
cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
|
||||
ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
|
||||
ofono_cbs_register(cd->cbs);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
@@ -172,7 +199,6 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
ofono_cbs_set_data(cbs, cd);
|
||||
cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
@@ -182,20 +208,7 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
DBG_(cd, "");
|
||||
cd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
|
||||
* especially if other RIL requests are running in parallel. We may
|
||||
* have to retry a few times. Also, make it blocking in order to
|
||||
* improve the chance of success.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||
ril_cbs_probe_done_cb, NULL, cd);
|
||||
grilio_request_unref(req);
|
||||
cd->register_id = g_idle_add(ril_cbs_register, cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,6 +217,9 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
|
||||
struct ril_cbs *cd = ofono_cbs_get_data(cbs);
|
||||
|
||||
DBG_(cd, "");
|
||||
if (cd->register_id) {
|
||||
g_source_remove(cd->register_id);
|
||||
}
|
||||
ofono_cbs_set_data(cbs, NULL);
|
||||
grilio_channel_remove_handler(cd->io, cd->event_id);
|
||||
grilio_channel_unref(cd->io);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -46,6 +47,7 @@ struct ril_cell_info {
|
||||
gulong event_id;
|
||||
guint query_id;
|
||||
guint set_rate_id;
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
enum ril_cell_info_signal {
|
||||
@@ -330,7 +332,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
DBG_(self, "");
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
|
||||
ril_cell_info_update_cells(self,
|
||||
(status == RIL_E_SUCCESS && self->enabled) ?
|
||||
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
|
||||
}
|
||||
|
||||
@@ -344,11 +347,26 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return self->enabled;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
|
||||
@@ -359,9 +377,11 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1,
|
||||
(self->update_rate_ms > 0) ? self->update_rate_ms : INT_MAX);
|
||||
(self->update_rate_ms >= 0 && self->enabled) ?
|
||||
self->update_rate_ms : INT_MAX);
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
|
||||
grilio_request_set_retry_func(req, ril_cell_info_retry);
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
|
||||
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
|
||||
@@ -372,7 +392,8 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self)
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
|
||||
self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -467,6 +488,21 @@ static void ril_cell_info_set_update_interval_proc
|
||||
if (self->update_rate_ms != ms) {
|
||||
self->update_rate_ms = ms;
|
||||
DBG_(self, "%d ms", ms);
|
||||
if (self->enabled && self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_set_enabled_proc(struct sailfish_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
struct ril_cell_info *self = ril_cell_info_cast(info);
|
||||
|
||||
if (self->enabled != enabled) {
|
||||
self->enabled = enabled;
|
||||
DBG_(self, "%d", enabled);
|
||||
ril_cell_info_refresh(self);
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
@@ -482,7 +518,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc,
|
||||
ril_cell_info_set_update_interval_proc
|
||||
ril_cell_info_set_update_interval_proc,
|
||||
ril_cell_info_set_enabled_proc
|
||||
};
|
||||
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
@@ -504,6 +541,9 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
self->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
ril_cell_info_refresh(self);
|
||||
|
||||
/* Disable updates by default */
|
||||
self->enabled = FALSE;
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_set_rate(self);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -185,6 +186,72 @@ gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
char **values, **ptr;
|
||||
|
||||
if (comment) *comment = 0;
|
||||
values = g_strsplit(str, "+", -1);
|
||||
|
||||
for (ok = TRUE, ptr = values; *ptr && ok; ptr++) {
|
||||
const char* found_str = NULL;
|
||||
const char* s = g_strstrip(*ptr);
|
||||
|
||||
if (!strcasecmp(s, name)) {
|
||||
found_str = name;
|
||||
if (result) {
|
||||
*result |= value;
|
||||
}
|
||||
} else {
|
||||
va_list args;
|
||||
const char* known;
|
||||
|
||||
va_start(args, value);
|
||||
while ((known = va_arg(args, char*)) != NULL) {
|
||||
const int bit = va_arg(args, int);
|
||||
|
||||
if (!strcasecmp(s, known)) {
|
||||
found_str = known;
|
||||
if (result) {
|
||||
*result |= bit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!found_str) {
|
||||
ofono_error("Unknown bit '%s' in %s", s, key);
|
||||
ok = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(values);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
if (!ok && result) {
|
||||
*result = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
@@ -237,337 +304,6 @@ char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ril_config_merge_files() function does the following:
|
||||
*
|
||||
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||
* 4. Merges the contents of the additional files with the main file
|
||||
* according to their sort order.
|
||||
*
|
||||
* When the entries are merged, keys and groups overwrite the exising
|
||||
* ones by default. Keys can be suffixed with special characters to
|
||||
* remove or modify the existing entries instead:
|
||||
*
|
||||
* ':' Sets the (default) value if the key is missing
|
||||
* '+' Appends values to the string list
|
||||
* '?' Appends only new (non-existent) values to the string list
|
||||
* '-' Removes the values from the string list
|
||||
*
|
||||
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||
* or group.
|
||||
*
|
||||
* For example if we merge these two files:
|
||||
*
|
||||
* /etc/foo.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=4
|
||||
* d=5
|
||||
* [bar]
|
||||
* e=5
|
||||
*
|
||||
* /etc/foo.d/bar.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a+=2
|
||||
* b-=2
|
||||
* c=5
|
||||
* !d
|
||||
* [!bar]
|
||||
*
|
||||
* we end up with this:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=5
|
||||
*
|
||||
* Not that the list separator is assumed to be ',' (rather than default ';').
|
||||
* The keyfile passed to ril_config_merge_files() should use the same list
|
||||
* separator, because the default values are copied from the config files
|
||||
* as is.
|
||||
*/
|
||||
|
||||
static gint ril_config_sort_files(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||
* the pointers from the array as arguments, it takes pointers
|
||||
* to the pointers in the array. */
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static char **ril_config_collect_files(const char *path, const char *suffix)
|
||||
{
|
||||
/* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found. */
|
||||
char **files = NULL;
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
GPtrArray *list = g_ptr_array_new();
|
||||
const struct dirent *p;
|
||||
|
||||
while ((p = readdir(d)) != NULL) {
|
||||
/* No need to even stat . and .. */
|
||||
if (strcmp(p->d_name, ".") &&
|
||||
strcmp(p->d_name, "..") && (!suffix ||
|
||||
g_str_has_suffix(p->d_name, suffix))) {
|
||||
struct stat st;
|
||||
char *buf = g_strconcat(path, "/", p->d_name,
|
||||
NULL);
|
||||
|
||||
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, buf);
|
||||
} else {
|
||||
g_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_sort(list, ril_config_sort_files);
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**)g_ptr_array_free(list, FALSE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static int ril_config_list_find(char **list, gsize len, const char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(list[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key,
|
||||
char **values, gsize n, gboolean unique)
|
||||
{
|
||||
/* Note: will steal strings from values */
|
||||
if (n > 0) {
|
||||
int i;
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||
|
||||
for (i = 0; i < (int)len; i++) {
|
||||
g_ptr_array_add(newlist, list[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)n; i++) {
|
||||
char *val = values[i];
|
||||
|
||||
if (!unique || ril_config_list_find((char**)
|
||||
newlist->pdata, newlist->len, val) < 0) {
|
||||
/* Move the string to the new list */
|
||||
g_ptr_array_add(newlist, val);
|
||||
memmove(values + i, values + i + 1,
|
||||
sizeof(char*) * (n - i));
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlist->len > len) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) newlist->pdata,
|
||||
newlist->len);
|
||||
}
|
||||
|
||||
/* Strings are deallocated by GPtrArray */
|
||||
g_ptr_array_free(newlist, TRUE);
|
||||
g_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key, char **values, gsize n)
|
||||
{
|
||||
if (n > 0) {
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
|
||||
if (len > 0) {
|
||||
gsize i;
|
||||
const gsize oldlen = len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int pos;
|
||||
|
||||
/* Remove all matching values */
|
||||
while ((pos = ril_config_list_find(list, len,
|
||||
values[i])) >= 0) {
|
||||
g_free(list[pos]);
|
||||
memmove(list + pos, list + pos + 1,
|
||||
sizeof(char*) * (len - pos));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < oldlen) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) list, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
char *key = keys[i];
|
||||
|
||||
if (key[0] == '!') {
|
||||
if (key[1]) {
|
||||
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||
}
|
||||
} else {
|
||||
const gsize len = strlen(key);
|
||||
const char last = (len > 0) ? key[len-1] : 0;
|
||||
|
||||
if (last == '+' || last == '?') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_append(conf, k, group, key,
|
||||
values, count, last == '?');
|
||||
g_strfreev(values);
|
||||
} else if (last == '-') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
ril_config_list_remove(conf, k, group, key,
|
||||
values, count);
|
||||
g_strfreev(values);
|
||||
} else {
|
||||
/* Overwrite the value (it must exist in k) */
|
||||
gchar *value = g_key_file_get_value(k, group,
|
||||
key, NULL);
|
||||
|
||||
if (last == ':') {
|
||||
/* Default value */
|
||||
key[len-1] = 0;
|
||||
if (!g_key_file_has_key(conf,
|
||||
group, key, NULL)) {
|
||||
g_key_file_set_value(conf,
|
||||
group, key, value);
|
||||
}
|
||||
} else {
|
||||
g_key_file_set_value(conf, group, key,
|
||||
value);
|
||||
}
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
static void ril_config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
|
||||
if (group[0] == '!') {
|
||||
g_key_file_remove_group(conf, group + 1, NULL);
|
||||
} else {
|
||||
ril_config_merge_group(conf, k, group);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
}
|
||||
|
||||
static void ril_config_merge_file(GKeyFile *conf, const char *file)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
|
||||
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||
ril_config_merge_keyfile(conf, k);
|
||||
}
|
||||
|
||||
g_key_file_unref(k);
|
||||
}
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file)
|
||||
{
|
||||
if (conf && file && file[0]) {
|
||||
char *dot = strrchr(file, '.');
|
||||
const char *suffix;
|
||||
char *dir;
|
||||
char **files;
|
||||
|
||||
if (!dot) {
|
||||
dir = g_strconcat(file, ".d", NULL);
|
||||
suffix = NULL;
|
||||
} else if (!dot[1]) {
|
||||
dir = g_strconcat(file, "d", NULL);
|
||||
suffix = NULL;
|
||||
} else {
|
||||
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||
dir = g_malloc(dot - file + 3);
|
||||
strncpy(dir, file, dot - file);
|
||||
strcpy(dir + (dot - file), ".d");
|
||||
suffix = dot + 1;
|
||||
}
|
||||
|
||||
files = ril_config_collect_files(dir, suffix);
|
||||
g_free(dir);
|
||||
|
||||
/* Load the main config */
|
||||
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Loading %s", file);
|
||||
ril_config_merge_file(conf, file);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
char **ptr;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
DBG("Merging %s", *ptr);
|
||||
ril_config_merge_file(conf, *ptr);
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -22,8 +23,6 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
void ril_config_merge_files(GKeyFile *conf, const char *file);
|
||||
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
@@ -36,7 +35,12 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags);
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...);
|
||||
const char *name, int value, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
gboolean ril_config_get_mask(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
G_GNUC_NULL_TERMINATED;
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2019 Jolla Ltd.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -205,10 +205,44 @@ enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
|
||||
PDP_FAIL_NSAPI_IN_USE = 0x23,
|
||||
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
|
||||
PDP_FAIL_QOS_NOT_ACCEPTED = 0x25,
|
||||
PDP_FAIL_NETWORK_FAILURE = 0x26,
|
||||
PDP_FAIL_UMTS_REACTIVATION_REQ = 0x27,
|
||||
PDP_FAIL_FEATURE_NOT_SUPP = 0x28,
|
||||
PDP_FAIL_TFT_SEMANTIC_ERROR = 0x29,
|
||||
PDP_FAIL_TFT_SYTAX_ERROR = 0x2A,
|
||||
PDP_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
|
||||
PDP_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
|
||||
PDP_FAIL_FILTER_SYTAX_ERROR = 0x2D,
|
||||
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
|
||||
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
|
||||
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
|
||||
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
|
||||
PDP_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
|
||||
PDP_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
|
||||
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
|
||||
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
|
||||
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
|
||||
PDP_FAIL_INVALID_TRANSACTION_ID = 0x51,
|
||||
PDP_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
|
||||
PDP_FAIL_INVALID_MANDATORY_INFO = 0x60,
|
||||
PDP_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
|
||||
PDP_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
|
||||
PDP_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
|
||||
PDP_FAIL_CONDITIONAL_IE_ERROR = 0x64,
|
||||
PDP_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
|
||||
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
|
||||
PDP_FAIL_APN_TYPE_CONFLICT = 0x70,
|
||||
PDP_FAIL_INVALID_PCSCF_ADDR = 0x71,
|
||||
PDP_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED = 0x73,
|
||||
PDP_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
|
||||
PDP_FAIL_IFACE_MISMATCH = 0x75,
|
||||
PDP_FAIL_COMPANION_IFACE_IN_USE = 0x76,
|
||||
PDP_FAIL_IP_ADDRESS_MISMATCH = 0x77,
|
||||
PDP_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
|
||||
PDP_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
|
||||
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
|
||||
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
|
||||
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
|
||||
PDP_FAIL_SIGNAL_LOST = -3,
|
||||
@@ -341,6 +375,19 @@ enum ril_restricted_state {
|
||||
#define RIL_FACILITY_UNLOCK "0"
|
||||
#define RIL_FACILITY_LOCK "1"
|
||||
|
||||
/* See RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER (RIL_VERSION >= 15) */
|
||||
enum ril_unsolicited_response_filter {
|
||||
RIL_UR_SIGNAL_STRENGTH = 0x01,
|
||||
RIL_UR_FULL_NETWORK_STATE = 0x02,
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED = 0x04
|
||||
};
|
||||
|
||||
/* RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE result */
|
||||
enum ril_network_selection_mode {
|
||||
RIL_NETWORK_SELECTION_MODE_AUTO = 0,
|
||||
RIL_NETWORK_SELECTION_MODE_MANUAL = 1
|
||||
};
|
||||
|
||||
#endif /*__RIL_CONSTANTS_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_data.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_network.h"
|
||||
@@ -28,6 +31,8 @@
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
|
||||
|
||||
/* Yes, it does sometimes take minutes in roaming */
|
||||
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
|
||||
|
||||
@@ -76,6 +81,7 @@ typedef struct ril_data RilData;
|
||||
enum ril_data_io_event_id {
|
||||
IO_EVENT_DATA_CALL_LIST_CHANGED,
|
||||
IO_EVENT_RESTRICTED_STATE_CHANGED,
|
||||
IO_EVENT_EOF,
|
||||
IO_EVENT_COUNT
|
||||
};
|
||||
|
||||
@@ -114,6 +120,7 @@ struct ril_data_priv {
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
gulong settings_event_id[SETTINGS_EVENT_COUNT];
|
||||
GHashTable* grab;
|
||||
gboolean downgraded_tech; /* Status 55 workaround */
|
||||
};
|
||||
|
||||
enum ril_data_signal {
|
||||
@@ -184,9 +191,9 @@ struct ril_data_request_allow_data {
|
||||
gboolean allow;
|
||||
};
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
static void ril_data_manager_check_network_mode(struct ril_data_manager *dm);
|
||||
static void ril_data_call_deact_cid(struct ril_data *data, int cid);
|
||||
static void ril_data_cancel_all_requests(struct ril_data *self);
|
||||
static void ril_data_power_update(struct ril_data *self);
|
||||
static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
{
|
||||
@@ -236,6 +243,7 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
|
||||
dc->dnses = g_strdupv(call->dnses);
|
||||
dc->gateways = g_strdupv(call->gateways);
|
||||
dc->addresses = g_strdupv(call->addresses);
|
||||
dc->pcscf = g_strdupv(call->pcscf);
|
||||
return dc;
|
||||
} else {
|
||||
return NULL;
|
||||
@@ -246,8 +254,9 @@ static void ril_data_call_destroy(struct ril_data_call *call)
|
||||
{
|
||||
g_free(call->ifname);
|
||||
g_strfreev(call->dnses);
|
||||
g_strfreev(call->addresses);
|
||||
g_strfreev(call->gateways);
|
||||
g_strfreev(call->addresses);
|
||||
g_strfreev(call->pcscf);
|
||||
}
|
||||
|
||||
void ril_data_call_free(struct ril_data_call *call)
|
||||
@@ -315,8 +324,7 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
|
||||
|
||||
/* RIL_Data_Call_Response_v9 */
|
||||
if (version >= 9) {
|
||||
/* PCSCF */
|
||||
grilio_parser_skip_string(rilp);
|
||||
call->pcscf = grilio_parser_split_utf8(rilp, " ");
|
||||
|
||||
/* RIL_Data_Call_Response_v11 */
|
||||
if (version >= 11) {
|
||||
@@ -347,16 +355,19 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
|
||||
|
||||
if (parsed) {
|
||||
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
|
||||
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
|
||||
"mtu=%d,address=%s,dns=%s %s,gateways=%s,pcscf=%s %s]",
|
||||
call->status, call->retry_time,
|
||||
call->cid, call->active,
|
||||
ril_protocol_from_ofono(call->prot),
|
||||
call->ifname, call->mtu,
|
||||
call->addresses ? call->addresses[0] : NULL,
|
||||
call->dnses ? call->dnses[0] : NULL,
|
||||
call->addresses ? call->addresses[0] : "",
|
||||
call->dnses ? call->dnses[0] : "",
|
||||
(call->dnses && call->dnses[0] &&
|
||||
call->dnses[1]) ? call->dnses[1] : "",
|
||||
call->gateways ? call->gateways[0] : NULL);
|
||||
call->gateways ? call->gateways[0] : "",
|
||||
call->pcscf ? call->pcscf[0] : "",
|
||||
(call->pcscf && call->pcscf[0] &&
|
||||
call->pcscf[1]) ? call->pcscf[1] : "");
|
||||
return call;
|
||||
} else {
|
||||
ril_data_call_free(call);
|
||||
@@ -422,7 +433,8 @@ static gboolean ril_data_call_equal(const struct ril_data_call *c1,
|
||||
!g_strcmp0(c1->ifname, c2->ifname) &&
|
||||
gutil_strv_equal(c1->dnses, c2->dnses) &&
|
||||
gutil_strv_equal(c1->gateways, c2->gateways) &&
|
||||
gutil_strv_equal(c1->addresses, c2->addresses);
|
||||
gutil_strv_equal(c1->addresses, c2->addresses) &&
|
||||
gutil_strv_equal(c1->pcscf, c2->pcscf);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -434,7 +446,7 @@ static gboolean ril_data_call_list_equal(const struct ril_data_call_list *l1,
|
||||
if (!l1 && !l2) {
|
||||
return TRUE;
|
||||
} else if (l1 && l2) {
|
||||
if (l1->version == l1->version && l1->num == l2->num) {
|
||||
if (l1->version == l2->version && l1->num == l2->num) {
|
||||
GSList *p1 = l1->calls;
|
||||
GSList *p2 = l2->calls;
|
||||
|
||||
@@ -815,6 +827,31 @@ static gboolean ril_data_call_setup_retry(void *user_data)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean ril_data_call_retry(struct ril_data_request_setup *setup)
|
||||
{
|
||||
struct ril_data_request *req = &setup->req;
|
||||
const struct ril_data_options *options = &req->data->priv->options;
|
||||
|
||||
if (setup->retry_count < options->data_call_retry_limit) {
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
/* No delay first time */
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
options->data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
const guint ms = options->data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -839,33 +876,49 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
|
||||
setup->retry_count < priv->options.data_call_retry_limit) {
|
||||
if (call) {
|
||||
switch (call->status) {
|
||||
/*
|
||||
* According to the comment from ril.h we should silently
|
||||
* retry. First time we retry immediately and if that doedsn't
|
||||
* retry. First time we retry immediately and if that doesn't
|
||||
* work, then after certain delay.
|
||||
*/
|
||||
req->pending_id = 0;
|
||||
GASSERT(!setup->retry_delay_id);
|
||||
if (!setup->retry_count) {
|
||||
setup->retry_count++;
|
||||
DBG("silent retry %u out of %u", setup->retry_count,
|
||||
priv->options.data_call_retry_limit);
|
||||
req->submit(req);
|
||||
} else {
|
||||
guint ms = priv->options.data_call_retry_delay_ms;
|
||||
DBG("silent retry scheduled in %u ms", ms);
|
||||
setup->retry_delay_id = g_timeout_add(ms,
|
||||
ril_data_call_setup_retry, setup);
|
||||
case PDP_FAIL_ERROR_UNSPECIFIED:
|
||||
if (ril_data_call_retry(setup)) {
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* With some networks we sometimes start getting error 55
|
||||
* (Multiple PDN connections for a given APN not allowed)
|
||||
* when trying to setup an LTE data call and this error
|
||||
* doesn't go away until we successfully establish a data
|
||||
* call over 3G. Then we can switch back to LTE.
|
||||
*/
|
||||
case PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED:
|
||||
if (priv->network->data.access_tech ==
|
||||
ACCESS_TECHNOLOGY_EUTRAN &&
|
||||
!priv->downgraded_tech) {
|
||||
DBG("downgrading preferred technology");
|
||||
priv->downgraded_tech = TRUE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
/* And let this call fail */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ril_data_call_list_free(list);
|
||||
return;
|
||||
}
|
||||
|
||||
ril_data_request_completed(req);
|
||||
|
||||
if (call && call->status == PDP_FAIL_NONE) {
|
||||
if (priv->downgraded_tech) {
|
||||
DBG("done with status 55 workaround");
|
||||
priv->downgraded_tech = FALSE;
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
}
|
||||
if (ril_data_call_list_move_calls(self->data_calls, list) > 0) {
|
||||
DBG("data call(s) added");
|
||||
ril_data_signal_emit(self, SIGNAL_CALLS_CHANGED);
|
||||
@@ -903,7 +956,8 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
*
|
||||
* Makes little sense but it is what it is.
|
||||
*/
|
||||
tech = priv->network->data.ril_tech;
|
||||
tech = (setup->profile_id == RIL_DATA_PROFILE_IMS) ?
|
||||
RADIO_TECH_LTE : priv->network->data.ril_tech;
|
||||
if (tech > 2) {
|
||||
tech += 2;
|
||||
} else {
|
||||
@@ -966,10 +1020,22 @@ static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
|
||||
g_new0(struct ril_data_request_setup, 1);
|
||||
struct ril_data_request *req = &setup->req;
|
||||
|
||||
setup->profile_id = (priv->use_data_profiles &&
|
||||
context_type == OFONO_GPRS_CONTEXT_TYPE_MMS) ?
|
||||
priv->mms_data_profile_id :
|
||||
RIL_DATA_PROFILE_DEFAULT;
|
||||
setup->profile_id = RIL_DATA_PROFILE_DEFAULT;
|
||||
if (priv->use_data_profiles) {
|
||||
switch (context_type) {
|
||||
case OFONO_GPRS_CONTEXT_TYPE_MMS:
|
||||
setup->profile_id = priv->mms_data_profile_id;
|
||||
break;
|
||||
case OFONO_GPRS_CONTEXT_TYPE_IMS:
|
||||
setup->profile_id = RIL_DATA_PROFILE_IMS;
|
||||
break;
|
||||
case OFONO_GPRS_CONTEXT_TYPE_ANY:
|
||||
case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
|
||||
case OFONO_GPRS_CONTEXT_TYPE_WAP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setup->apn = g_strdup(ctx->apn);
|
||||
setup->username = g_strdup(ctx->username);
|
||||
setup->password = g_strdup(ctx->password);
|
||||
@@ -1148,9 +1214,39 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
|
||||
return req;
|
||||
}
|
||||
|
||||
static gboolean ril_data_allow_can_submit(struct ril_data *self)
|
||||
{
|
||||
if (self) {
|
||||
switch (self->priv->options.allow_data) {
|
||||
case RIL_ALLOW_DATA_ENABLED:
|
||||
return TRUE;
|
||||
case RIL_ALLOW_DATA_DISABLED:
|
||||
case RIL_ALLOW_DATA_AUTO:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_data_allow_submit_request(struct ril_data *data,
|
||||
gboolean allow)
|
||||
{
|
||||
if (ril_data_allow_can_submit(data)) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, allow));
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data
|
||||
*==========================================================================*/
|
||||
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
|
||||
{
|
||||
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
|
||||
OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
|
||||
ril_data_cb_t cb, void *arg)
|
||||
@@ -1173,12 +1269,39 @@ void ril_data_remove_handler(struct ril_data *self, gulong id)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_imsi_changed(struct ril_sim_settings *settings,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (!settings->imsi) {
|
||||
/*
|
||||
* Most likely, SIM removal. In any case, no data requests
|
||||
* make sense when IMSI is unavailable.
|
||||
*/
|
||||
ril_data_cancel_all_requests(self);
|
||||
}
|
||||
ril_data_manager_check_network_mode(priv->dm);
|
||||
}
|
||||
|
||||
static void ril_data_settings_changed(struct ril_sim_settings *settings,
|
||||
void *user_data)
|
||||
{
|
||||
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
|
||||
}
|
||||
|
||||
static void ril_data_ril_disconnected_cb(GRilIoChannel *io, void *user_data)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(user_data);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "disconnected");
|
||||
priv->flags = RIL_DATA_FLAG_NONE;
|
||||
priv->restricted_state = 0;
|
||||
ril_data_cancel_all_requests(self);
|
||||
}
|
||||
|
||||
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct ril_data *d1 = a;
|
||||
@@ -1238,10 +1361,13 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
grilio_channel_add_unsol_event_handler(io,
|
||||
ril_data_restricted_state_changed_cb,
|
||||
RIL_UNSOL_RESTRICTED_STATE_CHANGED, self);
|
||||
priv->io_event_id[IO_EVENT_EOF] =
|
||||
grilio_channel_add_disconnected_handler(io,
|
||||
ril_data_ril_disconnected_cb, self);
|
||||
|
||||
priv->settings_event_id[SETTINGS_EVENT_IMSI_CHANGED] =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
ril_data_settings_changed, self);
|
||||
ril_data_imsi_changed, self);
|
||||
priv->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
|
||||
ril_sim_settings_add_pref_mode_changed_handler(settings,
|
||||
ril_data_settings_changed, self);
|
||||
@@ -1364,6 +1490,20 @@ static void ril_data_cancel_requests(struct ril_data *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_cancel_all_requests(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_data_request *req = priv->req_queue;
|
||||
|
||||
ril_data_request_do_cancel(priv->pending_req);
|
||||
while (req) {
|
||||
struct ril_data_request *next = req->next;
|
||||
|
||||
ril_data_request_do_cancel(req);
|
||||
req = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_disallow(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
@@ -1385,10 +1525,8 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
*/
|
||||
ril_data_deactivate_all(self);
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
/* Tell rild that the data is now disabled */
|
||||
ril_data_request_queue(ril_data_allow_new(self, FALSE));
|
||||
} else {
|
||||
/* Tell rild that the data is now disabled */
|
||||
if (!ril_data_allow_submit_request(self, FALSE)) {
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
GASSERT(!ril_data_allowed(self));
|
||||
DBG_(self, "data off");
|
||||
@@ -1535,24 +1673,11 @@ static void ril_data_dispose(GObject *object)
|
||||
struct ril_data *self = RIL_DATA(object);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_data_manager *dm = priv->dm;
|
||||
struct ril_network *network = priv->network;
|
||||
struct ril_sim_settings *settings = network->settings;
|
||||
struct ril_data_request *req;
|
||||
|
||||
ril_sim_settings_remove_handlers(settings, priv->settings_event_id,
|
||||
G_N_ELEMENTS(priv->settings_event_id));
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
priv->query_id = 0;
|
||||
|
||||
ril_data_request_do_cancel(priv->pending_req);
|
||||
req = priv->req_queue;
|
||||
while (req) {
|
||||
struct ril_data_request *next = req->next;
|
||||
ril_data_request_do_cancel(req);
|
||||
req = next;
|
||||
}
|
||||
|
||||
ril_data_cancel_all_requests(self);
|
||||
dm->data_list = g_slist_remove(dm->data_list, self);
|
||||
ril_data_manager_check_data(dm);
|
||||
g_hash_table_destroy(priv->grab);
|
||||
@@ -1563,6 +1688,11 @@ static void ril_data_finalize(GObject *object)
|
||||
{
|
||||
struct ril_data *self = RIL_DATA(object);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_network *network = priv->network;
|
||||
struct ril_sim_settings *settings = network->settings;
|
||||
|
||||
ril_sim_settings_remove_all_handlers(settings, priv->settings_event_id);
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->io_event_id);
|
||||
|
||||
g_free(priv->log_prefix);
|
||||
grilio_queue_unref(priv->q);
|
||||
@@ -1646,35 +1776,41 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
struct ril_network *lte_network = NULL;
|
||||
int non_gsm_count = 0;
|
||||
if ((self->flags & RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS) &&
|
||||
ril_data_manager_handover(self)) {
|
||||
struct ril_network *lte_network = NULL, *best_network = NULL;
|
||||
enum ofono_radio_access_mode best_mode =
|
||||
OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
|
||||
/*
|
||||
* Count number of SIMs for which non-GSM mode is selected
|
||||
*/
|
||||
/* Find a SIM for internet access */
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
struct ril_data_priv *priv = data->priv;
|
||||
struct ril_network *network = priv->network;
|
||||
struct ril_sim_settings *sim = network->settings;
|
||||
enum ofono_radio_access_mode mode;
|
||||
|
||||
if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
|
||||
non_gsm_count++;
|
||||
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
|
||||
!lte_network) {
|
||||
lte_network = network;
|
||||
}
|
||||
/* Select the first network with internet role */
|
||||
if ((sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) &&
|
||||
(priv->flags & RIL_DATA_FLAG_MAX_SPEED)) {
|
||||
lte_network = network;
|
||||
break;
|
||||
}
|
||||
|
||||
/* At the same time, look for a suitable slot */
|
||||
mode = ril_network_max_supported_mode(network);
|
||||
if (mode > best_mode) {
|
||||
best_network = network;
|
||||
best_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's no SIM selected for internet access
|
||||
* then choose the first slot for LTE.
|
||||
* then use a slot with highest capabilities for LTE.
|
||||
*/
|
||||
if (!lte_network) {
|
||||
struct ril_data *data = self->data_list->data;
|
||||
lte_network = data->priv->network;
|
||||
lte_network = best_network;
|
||||
}
|
||||
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
@@ -1683,7 +1819,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
|
||||
ril_network_set_max_pref_mode(network,
|
||||
(network == lte_network) ?
|
||||
OFONO_RADIO_ACCESS_MODE_ANY :
|
||||
ril_data_max_mode(data) :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM,
|
||||
FALSE);
|
||||
}
|
||||
@@ -1693,19 +1829,21 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
ril_network_set_max_pref_mode(data->priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
|
||||
ril_data_max_mode(data), FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
|
||||
{
|
||||
GSList *l;
|
||||
if (self) {
|
||||
GSList *l;
|
||||
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
return data;
|
||||
for (l= self->data_list; l; l = l->next) {
|
||||
struct ril_data *data = l->data;
|
||||
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1722,12 +1860,10 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
|
||||
if (ril_data_manager_handover(self)) {
|
||||
ril_network_set_max_pref_mode(priv->network,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
|
||||
ril_data_max_mode(data), TRUE);
|
||||
}
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
} else {
|
||||
if (!ril_data_allow_submit_request(data, TRUE)) {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
GASSERT(ril_data_allowed(data));
|
||||
DBG_(data, "data on");
|
||||
@@ -1735,7 +1871,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
{
|
||||
/*
|
||||
* Don't do anything if there any requests pending.
|
||||
@@ -1751,12 +1887,7 @@ static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_data *data = ril_data_manager_allowed(self);
|
||||
if (data) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
}
|
||||
}
|
||||
ril_data_allow_submit_request(ril_data_manager_allowed(self), TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -39,6 +40,7 @@ struct ril_data_call {
|
||||
char **dnses;
|
||||
char **gateways;
|
||||
char **addresses;
|
||||
char **pcscf;
|
||||
};
|
||||
|
||||
struct ril_data_call_list {
|
||||
@@ -54,7 +56,8 @@ struct ril_data {
|
||||
};
|
||||
|
||||
enum ril_data_manager_flags {
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01,
|
||||
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
|
||||
};
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
@@ -77,16 +80,11 @@ struct ril_data_options {
|
||||
unsigned int data_call_retry_delay_ms;
|
||||
};
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Data not allowed */
|
||||
RIL_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||
};
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -33,27 +34,34 @@ struct ril_devmon {
|
||||
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
|
||||
};
|
||||
|
||||
/* Cell info update intervals */
|
||||
#define RIL_CELL_INFO_INTERVAL_SHORT_MS (2000) /* 2 sec */
|
||||
#define RIL_CELL_INFO_INTERVAL_LONG_MS (30000) /* 30 sec */
|
||||
|
||||
/*
|
||||
* Legacy Device Monitor uses RIL_REQUEST_SCREEN_STATE to tell
|
||||
* the modem when screen turns on and off.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ss_new(void);
|
||||
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This Device Monitor uses RIL_REQUEST_SEND_DEVICE_STATE to let
|
||||
* the modem choose the right power saving strategy. It basically
|
||||
* mirrors the logic of Android's DeviceStateMonitor class.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ds_new(void);
|
||||
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This Device Monitor implementation controls network state updates
|
||||
* by sending SET_UNSOLICITED_RESPONSE_FILTER.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This one selects the type based on the RIL version.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_auto_new(void);
|
||||
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config);
|
||||
|
||||
/*
|
||||
* This one combines several methods. Takes ownership of ril_devmon objects.
|
||||
*/
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *devmon[], guint n);
|
||||
|
||||
/* Utilities (NULL tolerant) */
|
||||
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
|
||||
|
||||
@@ -65,7 +65,7 @@ static void ril_devmon_auto_free(struct ril_devmon *devmon)
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_auto_new()
|
||||
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
@@ -78,8 +78,8 @@ struct ril_devmon *ril_devmon_auto_new()
|
||||
*/
|
||||
self->pub.free = ril_devmon_auto_free;
|
||||
self->pub.start_io = ril_devmon_auto_start_io;
|
||||
self->ss = ril_devmon_ss_new();
|
||||
self->ds = ril_devmon_ds_new();
|
||||
self->ss = ril_devmon_ss_new(config);
|
||||
self->ds = ril_devmon_ds_new(config);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
|
||||
104
ofono/drivers/ril/ril_devmon_combine.c
Normal file
104
ofono/drivers/ril/ril_devmon_combine.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
typedef struct ril_devmon_combine {
|
||||
struct ril_devmon pub;
|
||||
struct ril_devmon **impl;
|
||||
guint count;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_combine_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct ril_devmon_io **impl;
|
||||
guint count;
|
||||
} DevMonIo;
|
||||
|
||||
static inline DevMon *ril_devmon_combine_cast(struct ril_devmon *dm)
|
||||
{
|
||||
return G_CAST(dm, DevMon, pub);
|
||||
}
|
||||
|
||||
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *io)
|
||||
{
|
||||
return G_CAST(io, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_io_free(struct ril_devmon_io *io)
|
||||
{
|
||||
guint i;
|
||||
DevMonIo *self = ril_devmon_ds_io_cast(io);
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_io_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_combine_start_io(struct ril_devmon *dm,
|
||||
GRilIoChannel *chan, struct sailfish_cell_info *ci)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
DevMonIo *io = g_malloc0(sizeof(DevMonIo) +
|
||||
sizeof(struct ril_devmon_io *) * self->count);
|
||||
|
||||
io->pub.free = ril_devmon_combine_io_free;
|
||||
io->impl = (struct ril_devmon_io**)(io + 1);
|
||||
io->count = self->count;
|
||||
for (i = 0; i < io->count; i++) {
|
||||
io->impl[i] = ril_devmon_start_io(self->impl[i], chan, ci);
|
||||
}
|
||||
return &io->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_combine_free(struct ril_devmon *dm)
|
||||
{
|
||||
DevMon *self = ril_devmon_combine_cast(dm);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
ril_devmon_free(self->impl[i]);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_combine(struct ril_devmon *dm[], guint n)
|
||||
{
|
||||
guint i;
|
||||
DevMon *self = g_malloc0(sizeof(DevMon) +
|
||||
sizeof(struct ril_devmon *) * n);
|
||||
|
||||
self->pub.free = ril_devmon_combine_free;
|
||||
self->pub.start_io = ril_devmon_combine_start_io;
|
||||
self->impl = (struct ril_devmon **)(self + 1);
|
||||
self->count = n;
|
||||
for (i = 0; i < n; i++) {
|
||||
self->impl[i] = dm[i];
|
||||
}
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -65,6 +65,8 @@ typedef struct ril_devmon_ds {
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ds_io {
|
||||
@@ -86,6 +88,8 @@ typedef struct ril_devmon_ds_io {
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
@@ -201,8 +205,8 @@ static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
(ril_devmon_ds_display_on(self->display) &&
|
||||
(ril_devmon_ds_charging(self->charger) ||
|
||||
ril_devmon_ds_battery_ok(self->battery))) ?
|
||||
RIL_CELL_INFO_INTERVAL_SHORT_MS :
|
||||
RIL_CELL_INFO_INTERVAL_LONG_MS);
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
|
||||
@@ -303,6 +307,11 @@ static struct ril_devmon_io *ril_devmon_ds_start_io(struct ril_devmon *devmon,
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ds_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ds->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ds->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ds_io_update_low_data(self);
|
||||
ril_devmon_ds_io_update_charging(self);
|
||||
ril_devmon_ds_io_set_cell_info_update_interval(self);
|
||||
@@ -320,7 +329,7 @@ static void ril_devmon_ds_free(struct ril_devmon *devmon)
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ds_new()
|
||||
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
@@ -330,6 +339,10 @@ struct ril_devmon *ril_devmon_ds_new()
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ typedef struct ril_devmon_ss {
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ss_io {
|
||||
@@ -65,6 +67,8 @@ typedef struct ril_devmon_ss_io {
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
|
||||
@@ -130,8 +134,8 @@ static void ril_devmon_ss_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
sailfish_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ss_charging(self->charger) ||
|
||||
ril_devmon_ss_battery_ok(self->battery))) ?
|
||||
RIL_CELL_INFO_INTERVAL_SHORT_MS :
|
||||
RIL_CELL_INFO_INTERVAL_LONG_MS);
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ss_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
@@ -212,6 +216,11 @@ static struct ril_devmon_io *ril_devmon_ss_start_io(struct ril_devmon *devmon,
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ss_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ss->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ss->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ss_io_send_screen_state(self);
|
||||
ril_devmon_ss_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
@@ -227,7 +236,7 @@ static void ril_devmon_ss_free(struct ril_devmon *devmon)
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ss_new()
|
||||
struct ril_devmon *ril_devmon_ss_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
@@ -236,6 +245,10 @@ struct ril_devmon *ril_devmon_ss_new()
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
|
||||
267
ofono/drivers/ril/ril_devmon_ur.c
Normal file
267
ofono/drivers/ril/ril_devmon_ur.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC
|
||||
*
|
||||
* 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_devmon.h"
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/ril-constants.h>
|
||||
|
||||
#include <mce_battery.h>
|
||||
#include <mce_charger.h>
|
||||
#include <mce_display.h>
|
||||
|
||||
#include <grilio_channel.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#define RIL_UR_ENABLE_ALL (RIL_UR_SIGNAL_STRENGTH | \
|
||||
RIL_UR_FULL_NETWORK_STATE | \
|
||||
RIL_UR_DATA_CALL_DORMANCY_CHANGED)
|
||||
|
||||
enum ril_devmon_ur_battery_event {
|
||||
BATTERY_EVENT_VALID,
|
||||
BATTERY_EVENT_STATUS,
|
||||
BATTERY_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_charger_event {
|
||||
CHARGER_EVENT_VALID,
|
||||
CHARGER_EVENT_STATE,
|
||||
CHARGER_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_devmon_ur_display_event {
|
||||
DISPLAY_EVENT_VALID,
|
||||
DISPLAY_EVENT_STATE,
|
||||
DISPLAY_EVENT_COUNT
|
||||
};
|
||||
|
||||
typedef struct ril_devmon_ur {
|
||||
struct ril_devmon pub;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMon;
|
||||
|
||||
typedef struct ril_devmon_ur_io {
|
||||
struct ril_devmon_io pub;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
MceBattery *battery;
|
||||
MceCharger *charger;
|
||||
MceDisplay *display;
|
||||
GRilIoChannel *io;
|
||||
gboolean display_on;
|
||||
gboolean unsol_filter_supported;
|
||||
gulong battery_event_id[BATTERY_EVENT_COUNT];
|
||||
gulong charger_event_id[CHARGER_EVENT_COUNT];
|
||||
gulong display_event_id[DISPLAY_EVENT_COUNT];
|
||||
guint req_id;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
} DevMonIo;
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s: " fmt, (self)->io->name, ##args)
|
||||
|
||||
inline static DevMon *ril_devmon_ur_cast(struct ril_devmon *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMon, pub);
|
||||
}
|
||||
|
||||
inline static DevMonIo *ril_devmon_ur_io_cast(struct ril_devmon_io *pub)
|
||||
{
|
||||
return G_CAST(pub, DevMonIo, pub);
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_battery_ok(MceBattery *battery)
|
||||
{
|
||||
return battery->valid && battery->status >= MCE_BATTERY_OK;
|
||||
}
|
||||
|
||||
static inline gboolean ril_devmon_ur_charging(MceCharger *charger)
|
||||
{
|
||||
return charger->valid && charger->state == MCE_CHARGER_ON;
|
||||
}
|
||||
|
||||
static gboolean ril_devmon_ur_display_on(MceDisplay *display)
|
||||
{
|
||||
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_unsol_response_filter_sent(GRilIoChannel *io,
|
||||
int status, const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
|
||||
self->req_id = 0;
|
||||
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
|
||||
/* This is a permanent failure */
|
||||
DBG_(self, "Unsolicited response filter is not supported");
|
||||
self->unsol_filter_supported = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_unsol_response_filter(DevMonIo *self)
|
||||
{
|
||||
if (self->unsol_filter_supported) {
|
||||
const gint32 value = self->display_on ? RIL_UR_ENABLE_ALL : 0;
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, value);
|
||||
|
||||
DBG_(self, "Setting unsolicited response filter: %u", value);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
self->req_id =
|
||||
grilio_channel_send_request_full(self->io, req,
|
||||
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER,
|
||||
ril_devmon_ur_io_unsol_response_filter_sent,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_set_cell_info_update_interval(DevMonIo *self)
|
||||
{
|
||||
sailfish_cell_info_set_update_interval(self->cell_info,
|
||||
(self->display_on && (ril_devmon_ur_charging(self->charger) ||
|
||||
ril_devmon_ur_battery_ok(self->battery))) ?
|
||||
self->cell_info_interval_short_ms :
|
||||
self->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_battery_cb(MceBattery *battery, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_charger_cb(MceCharger *charger, void *user_data)
|
||||
{
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(user_data);
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_display_cb(MceDisplay *display, void *user_data)
|
||||
{
|
||||
DevMonIo *self = user_data;
|
||||
const gboolean display_on = ril_devmon_ur_display_on(display);
|
||||
|
||||
if (self->display_on != display_on) {
|
||||
self->display_on = display_on;
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_io_free(struct ril_devmon_io *devmon_io)
|
||||
{
|
||||
DevMonIo *self = ril_devmon_ur_io_cast(devmon_io);
|
||||
|
||||
mce_battery_remove_all_handlers(self->battery, self->battery_event_id);
|
||||
mce_battery_unref(self->battery);
|
||||
|
||||
mce_charger_remove_all_handlers(self->charger, self->charger_event_id);
|
||||
mce_charger_unref(self->charger);
|
||||
|
||||
mce_display_remove_all_handlers(self->display, self->display_event_id);
|
||||
mce_display_unref(self->display);
|
||||
|
||||
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
|
||||
grilio_channel_unref(self->io);
|
||||
|
||||
sailfish_cell_info_unref(self->cell_info);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static struct ril_devmon_io *ril_devmon_ur_start_io(struct ril_devmon *devmon,
|
||||
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
DevMon *ur = ril_devmon_ur_cast(devmon);
|
||||
DevMonIo *self = g_new0(DevMonIo, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_io_free;
|
||||
self->unsol_filter_supported = TRUE;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
|
||||
self->battery = mce_battery_ref(ur->battery);
|
||||
self->battery_event_id[BATTERY_EVENT_VALID] =
|
||||
mce_battery_add_valid_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
self->battery_event_id[BATTERY_EVENT_STATUS] =
|
||||
mce_battery_add_status_changed_handler(self->battery,
|
||||
ril_devmon_ur_io_battery_cb, self);
|
||||
|
||||
self->charger = mce_charger_ref(ur->charger);
|
||||
self->charger_event_id[CHARGER_EVENT_VALID] =
|
||||
mce_charger_add_valid_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
self->charger_event_id[CHARGER_EVENT_STATE] =
|
||||
mce_charger_add_state_changed_handler(self->charger,
|
||||
ril_devmon_ur_io_charger_cb, self);
|
||||
|
||||
self->display = mce_display_ref(ur->display);
|
||||
self->display_on = ril_devmon_ur_display_on(self->display);
|
||||
self->display_event_id[DISPLAY_EVENT_VALID] =
|
||||
mce_display_add_valid_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
self->display_event_id[DISPLAY_EVENT_STATE] =
|
||||
mce_display_add_state_changed_handler(self->display,
|
||||
ril_devmon_ur_io_display_cb, self);
|
||||
|
||||
self->cell_info_interval_short_ms =
|
||||
ur->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
ur->cell_info_interval_long_ms;
|
||||
|
||||
ril_devmon_ur_io_set_unsol_response_filter(self);
|
||||
ril_devmon_ur_io_set_cell_info_update_interval(self);
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
static void ril_devmon_ur_free(struct ril_devmon *devmon)
|
||||
{
|
||||
DevMon *self = ril_devmon_ur_cast(devmon);
|
||||
|
||||
mce_battery_unref(self->battery);
|
||||
mce_charger_unref(self->charger);
|
||||
mce_display_unref(self->display);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct ril_devmon *ril_devmon_ur_new(const struct ril_slot_config *config)
|
||||
{
|
||||
DevMon *self = g_new0(DevMon, 1);
|
||||
|
||||
self->pub.free = ril_devmon_ur_free;
|
||||
self->pub.start_io = ril_devmon_ur_start_io;
|
||||
self->battery = mce_battery_new();
|
||||
self->charger = mce_charger_new();
|
||||
self->display = mce_display_new();
|
||||
self->cell_info_interval_short_ms =
|
||||
config->cell_info_interval_short_ms;
|
||||
self->cell_info_interval_long_ms =
|
||||
config->cell_info_interval_long_ms;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +14,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -47,6 +50,53 @@ G_DEFINE_TYPE(RilEccList, ril_ecclist, G_TYPE_OBJECT)
|
||||
#define RIL_ECCLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_ECCLIST_TYPE, RilEccList))
|
||||
|
||||
static char **ril_ecclist_parse(const char *content)
|
||||
{
|
||||
char **ptr;
|
||||
char **list = NULL;
|
||||
guint i;
|
||||
|
||||
/*
|
||||
* Some MediaTek devices use ECC,CAT;ECC,CAT kind of syntax
|
||||
*/
|
||||
if (strchr(content, ';')) {
|
||||
list = g_strsplit(content, ";", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
char* comma;
|
||||
|
||||
*ptr = g_strstrip(*ptr);
|
||||
|
||||
/* Strip service category */
|
||||
comma = strchr(*ptr, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The right ECC,ECC syntax is handled here */
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
gutil_strv_sort(list, TRUE);
|
||||
|
||||
/* Remove empty strings (those are at the beginning after sorting) */
|
||||
while (list[0] && !list[0][0]) {
|
||||
list = gutil_strv_remove_at(list, 0, TRUE);
|
||||
}
|
||||
|
||||
/* Remove duplicates */
|
||||
for (i = 0; list[i] && list[i+1]; i++) {
|
||||
while (list[i+1] && !strcmp(list[i], list[i+1])) {
|
||||
list = gutil_strv_remove_at(list, i+1, TRUE);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
{
|
||||
struct ril_ecclist_priv *priv = self->priv;
|
||||
@@ -58,16 +108,9 @@ static char **ril_ecclist_read(struct ril_ecclist *self)
|
||||
GError *error = NULL;
|
||||
|
||||
if (g_file_get_contents(priv->path, &content, &len, &error)) {
|
||||
char **ptr;
|
||||
|
||||
DBG("%s = %s", priv->name, content);
|
||||
list = g_strsplit(content, ",", 0);
|
||||
for (ptr = list; *ptr; ptr++) {
|
||||
*ptr = g_strstrip(*ptr);
|
||||
}
|
||||
|
||||
gutil_strv_sort(list, TRUE);
|
||||
} else if (error) {
|
||||
list = ril_ecclist_parse(content);
|
||||
} else {
|
||||
DBG("%s: %s", priv->path, GERRMSG(error));
|
||||
g_error_free(error);
|
||||
}
|
||||
@@ -89,7 +132,8 @@ static void ril_ecclist_update(struct ril_ecclist *self)
|
||||
DBG("%s changed", priv->name);
|
||||
g_strfreev(self->list);
|
||||
self->list = list;
|
||||
g_signal_emit(self, ril_ecclist_signals[SIGNAL_LIST_CHANGED], 0);
|
||||
g_signal_emit(self, ril_ecclist_signals
|
||||
[SIGNAL_LIST_CHANGED], 0);
|
||||
} else {
|
||||
g_strfreev(list);
|
||||
}
|
||||
@@ -121,10 +165,9 @@ static void ril_ecclist_dir_changed(GUtilInotifyWatch *watch, guint mask,
|
||||
priv->file_watch = gutil_inotify_watch_callback_new(priv->path,
|
||||
IN_MODIFY | IN_CLOSE_WRITE,
|
||||
ril_ecclist_changed, self);
|
||||
if (priv->file_watch) {
|
||||
DBG("watching %s", priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
DBG("%swatching %s", priv->file_watch ? "" : "not ",
|
||||
priv->path);
|
||||
ril_ecclist_update(self);
|
||||
}
|
||||
|
||||
if (mask & IN_IGNORED) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
#define MAX_MTU 1280
|
||||
#define MAX_MMS_MTU 1280
|
||||
|
||||
struct ril_gprs_context_call {
|
||||
struct ril_data_request *req;
|
||||
@@ -108,8 +108,15 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
if (call) {
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
if (ofono_gprs_context_get_type(gcd->gc) ==
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
/*
|
||||
* Some MMS providers have a problem with MTU
|
||||
* greater than 1280. Let's be safe.
|
||||
*/
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MMS_MTU);
|
||||
}
|
||||
}
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
ril_data_call_grab(gcd->data, call->cid, gcd);
|
||||
@@ -247,34 +254,59 @@ static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
|
||||
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
typedef void (*ofono_gprs_context_list_setter_t)(struct ofono_gprs_context *gc,
|
||||
const char **list);
|
||||
|
||||
static void ril_gprs_context_set_servers(struct ofono_gprs_context *gc,
|
||||
char * const *list, ofono_gprs_context_list_setter_t set_ipv4,
|
||||
ofono_gprs_context_list_setter_t set_ipv6)
|
||||
{
|
||||
int i;
|
||||
char * const *list = call->dnses;
|
||||
const char **ip_list = NULL, **ip_ptr = NULL;
|
||||
const char **ipv6_list = NULL, **ipv6_ptr = NULL;
|
||||
const int n = gutil_strv_length(list);
|
||||
const char **ip_dns = g_new0(const char *, n+1);
|
||||
const char **ipv6_dns = g_new0(const char *, n+1);
|
||||
const char **ip_ptr = ip_dns;
|
||||
const char **ipv6_ptr = ipv6_dns;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *addr = list[i];
|
||||
switch (ril_gprs_context_address_family(addr)) {
|
||||
case AF_INET:
|
||||
if (!ip_ptr) {
|
||||
ip_list = g_new0(const char *, n - i + 1);
|
||||
ip_ptr = ip_list;
|
||||
}
|
||||
*ip_ptr++ = addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!ipv6_ptr) {
|
||||
ipv6_list = g_new0(const char *, n - i + 1);
|
||||
ipv6_ptr = ipv6_list;
|
||||
}
|
||||
*ipv6_ptr++ = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
|
||||
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
|
||||
set_ipv4(gc, ip_list);
|
||||
set_ipv6(gc, ipv6_list);
|
||||
|
||||
g_free(ip_dns);
|
||||
g_free(ipv6_dns);
|
||||
g_free(ip_list);
|
||||
g_free(ipv6_list);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->dnses,
|
||||
ofono_gprs_context_set_ipv4_dns_servers,
|
||||
ofono_gprs_context_set_ipv6_dns_servers);
|
||||
}
|
||||
|
||||
static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const struct ril_data_call *call)
|
||||
{
|
||||
ril_gprs_context_set_servers(gc, call->pcscf,
|
||||
ofono_gprs_context_set_ipv4_proxy_cscf,
|
||||
ofono_gprs_context_set_ipv6_proxy_cscf);
|
||||
}
|
||||
|
||||
/* Only compares the stuff that's important to us */
|
||||
@@ -282,7 +314,8 @@ static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
|
||||
#define DATA_CALL_ADDRESS_CHANGED (0x02)
|
||||
#define DATA_CALL_GATEWAY_CHANGED (0x04)
|
||||
#define DATA_CALL_DNS_CHANGED (0x08)
|
||||
#define DATA_CALL_ALL_CHANGED (0x0f)
|
||||
#define DATA_CALL_PCSCF_CHANGED (0x10)
|
||||
#define DATA_CALL_ALL_CHANGED (0x1f)
|
||||
static int ril_gprs_context_data_call_change(
|
||||
const struct ril_data_call *c1,
|
||||
const struct ril_data_call *c2)
|
||||
@@ -308,6 +341,10 @@ static int ril_gprs_context_data_call_change(
|
||||
changes |= DATA_CALL_DNS_CHANGED;
|
||||
}
|
||||
|
||||
if (!gutil_strv_equal(c1->pcscf, c2->pcscf)) {
|
||||
changes |= DATA_CALL_PCSCF_CHANGED;
|
||||
}
|
||||
|
||||
return changes;
|
||||
} else {
|
||||
return DATA_CALL_ALL_CHANGED;
|
||||
@@ -380,6 +417,11 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
}
|
||||
|
||||
if (change & DATA_CALL_PCSCF_CHANGED) {
|
||||
DBG("P-CSCF changed");
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
}
|
||||
|
||||
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
|
||||
ril_data_call_free(prev_call);
|
||||
}
|
||||
@@ -421,6 +463,7 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
|
||||
ril_gprs_context_set_address(gc, call);
|
||||
ril_gprs_context_set_gateway(gc, call);
|
||||
ril_gprs_context_set_dns_servers(gc, call);
|
||||
ril_gprs_context_set_proxy_cscf(gc, call);
|
||||
ril_error_init_ok(&error);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
@@ -28,7 +29,6 @@
|
||||
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
enum ril_modem_power_state {
|
||||
@@ -218,22 +218,21 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
|
||||
if (md->watch->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
if (!rs) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
ofono_radio_settings_create(m->ofono, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
}
|
||||
} else if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
/* ofono core may remove radio settings atom internally */
|
||||
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
|
||||
if (rs) {
|
||||
DBG_(md, "removing radio settings interface");
|
||||
ofono_radio_settings_remove(rs);
|
||||
} else {
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
DBG_(md, "radio settings interface is already gone");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +241,6 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.radio == radio);
|
||||
ril_modem_update_radio_settings(md);
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
@@ -306,15 +304,22 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
ofono_sms_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
gprs = ofono_gprs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (gprs) {
|
||||
int i;
|
||||
guint i;
|
||||
static const enum ofono_gprs_context_type ap_types[] = {
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET,
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS,
|
||||
OFONO_GPRS_CONTEXT_TYPE_IMS
|
||||
};
|
||||
|
||||
for (i = 0; i < MAX_PDP_CONTEXTS; i++) {
|
||||
/* Create a context for each type */
|
||||
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
|
||||
struct ofono_gprs_context *gc =
|
||||
ofono_gprs_context_create(modem, 0,
|
||||
RILMODEM_DRIVER, md);
|
||||
if (gc == NULL)
|
||||
break;
|
||||
|
||||
ofono_gprs_context_set_type(gc, ap_types[i]);
|
||||
ofono_gprs_add_context(gprs, gc);
|
||||
}
|
||||
}
|
||||
@@ -335,6 +340,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
|
||||
if (md->modem.config.enable_cbs) {
|
||||
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
ofono_sim_auth_create(modem);
|
||||
}
|
||||
|
||||
static void ril_modem_post_online(struct ofono_modem *modem)
|
||||
@@ -416,7 +422,9 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_set_online(modem->radio, FALSE);
|
||||
ril_radio_unref(modem->radio);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
@@ -435,6 +443,7 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
g_source_remove(md->set_offline.timeout_id);
|
||||
}
|
||||
|
||||
ril_vendor_unref(modem->vendor);
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_data_unref(modem->data);
|
||||
@@ -456,7 +465,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
@@ -483,6 +492,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
modem->ofono = ofono;
|
||||
modem->vendor = ril_vendor_ref(vendor);
|
||||
modem->radio = ril_radio_ref(radio);
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -16,12 +17,15 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_vendor.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "simutil.h"
|
||||
|
||||
#define REGISTRATION_TIMEOUT (100*1000) /* ms */
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#define REGISTRATION_MAX_RETRIES (2)
|
||||
|
||||
enum ril_netreg_events {
|
||||
@@ -39,15 +43,21 @@ enum ril_netreg_network_events {
|
||||
struct ril_netreg {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean network_selection_manual_0;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
struct ofono_watch *watch;
|
||||
struct ofono_netreg *netreg;
|
||||
struct ril_network *network;
|
||||
struct ril_vendor *vendor;
|
||||
char *log_prefix;
|
||||
guint timer_id;
|
||||
guint notify_id;
|
||||
guint current_operator_id;
|
||||
gulong ril_event_id[NETREG_RIL_EVENT_COUNT];
|
||||
gulong network_event_id[NETREG_NETWORK_EVENT_COUNT];
|
||||
int network_selection_timeout;
|
||||
};
|
||||
|
||||
struct ril_netreg_cbd {
|
||||
@@ -187,11 +197,74 @@ static void ril_netreg_current_operator(struct ofono_netreg *netreg,
|
||||
ril_netreg_cbd_free);
|
||||
}
|
||||
|
||||
static gboolean ril_netreg_strange(const struct ofono_network_operator *op,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
gsize mcclen;
|
||||
|
||||
if (sim && op->status != OPERATOR_STATUS_CURRENT) {
|
||||
const char *spn = ofono_sim_get_spn(sim);
|
||||
const char *mcc = ofono_sim_get_mcc(sim);
|
||||
const char *mnc = ofono_sim_get_mnc(sim);
|
||||
|
||||
if (spn && mcc && mnc && !strcmp(op->name, spn) &&
|
||||
(strcmp(op->mcc, mcc) || strcmp(op->mnc, mnc))) {
|
||||
/*
|
||||
* Status is not "current", SPN matches the SIM, but
|
||||
* MCC and/or MNC don't (e.g. Sony Xperia X where all
|
||||
* operators could be reported with the same name
|
||||
* which equals SPN).
|
||||
*/
|
||||
DBG("%s %s%s (sim spn?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mcclen = strlen(op->mcc);
|
||||
if (!strncmp(op->name, op->mcc, mcclen) &&
|
||||
!strcmp(op->name + mcclen, op->mnc)) {
|
||||
/* Some MediaTek RILs only report numeric operator name */
|
||||
DBG("%s %s%s (numeric?)", op->name, op->mcc, op->mnc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_netreg_process_operators(struct ril_netreg *nd,
|
||||
struct ofono_network_operator *ops, int nops)
|
||||
{
|
||||
if (nd->replace_strange_oper) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nops; i++) {
|
||||
struct ofono_network_operator *op = ops + i;
|
||||
struct ofono_gprs_provision_data *prov = NULL;
|
||||
int np = 0;
|
||||
|
||||
if (ril_netreg_strange(op, nd->watch->sim) &&
|
||||
__ofono_gprs_provision_get_settings(op->mcc,
|
||||
op->mnc, NULL, &prov, &np)) {
|
||||
/* Use the first entry */
|
||||
if (np > 0 && prov->provider_name &&
|
||||
prov->provider_name[0]) {
|
||||
DBG("%s %s%s -> %s", op->name, op->mcc,
|
||||
op->mnc, prov->provider_name);
|
||||
strncpy(op->name, prov->provider_name,
|
||||
OFONO_MAX_OPERATOR_NAME_LENGTH);
|
||||
}
|
||||
__ofono_gprs_provision_free_settings(prov, np);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_operator_list_cb_t cb = cbd->cb.operator_list;
|
||||
struct ril_netreg *nd = cbd->nd;
|
||||
struct ofono_network_operator *list;
|
||||
struct ofono_error error;
|
||||
int noperators = 0, i;
|
||||
@@ -233,21 +306,23 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
/* Set the proper status */
|
||||
if (!strcmp(status, "available")) {
|
||||
list[i].status = OPERATOR_STATUS_AVAILABLE;
|
||||
if (!status) {
|
||||
op->status = OPERATOR_STATUS_UNKNOWN;
|
||||
} else if (!strcmp(status, "available")) {
|
||||
op->status = OPERATOR_STATUS_AVAILABLE;
|
||||
} else if (!strcmp(status, "current")) {
|
||||
list[i].status = OPERATOR_STATUS_CURRENT;
|
||||
op->status = OPERATOR_STATUS_CURRENT;
|
||||
} else if (!strcmp(status, "forbidden")) {
|
||||
list[i].status = OPERATOR_STATUS_FORBIDDEN;
|
||||
op->status = OPERATOR_STATUS_FORBIDDEN;
|
||||
} else {
|
||||
list[i].status = OPERATOR_STATUS_UNKNOWN;
|
||||
op->status = OPERATOR_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
op->tech = -1;
|
||||
ok = ril_parse_mcc_mnc(numeric, op);
|
||||
if (ok) {
|
||||
if (op->tech < 0) {
|
||||
op->tech = cbd->nd->network->voice.access_tech;
|
||||
op->tech = nd->network->voice.access_tech;
|
||||
}
|
||||
DBG("[operator=%s, %s, %s, status: %s]", op->name,
|
||||
op->mcc, op->mnc, status);
|
||||
@@ -262,6 +337,7 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ril_netreg_process_operators(nd, list, noperators);
|
||||
cb(ril_error_ok(&error), noperators, list, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&error), 0, NULL, cbd->data);
|
||||
@@ -296,18 +372,55 @@ static void ril_netreg_register_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_set_register_auto(struct ril_netreg *nd,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_netreg_query_register_auto_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_netreg_cbd *cbd = user_data;
|
||||
ofono_netreg_register_cb_t cb = cbd->cb.reg;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GRilIoParser rilp;
|
||||
gint32 net_mode;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, NULL) /* Array length */ &&
|
||||
grilio_parser_get_int32(&rilp, &net_mode) &&
|
||||
net_mode == RIL_NETWORK_SELECTION_MODE_AUTO) {
|
||||
struct ofono_error error;
|
||||
ofono_info("nw selection is already auto");
|
||||
cb(ril_error_ok(&error), cbd->data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ril_netreg_set_register_auto(cbd->nd, cb, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_netreg_register_auto(struct ofono_netreg *netreg,
|
||||
ofono_netreg_register_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_netreg *nd = ril_netreg_get_data(netreg);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("nw select automatic");
|
||||
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
|
||||
ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
|
||||
ril_netreg_cbd_new(nd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
@@ -322,8 +435,7 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
|
||||
ofono_info("nw select manual: %s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_append_format(req, "%s%s%s", mcc, mnc, suffix);
|
||||
grilio_request_set_timeout(req, REGISTRATION_TIMEOUT);
|
||||
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
|
||||
grilio_request_set_timeout(req, nd->network_selection_timeout);
|
||||
grilio_queue_send_request_full(nd->q, req,
|
||||
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
|
||||
ril_netreg_register_cb, ril_netreg_cbd_free,
|
||||
@@ -331,100 +443,92 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static int ril_netreg_dbm_to_percentage(int dbm)
|
||||
static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
|
||||
{
|
||||
const int min_dbm = -100; /* very weak signal, 0.0000000001 mW */
|
||||
const int max_dbm = -60; /* strong signal, 0.000001 mW */
|
||||
const int min_qdbm = 4 * nd->signal_strength_dbm_weak; /* 4*dBm */
|
||||
const int max_qdbm = 4 * nd->signal_strength_dbm_strong; /* 4*dBm */
|
||||
|
||||
return (dbm <= min_dbm) ? 1 :
|
||||
(dbm >= max_dbm) ? 100 :
|
||||
(100 * (dbm - min_dbm) / (max_dbm - min_dbm));
|
||||
return (qdbm <= min_qdbm) ? 1 :
|
||||
(qdbm >= max_qdbm) ? 100 :
|
||||
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
|
||||
}
|
||||
|
||||
static int ril_netreg_get_signal_strength(const void *data, guint len)
|
||||
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
|
||||
const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
|
||||
int rsrp = 0, tdscdma_dbm = 0;
|
||||
struct ril_vendor_signal_strength signal;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &gw_signal);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
|
||||
gint32 rsrp = 0, tdscdma_dbm = 0;
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &cdma_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
/* Apply default parsing algorithm */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
signal.gsm = INT_MAX;
|
||||
signal.lte = INT_MAX;
|
||||
signal.qdbm = 0;
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &evdo_dbm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.gsm);
|
||||
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, <e_signal);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
|
||||
/* Skip the rest of LTE_SignalStrength_v8 */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL)) { /* timingAdvance */
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm); /* rscp */
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &signal.lte);
|
||||
grilio_parser_get_int32(&rilp, &rsrp);
|
||||
|
||||
/* The rest is considered optional */
|
||||
if (grilio_parser_get_int32(&rilp, NULL) && /* rsrq */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* rssnr */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* cqi */
|
||||
grilio_parser_get_int32(&rilp, NULL) && /* timingAdv */
|
||||
/* TD_SCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(&rilp, &tdscdma_dbm) &&
|
||||
/* RSCP range: 25 to 120 dBm per 3GPP TS 25.123 */
|
||||
tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
signal.qdbm = -4 * tdscdma_dbm;
|
||||
} else if (signal.lte == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
/* RSRP range: 44 to 140 dBm per 3GPP TS 36.133 */
|
||||
signal.qdbm = -4 * rsrp;
|
||||
}
|
||||
}
|
||||
|
||||
if (rsrp == INT_MAX) {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d, tdscdma: %d",
|
||||
gw_signal, cdma_dbm, evdo_dbm,
|
||||
lte_signal, tdscdma_dbm);
|
||||
} else {
|
||||
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d, tdscdma: %d",
|
||||
gw_signal, cdma_dbm, evdo_dbm,
|
||||
lte_signal, rsrp, tdscdma_dbm);
|
||||
}
|
||||
DBG("gw: %d, lte: %d, qdbm: %d", signal.gsm, signal.lte, signal.qdbm);
|
||||
|
||||
/* Return the first valid one */
|
||||
|
||||
/* Some RILs (namely, from MediaTek) report 0 here AND a valid LTE
|
||||
* RSRP value. If we've got zero, don't report it just yet. */
|
||||
if (gw_signal >= 1 && gw_signal <= 31) {
|
||||
if (signal.gsm >= 1 && signal.gsm <= 31) {
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
return (gw_signal * 100) / 31;
|
||||
return (signal.gsm * 100) / 31;
|
||||
}
|
||||
|
||||
/* Valid values are (0-31, 99) as defined in TS 27.007 */
|
||||
if (lte_signal >= 0 && lte_signal <= 31) {
|
||||
return (lte_signal * 100) / 31;
|
||||
if (signal.lte >= 0 && signal.lte <= 31) {
|
||||
return (signal.lte * 100) / 31;
|
||||
}
|
||||
|
||||
/* RSCP range: 25 to 120 dBm as defined in 3GPP TS 25.123 */
|
||||
if (tdscdma_dbm >= 25 && tdscdma_dbm <= 120) {
|
||||
return ril_netreg_dbm_to_percentage(-tdscdma_dbm);
|
||||
}
|
||||
|
||||
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
|
||||
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
|
||||
return ril_netreg_dbm_to_percentage(-rsrp);
|
||||
}
|
||||
|
||||
/* If we've got zero strength and no valid RSRP, then so be it */
|
||||
if (gw_signal == 0) {
|
||||
if (signal.qdbm < 0) {
|
||||
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
|
||||
} else if (signal.gsm == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* In case of dbm, return the value directly */
|
||||
if (cdma_dbm != -1) {
|
||||
return MIN(cdma_dbm, 100);
|
||||
}
|
||||
|
||||
if (evdo_dbm != -1) {
|
||||
return MIN(evdo_dbm, 100);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
@@ -434,9 +538,11 @@ static void ril_netreg_strength_notify(GRilIoChannel *io, guint ril_event,
|
||||
int strength;
|
||||
|
||||
GASSERT(ril_event == RIL_UNSOL_SIGNAL_STRENGTH);
|
||||
strength = ril_netreg_get_signal_strength(data, len);
|
||||
strength = ril_netreg_get_signal_strength(nd, data, len);
|
||||
DBG_(nd, "%d", strength);
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
if (strength >= 0) {
|
||||
ofono_netreg_strength_notify(nd->netreg, strength);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
@@ -447,8 +553,8 @@ static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int strength = ril_netreg_get_signal_strength(data, len);
|
||||
cb(ril_error_ok(&error), strength, cbd->data);
|
||||
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
|
||||
(cbd->nd, data, len), cbd->data);
|
||||
} else {
|
||||
ofono_error("Failed to retrive the signal strength: %s",
|
||||
ril_error_to_string(status));
|
||||
@@ -558,9 +664,15 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
|
||||
DBG_(nd, "%p", netreg);
|
||||
nd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
nd->q = grilio_queue_new(nd->io);
|
||||
nd->watch = ofono_watch_new(ril_modem_get_path(modem));
|
||||
nd->vendor = ril_vendor_ref(modem->vendor);
|
||||
nd->network = ril_network_ref(modem->network);
|
||||
nd->netreg = netreg;
|
||||
nd->replace_strange_oper = config->replace_strange_oper;
|
||||
nd->network_selection_manual_0 = config->network_selection_manual_0;
|
||||
nd->signal_strength_dbm_weak = config->signal_strength_dbm_weak;
|
||||
nd->signal_strength_dbm_strong = config->signal_strength_dbm_strong;
|
||||
nd->network_selection_timeout = config->network_selection_timeout;
|
||||
|
||||
ofono_netreg_set_data(netreg, nd);
|
||||
nd->timer_id = g_idle_add(ril_netreg_register, nd);
|
||||
@@ -587,8 +699,10 @@ static void ril_netreg_remove(struct ofono_netreg *netreg)
|
||||
g_source_remove(nd->current_operator_id);
|
||||
}
|
||||
|
||||
ofono_watch_unref(nd->watch);
|
||||
ril_network_remove_all_handlers(nd->network, nd->network_event_id);
|
||||
ril_network_unref(nd->network);
|
||||
ril_vendor_unref(nd->vendor);
|
||||
|
||||
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
|
||||
grilio_channel_unref(nd->io);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -13,8 +14,11 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_network.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_radio_caps.h"
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_vendor.h"
|
||||
@@ -32,6 +36,7 @@
|
||||
#include <ofono/watch.h>
|
||||
#include <ofono/gprs.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
|
||||
#define SET_PREF_MODE_HOLDOFF_SEC RIL_RETRY_SECS
|
||||
@@ -51,6 +56,12 @@ enum ril_network_radio_event {
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_radio_caps_mgr_events {
|
||||
RADIO_CAPS_MGR_TX_DONE,
|
||||
RADIO_CAPS_MGR_TX_ABORTED,
|
||||
RADIO_CAPS_MGR_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_sim_events {
|
||||
SIM_EVENT_STATUS_CHANGED,
|
||||
SIM_EVENT_IO_ACTIVE_CHANGED,
|
||||
@@ -59,7 +70,6 @@ enum ril_network_sim_events {
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
@@ -87,6 +97,7 @@ struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_radio_caps *caps;
|
||||
struct ril_sim_card *simcard;
|
||||
struct ril_vendor *vendor;
|
||||
struct ofono_watch *watch;
|
||||
@@ -103,6 +114,8 @@ struct ril_network_priv {
|
||||
gulong set_rat_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong supported_modes_event_id;
|
||||
gulong caps_mgr_event_id[RADIO_CAPS_MGR_EVENT_COUNT];
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
gulong simcard_event_id[SIM_EVENT_COUNT];
|
||||
gulong watch_ids[WATCH_EVENT_COUNT];
|
||||
@@ -110,6 +123,7 @@ struct ril_network_priv {
|
||||
gboolean set_initial_attach_apn;
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
int mms_data_profile_id;
|
||||
GSList *data_profiles;
|
||||
@@ -121,7 +135,6 @@ enum ril_network_signal {
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
@@ -129,7 +142,6 @@ enum ril_network_signal {
|
||||
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
|
||||
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
|
||||
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -415,18 +427,30 @@ static void ril_network_poll_data_state_cb(GRilIoChannel *io, int req_status,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_network_retry(GRilIoRequest* request, int ril_status,
|
||||
const void* response_data, guint response_len, void* user_data)
|
||||
{
|
||||
switch (ril_status) {
|
||||
case RIL_E_SUCCESS:
|
||||
case RIL_E_RADIO_NOT_AVAILABLE:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_network_poll_and_retry(struct ril_network *self, guint id,
|
||||
int code, GRilIoChannelResponseFunc fn)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, id);
|
||||
} else {
|
||||
/* Don't wait for retry timeout to expire */
|
||||
if (!id || !grilio_channel_retry_request(priv->io, id)) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req, ril_network_retry);
|
||||
grilio_queue_cancel_request(priv->q, id, FALSE);
|
||||
id = grilio_queue_send_request_full(priv->q, req, code, fn,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -508,6 +532,17 @@ static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
}
|
||||
}
|
||||
|
||||
enum ofono_radio_access_mode ril_network_max_supported_mode
|
||||
(struct ril_network *self)
|
||||
{
|
||||
struct ril_sim_settings *settings = self->settings;
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const struct ril_radio_caps *caps = priv->caps;
|
||||
|
||||
return caps ? __ofono_radio_access_max_mode(caps->supported_modes) :
|
||||
__ofono_radio_access_max_mode(settings->techs);
|
||||
}
|
||||
|
||||
static enum ofono_radio_access_mode ril_network_actual_pref_mode
|
||||
(struct ril_network *self)
|
||||
{
|
||||
@@ -515,13 +550,12 @@ static enum ofono_radio_access_mode ril_network_actual_pref_mode
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
/*
|
||||
* On dual-SIM phones such as Jolla C only one slot at a time
|
||||
* is allowed to use LTE. Even if the slot which has been using
|
||||
* LTE gets powered off, we still need to explicitely set its
|
||||
* preferred mode to GSM, to make LTE machinery available to
|
||||
* the other slot. This sort of behaviour might not be necessary
|
||||
* on some hardware and can (should) be made configurable when
|
||||
* it becomes necessary.
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
@@ -532,9 +566,16 @@ static enum ofono_radio_access_mode ril_network_actual_pref_mode
|
||||
* and max_pref_mode are not ANY, we pick the smallest value.
|
||||
* Otherwise we take any non-zero value if there is one.
|
||||
*/
|
||||
return (settings->pref_mode && max_pref_mode) ?
|
||||
const enum ofono_radio_access_mode pref_mode =
|
||||
(settings->pref_mode && max_pref_mode) ?
|
||||
MIN(settings->pref_mode, max_pref_mode) :
|
||||
settings->pref_mode ? settings->pref_mode : max_pref_mode;
|
||||
|
||||
/* Do not try to set unsupported mode */
|
||||
const enum ofono_radio_access_mode max_mode =
|
||||
ril_network_max_supported_mode(self);
|
||||
|
||||
return pref_mode ? MIN(pref_mode, max_mode) : max_mode;
|
||||
}
|
||||
|
||||
static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
|
||||
@@ -545,9 +586,9 @@ static gboolean ril_network_need_initial_attach_apn(struct ril_network *self)
|
||||
|
||||
if (watch->gprs && radio->state == RADIO_STATE_ON) {
|
||||
switch (ril_network_actual_pref_mode(self)) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
return TRUE;
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
break;
|
||||
@@ -655,7 +696,7 @@ struct ril_network_data_profile *ril_network_data_profile_new
|
||||
ptr += G_ALIGN8(sizeof(*profile));
|
||||
|
||||
profile->profile_id = profile_id;
|
||||
profile->type = RIL_PROFILE_3GPP;
|
||||
profile->type = RIL_PROFILE_COMMON;
|
||||
profile->auth_method = auth_method;
|
||||
profile->proto = context->proto;
|
||||
profile->enabled = TRUE;
|
||||
@@ -784,6 +825,9 @@ static void ril_network_check_data_profiles(struct ril_network *self)
|
||||
const struct ofono_gprs_primary_context* mms =
|
||||
ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_MMS);
|
||||
const struct ofono_gprs_primary_context* ims =
|
||||
ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_IMS);
|
||||
GSList *l = NULL;
|
||||
|
||||
if (internet) {
|
||||
@@ -799,6 +843,12 @@ static void ril_network_check_data_profiles(struct ril_network *self)
|
||||
ril_network_data_profile_new(mms,
|
||||
priv->mms_data_profile_id));
|
||||
}
|
||||
if (ims) {
|
||||
DBG_(self, "ims apn \"%s\"", ims->apn);
|
||||
l = g_slist_append(l,
|
||||
ril_network_data_profile_new(ims,
|
||||
RIL_DATA_PROFILE_IMS));
|
||||
}
|
||||
|
||||
if (ril_network_data_profiles_equal(priv->data_profiles, l)) {
|
||||
ril_network_data_profiles_free(l);
|
||||
@@ -902,43 +952,64 @@ static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode expected_mode =
|
||||
ril_network_actual_pref_mode(self);
|
||||
const enum ofono_radio_access_mode current_mode =
|
||||
ril_network_rat_to_mode(priv->rat);
|
||||
struct ril_radio *radio = priv->radio;
|
||||
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self, TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
/*
|
||||
* On most dual-SIM phones only one slot at a time is allowed
|
||||
* to use LTE. On some phones (such as Jolla C), even if the
|
||||
* slot which has been using LTE gets powered off, we still
|
||||
* need to explicitly set its preferred mode to GSM, to make
|
||||
* LTE machinery available to the other slot. This behavior is
|
||||
* configurable.
|
||||
*/
|
||||
if (radio->state == RADIO_STATE_ON || priv->force_gsm_when_radio_off) {
|
||||
const enum ofono_radio_access_mode expected =
|
||||
ril_network_actual_pref_mode(self);
|
||||
const enum ofono_radio_access_mode actual =
|
||||
ril_network_rat_to_mode(priv->rat);
|
||||
|
||||
if (priv->rat >= 0 && current_mode != expected_mode) {
|
||||
DBG_(self, "rat %d (%s), expected %s", priv->rat,
|
||||
ofono_radio_access_mode_to_string(current_mode),
|
||||
ofono_radio_access_mode_to_string(expected_mode));
|
||||
}
|
||||
if (priv->timer[TIMER_FORCE_CHECK_PREF_MODE]) {
|
||||
ril_network_stop_timer(self,
|
||||
TIMER_FORCE_CHECK_PREF_MODE);
|
||||
/*
|
||||
* TIMER_FORCE_CHECK_PREF_MODE is scheduled by
|
||||
* ril_network_pref_mode_changed_cb and is meant
|
||||
* to force radio tech check right now.
|
||||
*/
|
||||
immediate = TRUE;
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
if (priv->rat >= 0 && actual != expected) {
|
||||
DBG_(self, "rat %d (%s), expected %s", priv->rat,
|
||||
ofono_radio_access_mode_to_string(actual),
|
||||
ofono_radio_access_mode_to_string(expected));
|
||||
}
|
||||
|
||||
if (current_mode != expected_mode || priv->assert_rat) {
|
||||
const int rat = ril_network_mode_to_rat(self, expected_mode);
|
||||
if (immediate) {
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
if (actual != expected || priv->assert_rat) {
|
||||
const int rat = ril_network_mode_to_rat(self, expected);
|
||||
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
/* OK, later */
|
||||
DBG_(self, "need to set rat mode %d", rat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_assert_pref_mode(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->assert_rat = TRUE;
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
|
||||
static int ril_network_parse_pref_resp(const void *data, guint len)
|
||||
{
|
||||
GRilIoParser rilp;
|
||||
@@ -968,10 +1039,10 @@ static void ril_network_startup_query_pref_mode_cb(GRilIoChannel *io,
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike ril_network_query_pref_mode_cb, this one always
|
||||
* checks the preferred mode.
|
||||
* At startup, the device may have an inconsistency between
|
||||
* voice and data network modes, so it needs to be asserted.
|
||||
*/
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
ril_network_assert_pref_mode(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,22 +1053,22 @@ static void ril_network_query_pref_mode_cb(GRilIoChannel *io, int status,
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
const enum ofono_radio_access_mode pref_mode = self->pref_mode;
|
||||
|
||||
/* This request never fails because in case of error it gets retried */
|
||||
GASSERT(status == RIL_E_SUCCESS);
|
||||
GASSERT(priv->query_rat_id);
|
||||
|
||||
priv->query_rat_id = 0;
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
priv->rat = ril_network_parse_pref_resp(data, len);
|
||||
self->pref_mode = ril_network_rat_to_mode(priv->rat);
|
||||
DBG_(self, "rat mode %d (%s)", priv->rat,
|
||||
ofono_radio_access_mode_to_string(self->pref_mode));
|
||||
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
if (self->pref_mode != pref_mode) {
|
||||
ril_network_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_check_pref_mode(self, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,6 +1078,7 @@ static void ril_network_query_pref_mode(struct ril_network *self)
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_retry_func(req, ril_network_retry);
|
||||
grilio_queue_cancel_request(priv->q, priv->query_rat_id, FALSE);
|
||||
priv->query_rat_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
|
||||
@@ -1023,19 +1095,79 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
DBG_(self, "rat mode %d (%s)", max_mode,
|
||||
ofono_radio_access_mode_to_string(max_mode));
|
||||
self->max_pref_mode = max_mode;
|
||||
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
|
||||
ril_network_check_initial_attach_apn(self);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
|
||||
static void ril_network_supported_modes_handler(struct ril_radio_caps *caps,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "%s", ofono_radio_access_mode_to_string
|
||||
(caps->supported_modes));
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
|
||||
static void ril_network_radio_capability_tx_done_cb
|
||||
(struct ril_radio_caps_manager *mgr, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_network_assert_pref_mode(self);
|
||||
}
|
||||
|
||||
static void ril_network_release_radio_caps(struct ril_network *self)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
struct ril_radio_caps *caps = priv->caps;
|
||||
|
||||
if (caps) {
|
||||
ril_radio_caps_manager_remove_all_handlers(caps->mgr,
|
||||
priv->caps_mgr_event_id);
|
||||
ril_radio_caps_remove_handler(caps,
|
||||
priv->supported_modes_event_id);
|
||||
ril_radio_caps_unref(caps);
|
||||
|
||||
priv->caps = NULL;
|
||||
priv->supported_modes_event_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_network_attach_radio_caps(struct ril_network *self,
|
||||
struct ril_radio_caps *caps)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->assert_rat = TRUE;
|
||||
ril_network_check_pref_mode(self, immediate);
|
||||
priv->caps = ril_radio_caps_ref(caps);
|
||||
priv->supported_modes_event_id =
|
||||
ril_radio_caps_add_supported_modes_handler(caps,
|
||||
ril_network_supported_modes_handler, self);
|
||||
priv->caps_mgr_event_id[RADIO_CAPS_MGR_TX_DONE] =
|
||||
ril_radio_caps_manager_add_tx_done_handler(caps->mgr,
|
||||
ril_network_radio_capability_tx_done_cb, self);
|
||||
priv->caps_mgr_event_id[RADIO_CAPS_MGR_TX_ABORTED] =
|
||||
ril_radio_caps_manager_add_tx_aborted_handler(caps->mgr,
|
||||
ril_network_radio_capability_tx_done_cb, self);
|
||||
}
|
||||
|
||||
void ril_network_set_radio_caps(struct ril_network *self,
|
||||
struct ril_radio_caps *caps)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
if (priv->caps != caps) {
|
||||
ril_network_release_radio_caps(self);
|
||||
if (caps) {
|
||||
ril_network_attach_radio_caps(self, caps);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
@@ -1066,13 +1198,6 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
@@ -1095,16 +1220,6 @@ static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
|
||||
guint code, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
|
||||
ril_network_assert_pref_mode(self, FALSE);
|
||||
}
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
@@ -1228,6 +1343,7 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
priv->lte_network_mode = config->lte_network_mode;
|
||||
priv->umts_network_mode = config->umts_network_mode;
|
||||
priv->network_mode_timeout = config->network_mode_timeout;
|
||||
priv->force_gsm_when_radio_off = config->force_gsm_when_radio_off;
|
||||
priv->use_data_profiles = config->use_data_profiles;
|
||||
priv->mms_data_profile_id = config->mms_data_profile_id;
|
||||
|
||||
@@ -1236,10 +1352,6 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
|
||||
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_radio_capability_changed_cb,
|
||||
RIL_UNSOL_RADIO_CAPABILITY, self);
|
||||
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
@@ -1334,6 +1446,7 @@ static void ril_network_finalize(GObject *object)
|
||||
grilio_channel_remove_all_handlers(priv->io, priv->unsol_event_id);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_network_release_radio_caps(self);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_all_handlers(priv->simcard, priv->simcard_event_id);
|
||||
@@ -1355,7 +1468,6 @@ static void ril_network_class_init(RilNetworkClass *klass)
|
||||
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
|
||||
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -21,6 +22,7 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
struct ril_radio_caps;
|
||||
|
||||
struct ril_registration_state {
|
||||
int status; /* enum network_registration_status */
|
||||
@@ -42,7 +44,6 @@ struct ril_network {
|
||||
struct ril_sim_settings *settings;
|
||||
};
|
||||
|
||||
struct ofono_sim;
|
||||
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
@@ -54,10 +55,13 @@ struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
|
||||
void ril_network_set_radio_caps(struct ril_network *net,
|
||||
struct ril_radio_caps *caps);
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||
enum ofono_radio_access_mode ril_network_max_supported_mode
|
||||
(struct ril_network *self);
|
||||
void ril_network_query_registration_state(struct ril_network *net);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
@@ -67,8 +71,6 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -32,6 +33,11 @@ struct ril_oem_raw {
|
||||
|
||||
#define DBG_(oem,fmt,args...) DBG("%s" fmt, (oem)->log_prefix, ##args)
|
||||
|
||||
static void ril_oem_raw_send_done(void *msg)
|
||||
{
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -40,20 +46,13 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
DBusMessageIter it, array;
|
||||
const guchar* bytes = data;
|
||||
guint i;
|
||||
|
||||
reply = dbus_message_new_method_return(msg);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BYTE_AS_STRING, &array);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
guchar byte = bytes[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
|
||||
&byte);
|
||||
}
|
||||
|
||||
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
|
||||
&data, len);
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
|
||||
DBG("Timed out");
|
||||
@@ -63,7 +62,7 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
|
||||
reply = __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
__ofono_dbus_pending_reply(&msg, reply);
|
||||
g_dbus_send_message(ofono_dbus_get_connection(), reply);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
@@ -72,6 +71,12 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
DBusMessageIter it;
|
||||
struct ril_oem_raw *oem = user_data;
|
||||
|
||||
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
|
||||
OFONO_DBUS_ACCESS_INTF_OEMRAW,
|
||||
OFONO_DBUS_ACCESS_OEMRAW_SEND, NULL)) {
|
||||
return __ofono_error_access_denied(msg);
|
||||
}
|
||||
|
||||
dbus_message_iter_init(msg, &it);
|
||||
if (dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY &&
|
||||
dbus_message_iter_get_element_type(&it) == DBUS_TYPE_BYTE) {
|
||||
@@ -94,7 +99,7 @@ static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
|
||||
grilio_request_append_bytes(req, data, data_len);
|
||||
grilio_queue_send_request_full(oem->q, req,
|
||||
RIL_REQUEST_OEM_HOOK_RAW, ril_oem_raw_send_cb,
|
||||
NULL, dbus_message_ref(msg));
|
||||
ril_oem_raw_send_done, dbus_message_ref(msg));
|
||||
grilio_request_unref(req);
|
||||
return NULL;
|
||||
} else {
|
||||
|
||||
@@ -998,8 +998,9 @@ static void ril_export_entries(struct ofono_phonebook *pb,
|
||||
pbd->df_path = usim_path;
|
||||
pbd->df_size = sizeof(usim_path);
|
||||
|
||||
ofono_sim_read(pbd->sim_context, SIM_EFPBR_FILEID,
|
||||
ofono_sim_read_path(pbd->sim_context, SIM_EFPBR_FILEID,
|
||||
OFONO_SIM_FILE_STRUCTURE_FIXED,
|
||||
pbd->df_path, pbd->df_size,
|
||||
pb_reference_data_cb, pb);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -27,7 +28,10 @@
|
||||
#include "ril_devmon.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sailfish_manager.h>
|
||||
#include "ofono.h"
|
||||
#include "sailfish_manager.h"
|
||||
|
||||
#include <ofono/storage.h>
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <grilio_transport.h>
|
||||
@@ -60,7 +64,7 @@
|
||||
|
||||
#define RIL_SUB_SIZE 4
|
||||
|
||||
#define RILMODEM_CONF_FILE CONFIGDIR "/ril_subscription.conf"
|
||||
#define RILMODEM_CONF_FILE "ril_subscription.conf"
|
||||
#define RILMODEM_DEFAULT_IDENTITY "radio:radio"
|
||||
#define RILMODEM_DEFAULT_SOCK "/dev/socket/rild"
|
||||
#define RILMODEM_DEFAULT_SOCK2 "/dev/socket/rild2"
|
||||
@@ -69,6 +73,9 @@
|
||||
#define RILMODEM_DEFAULT_LTE_MODE PREF_NET_TYPE_LTE_GSM_WCDMA
|
||||
#define RILMODEM_DEFAULT_UMTS_MODE PREF_NET_TYPE_GSM_WCDMA_AUTO
|
||||
#define RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT (20*1000) /* ms */
|
||||
#define RILMODEM_DEFAULT_NETWORK_SELECTION_TIMEOUT (100*1000) /* ms */
|
||||
#define RILMODEM_DEFAULT_DBM_WEAK (-100) /* very weak, 0.0000000001 mW */
|
||||
#define RILMODEM_DEFAULT_DBM_STRONG (-60) /* strong signal, 0.000001 mW */
|
||||
#define RILMODEM_DEFAULT_ENABLE_VOICECALL TRUE
|
||||
#define RILMODEM_DEFAULT_ENABLE_CBS TRUE
|
||||
#define RILMODEM_DEFAULT_ENABLE_STK TRUE
|
||||
@@ -76,7 +83,8 @@
|
||||
#define RILMODEM_DEFAULT_TIMEOUT 0 /* No timeout */
|
||||
#define RILMODEM_DEFAULT_SIM_FLAGS RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND
|
||||
#define RILMODEM_DEFAULT_DATA_OPT RIL_ALLOW_DATA_AUTO
|
||||
#define RILMODEM_DEFAULT_DM_FLAGS RIL_DATA_MANAGER_3GLTE_HANDOVER
|
||||
#define RILMODEM_DEFAULT_DM_FLAGS (RIL_DATA_MANAGER_3GLTE_HANDOVER | \
|
||||
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS)
|
||||
#define RILMODEM_DEFAULT_START_TIMEOUT 20000 /* ms */
|
||||
#define RILMODEM_DEFAULT_DATA_CALL_FORMAT RIL_DATA_CALL_FORMAT_AUTO
|
||||
#define RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT 4
|
||||
@@ -86,10 +94,14 @@
|
||||
#define RILMODEM_DEFAULT_LEGACY_IMEI_QUERY FALSE
|
||||
#define RILMODEM_DEFAULT_RADIO_POWER_CYCLE TRUE
|
||||
#define RILMODEM_DEFAULT_CONFIRM_RADIO_POWER_ON TRUE
|
||||
#define RILMODEM_DEFAULT_REPLACE_STRANGE_OPER FALSE
|
||||
#define RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0 TRUE
|
||||
#define RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF TRUE
|
||||
#define RILMODEM_DEFAULT_USE_DATA_PROFILES FALSE
|
||||
#define RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID RIL_DATA_PROFILE_IMS
|
||||
#define RILMODEM_DEFAULT_SLOT_FLAGS SAILFISH_SLOT_NO_FLAGS
|
||||
#define RILMODEM_DEFAULT_CELL_INFO_INTERVAL_SHORT_MS (2000) /* 2 sec */
|
||||
#define RILMODEM_DEFAULT_CELL_INFO_INTERVAL_LONG_MS (30000) /* 30 sec */
|
||||
|
||||
/* RIL socket transport name and parameters */
|
||||
#define RIL_TRANSPORT_MODEM "modem"
|
||||
@@ -106,6 +118,7 @@
|
||||
#define RILCONF_SETTINGS_EMPTY "EmptyConfig"
|
||||
#define RILCONF_SETTINGS_IDENTITY "Identity"
|
||||
#define RILCONF_SETTINGS_3GHANDOVER "3GLTEHandover"
|
||||
#define RILCONF_SETTINGS_GSM_NON_DATA_SLOTS "ForceGsmForNonDataSlots"
|
||||
#define RILCONF_SETTINGS_SET_RADIO_CAP "SetRadioCapability"
|
||||
|
||||
#define RILCONF_MODEM_PREFIX "ril_"
|
||||
@@ -125,6 +138,8 @@
|
||||
#define RILCONF_LTE_MODE "lteNetworkMode"
|
||||
#define RILCONF_UMTS_MODE "umtsNetworkMode"
|
||||
#define RILCONF_NETWORK_MODE_TIMEOUT "networkModeTimeout"
|
||||
#define RILCONF_NETWORK_SELECTION_TIMEOUT "networkSelectionTimeout"
|
||||
#define RILCONF_SIGNAL_STRENGTH_RANGE "signalStrengthRange"
|
||||
#define RILCONF_UICC_WORKAROUND "uiccWorkaround"
|
||||
#define RILCONF_ECCLIST_FILE "ecclistFile"
|
||||
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
|
||||
@@ -139,10 +154,14 @@
|
||||
#define RILCONF_RADIO_POWER_CYCLE "radioPowerCycle"
|
||||
#define RILCONF_CONFIRM_RADIO_POWER_ON "confirmRadioPowerOn"
|
||||
#define RILCONF_SINGLE_DATA_CONTEXT "singleDataContext"
|
||||
#define RILCONF_REPLACE_STRANGE_OPER "replaceStrangeOperatorNames"
|
||||
#define RILCONF_NETWORK_SELECTION_MANUAL_0 "networkSelectionManual0"
|
||||
#define RILCONF_FORCE_GSM_WHEN_RADIO_OFF "forceGsmWhenRadioOff"
|
||||
#define RILCONF_USE_DATA_PROFILES "useDataProfiles"
|
||||
#define RILCONF_MMS_DATA_PROFILE_ID "mmsDataProfileId"
|
||||
#define RILCONF_DEVMON "deviceStateTracking"
|
||||
#define RILCONF_CELL_INFO_INTERVAL_SHORT_MS "cellInfoIntervalShortMs"
|
||||
#define RILCONF_CELL_INFO_INTERVAL_LONG_MS "cellInfoIntervalLongMs"
|
||||
|
||||
/* Modem error ids */
|
||||
#define RIL_ERROR_ID_RILD_RESTART "rild-restart"
|
||||
@@ -168,10 +187,9 @@ enum ril_set_radio_cap_opt {
|
||||
};
|
||||
|
||||
enum ril_devmon_opt {
|
||||
RIL_DEVMON_NONE,
|
||||
RIL_DEVMON_AUTO,
|
||||
RIL_DEVMON_SS,
|
||||
RIL_DEVMON_DS
|
||||
RIL_DEVMON_SS = 0x01,
|
||||
RIL_DEVMON_DS = 0x02,
|
||||
RIL_DEVMON_UR = 0x04
|
||||
};
|
||||
|
||||
struct ril_plugin_identity {
|
||||
@@ -216,6 +234,7 @@ typedef struct sailfish_slot_impl {
|
||||
struct ril_modem *modem;
|
||||
struct ril_radio *radio;
|
||||
struct ril_radio_caps *caps;
|
||||
struct ril_radio_caps_request *caps_req;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
@@ -352,6 +371,7 @@ static void ril_plugin_remove_slot_handler(ril_slot *slot, int id)
|
||||
static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
|
||||
{
|
||||
if (slot->modem) {
|
||||
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
|
||||
ril_modem_delete(slot->modem);
|
||||
/* The above call is expected to result in
|
||||
* ril_plugin_modem_removed getting called
|
||||
@@ -371,12 +391,16 @@ static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
|
||||
}
|
||||
|
||||
if (slot->cell_info) {
|
||||
sailfish_manager_set_cell_info(slot->handle, NULL);
|
||||
sailfish_cell_info_unref(slot->cell_info);
|
||||
slot->cell_info = NULL;
|
||||
}
|
||||
|
||||
if (slot->caps) {
|
||||
ril_radio_caps_unref(slot->caps);
|
||||
ril_network_set_radio_caps(slot->network, NULL);
|
||||
ril_radio_caps_request_free(slot->caps_req);
|
||||
ril_radio_caps_drop(slot->caps);
|
||||
slot->caps_req = NULL;
|
||||
slot->caps = NULL;
|
||||
}
|
||||
|
||||
@@ -833,7 +857,7 @@ static void ril_plugin_create_modem(ril_slot *slot)
|
||||
modem = ril_modem_create(slot->io, log_prefix, slot->path, slot->imei,
|
||||
slot->imeisv, slot->ecclist_file, &slot->config, slot->radio,
|
||||
slot->network, slot->sim_card, slot->data, slot->sim_settings,
|
||||
slot->cell_info);
|
||||
slot->vendor, slot->cell_info);
|
||||
|
||||
if (modem) {
|
||||
slot->modem = modem;
|
||||
@@ -890,7 +914,7 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
|
||||
plugin->caps_manager = ril_radio_caps_manager_new
|
||||
(plugin->data_manager);
|
||||
plugin->caps_manager_event_id =
|
||||
ril_radio_caps_manager_add_aborted_handler(
|
||||
ril_radio_caps_manager_add_tx_aborted_handler(
|
||||
plugin->caps_manager,
|
||||
ril_plugin_caps_switch_aborted,
|
||||
plugin);
|
||||
@@ -898,15 +922,17 @@ static void ril_plugin_radio_caps_cb(const struct ril_radio_capability *cap,
|
||||
|
||||
GASSERT(!slot->caps);
|
||||
slot->caps = ril_radio_caps_new(plugin->caps_manager,
|
||||
ril_plugin_log_prefix(slot), slot->io, slot->data,
|
||||
slot->radio, slot->sim_card, slot->network,
|
||||
&slot->config, cap);
|
||||
ril_plugin_log_prefix(slot), slot->io, slot->watch,
|
||||
slot->data, slot->radio, slot->sim_card,
|
||||
slot->sim_settings, &slot->config, cap);
|
||||
ril_network_set_radio_caps(slot->network, slot->caps);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_manager_started(ril_plugin *plugin)
|
||||
{
|
||||
ril_plugin_drop_orphan_slots(plugin);
|
||||
ril_data_manager_check_data(plugin->data_manager);
|
||||
sailfish_slot_manager_started(plugin->handle);
|
||||
}
|
||||
|
||||
@@ -1027,13 +1053,13 @@ static void ril_plugin_slot_connected(ril_slot *slot)
|
||||
slot->path, slot->config.techs, slot->imei,
|
||||
slot->imeisv, ril_plugin_sim_state(slot),
|
||||
slot->slot_flags);
|
||||
sailfish_manager_set_cell_info(slot->handle, slot->cell_info);
|
||||
grilio_channel_set_enabled(slot->io, slot->handle->enabled);
|
||||
|
||||
/* Check if this was the last slot we were waiting for */
|
||||
ril_plugin_check_if_started(plugin);
|
||||
}
|
||||
|
||||
sailfish_manager_set_cell_info(slot->handle, slot->cell_info);
|
||||
ril_plugin_check_modem(slot);
|
||||
ril_plugin_check_ready(slot);
|
||||
}
|
||||
@@ -1049,8 +1075,11 @@ static void ril_plugin_slot_connected_cb(GRilIoChannel *io, void *user_data)
|
||||
static void ril_plugin_init_io(ril_slot *slot)
|
||||
{
|
||||
if (!slot->io) {
|
||||
slot->io = grilio_channel_new(ofono_ril_transport_connect
|
||||
(slot->transport_name, slot->transport_params));
|
||||
struct grilio_transport *transport =
|
||||
ofono_ril_transport_connect(slot->transport_name,
|
||||
slot->transport_params);
|
||||
|
||||
slot->io = grilio_channel_new(transport);
|
||||
if (slot->io) {
|
||||
ril_debug_trace_update(slot);
|
||||
ril_debug_dump_update(slot);
|
||||
@@ -1082,6 +1111,7 @@ static void ril_plugin_init_io(ril_slot *slot)
|
||||
slot);
|
||||
}
|
||||
}
|
||||
grilio_transport_unref(transport);
|
||||
}
|
||||
|
||||
if (!slot->io) {
|
||||
@@ -1127,6 +1157,8 @@ static void ril_plugin_slot_modem_changed(struct ofono_watch *w,
|
||||
|
||||
slot->modem = NULL;
|
||||
ril_data_allow(slot->data, RIL_DATA_ROLE_NONE);
|
||||
ril_radio_caps_request_free(slot->caps_req);
|
||||
slot->caps_req = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1181,6 +1213,11 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
config->techs = RILMODEM_DEFAULT_TECHS;
|
||||
config->lte_network_mode = RILMODEM_DEFAULT_LTE_MODE;
|
||||
config->umts_network_mode = RILMODEM_DEFAULT_UMTS_MODE;
|
||||
config->network_mode_timeout = RILMODEM_DEFAULT_NETWORK_MODE_TIMEOUT;
|
||||
config->network_selection_timeout =
|
||||
RILMODEM_DEFAULT_NETWORK_SELECTION_TIMEOUT;
|
||||
config->signal_strength_dbm_weak = RILMODEM_DEFAULT_DBM_WEAK;
|
||||
config->signal_strength_dbm_strong = RILMODEM_DEFAULT_DBM_STRONG;
|
||||
config->empty_pin_query = RILMODEM_DEFAULT_EMPTY_PIN_QUERY;
|
||||
config->radio_power_cycle = RILMODEM_DEFAULT_RADIO_POWER_CYCLE;
|
||||
config->confirm_radio_power_on =
|
||||
@@ -1190,10 +1227,17 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
config->enable_stk = RILMODEM_DEFAULT_ENABLE_STK;
|
||||
config->query_available_band_mode =
|
||||
RILMODEM_DEFAULT_QUERY_AVAILABLE_BAND_MODE;
|
||||
config->replace_strange_oper = RILMODEM_DEFAULT_REPLACE_STRANGE_OPER;
|
||||
config->network_selection_manual_0 =
|
||||
RILMODEM_DEFAULT_NETWORK_SELECTION_MANUAL_0;
|
||||
config->force_gsm_when_radio_off =
|
||||
RILMODEM_DEFAULT_FORCE_GSM_WHEN_RADIO_OFF;
|
||||
config->use_data_profiles = RILMODEM_DEFAULT_USE_DATA_PROFILES;
|
||||
config->mms_data_profile_id = RILMODEM_DEFAULT_MMS_DATA_PROFILE_ID;
|
||||
config->cell_info_interval_short_ms =
|
||||
RILMODEM_DEFAULT_CELL_INFO_INTERVAL_SHORT_MS;
|
||||
config->cell_info_interval_long_ms =
|
||||
RILMODEM_DEFAULT_CELL_INFO_INTERVAL_LONG_MS;
|
||||
slot->timeout = RILMODEM_DEFAULT_TIMEOUT;
|
||||
slot->sim_flags = RILMODEM_DEFAULT_SIM_FLAGS;
|
||||
slot->slot_flags = RILMODEM_DEFAULT_SLOT_FLAGS;
|
||||
@@ -1205,8 +1249,7 @@ static ril_slot *ril_plugin_slot_new_take(char *transport,
|
||||
RILMODEM_DEFAULT_DATA_CALL_RETRY_LIMIT;
|
||||
slot->data_opt.data_call_retry_delay_ms =
|
||||
RILMODEM_DEFAULT_DATA_CALL_RETRY_DELAY;
|
||||
|
||||
slot->devmon = ril_devmon_auto_new();
|
||||
slot->devmon = ril_devmon_auto_new(config);
|
||||
slot->watch = ofono_watch_new(dbus_path);
|
||||
slot->watch_event_id[WATCH_EVENT_MODEM] =
|
||||
ofono_watch_add_modem_changed_handler(slot->watch,
|
||||
@@ -1228,6 +1271,9 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
defaults.empty_pin_query = config->empty_pin_query;
|
||||
defaults.mms_data_profile_id = config->mms_data_profile_id;
|
||||
defaults.use_data_profiles = config->use_data_profiles;
|
||||
defaults.replace_strange_oper = config->replace_strange_oper;
|
||||
defaults.force_gsm_when_radio_off =
|
||||
config->force_gsm_when_radio_off;
|
||||
defaults.query_available_band_mode =
|
||||
config->query_available_band_mode;
|
||||
|
||||
@@ -1238,6 +1284,9 @@ static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
|
||||
config->empty_pin_query = defaults.empty_pin_query;
|
||||
config->use_data_profiles = defaults.use_data_profiles;
|
||||
config->mms_data_profile_id = defaults.mms_data_profile_id;
|
||||
config->replace_strange_oper = defaults.replace_strange_oper;
|
||||
config->force_gsm_when_radio_off =
|
||||
defaults.force_gsm_when_radio_off;
|
||||
config->query_available_band_mode =
|
||||
defaults.query_available_band_mode;
|
||||
}
|
||||
@@ -1347,6 +1396,7 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
char *sval;
|
||||
char **strv;
|
||||
char *modem;
|
||||
GUtilInts *ints;
|
||||
GHashTable *transport_params = g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, g_free);
|
||||
char *transport = NULL;
|
||||
@@ -1458,6 +1508,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->enable_stk ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* replaceStrangeOperatorNames */
|
||||
if (ril_config_get_boolean(file, group,
|
||||
RILCONF_REPLACE_STRANGE_OPER,
|
||||
&config->replace_strange_oper)) {
|
||||
DBG("%s: " RILCONF_REPLACE_STRANGE_OPER " %s", group,
|
||||
config->replace_strange_oper ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* networkSelectionManual0 */
|
||||
if (ril_config_get_boolean(file, group,
|
||||
RILCONF_NETWORK_SELECTION_MANUAL_0,
|
||||
@@ -1466,6 +1524,14 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->network_selection_manual_0 ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* forceGsmWhenRadioOff */
|
||||
if (ril_config_get_boolean(file, group,
|
||||
RILCONF_FORCE_GSM_WHEN_RADIO_OFF,
|
||||
&config->force_gsm_when_radio_off)) {
|
||||
DBG("%s: " RILCONF_FORCE_GSM_WHEN_RADIO_OFF " %s", group,
|
||||
config->force_gsm_when_radio_off ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* useDataProfiles */
|
||||
if (ril_config_get_boolean(file, group, RILCONF_USE_DATA_PROFILES,
|
||||
&config->use_data_profiles)) {
|
||||
@@ -1536,6 +1602,29 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
config->network_mode_timeout);
|
||||
}
|
||||
|
||||
/* networkSelectionTimeout */
|
||||
if (ril_config_get_integer(file, group,
|
||||
RILCONF_NETWORK_SELECTION_TIMEOUT,
|
||||
&config->network_selection_timeout)) {
|
||||
DBG("%s: " RILCONF_NETWORK_SELECTION_TIMEOUT " %d", group,
|
||||
config->network_selection_timeout);
|
||||
}
|
||||
|
||||
/* signalStrengthRange */
|
||||
ints = ril_config_get_ints(file, group, RILCONF_SIGNAL_STRENGTH_RANGE);
|
||||
if (gutil_ints_get_count(ints) == 2) {
|
||||
const int* dbms = gutil_ints_get_data(ints, NULL);
|
||||
|
||||
/* MIN,MAX */
|
||||
if (dbms[0] < dbms[1]) {
|
||||
DBG("%s: " RILCONF_SIGNAL_STRENGTH_RANGE " [%d,%d]",
|
||||
group, dbms[0], dbms[1]);
|
||||
config->signal_strength_dbm_weak = dbms[0];
|
||||
config->signal_strength_dbm_strong = dbms[1];
|
||||
}
|
||||
}
|
||||
gutil_ints_unref(ints);
|
||||
|
||||
/* enable4G (deprecated but still supported) */
|
||||
ival = config->techs;
|
||||
if (ril_config_get_flag(file, group, RILCONF_4G,
|
||||
@@ -1660,24 +1749,59 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
|
||||
slot->legacy_imei_query ? "on" : "off");
|
||||
}
|
||||
|
||||
/* cellInfoIntervalShortMs */
|
||||
if (ril_config_get_integer(file, group,
|
||||
RILCONF_CELL_INFO_INTERVAL_SHORT_MS,
|
||||
&config->cell_info_interval_short_ms)) {
|
||||
DBG("%s: " RILCONF_CELL_INFO_INTERVAL_SHORT_MS " %d", group,
|
||||
config->cell_info_interval_short_ms);
|
||||
}
|
||||
|
||||
/* cellInfoIntervalLongMs */
|
||||
if (ril_config_get_integer(file, group,
|
||||
RILCONF_CELL_INFO_INTERVAL_LONG_MS,
|
||||
&config->cell_info_interval_long_ms)) {
|
||||
DBG("%s: " RILCONF_CELL_INFO_INTERVAL_LONG_MS " %d",
|
||||
group, config->cell_info_interval_long_ms);
|
||||
}
|
||||
|
||||
/* Replace devmon with a new one with applied settings */
|
||||
ril_devmon_free(slot->devmon);
|
||||
slot->devmon = NULL;
|
||||
|
||||
/* deviceStateTracking */
|
||||
if (ril_config_get_enum(file, group, RILCONF_DEVMON, &ival,
|
||||
"none", RIL_DEVMON_NONE,
|
||||
"auto", RIL_DEVMON_AUTO,
|
||||
if (ril_config_get_mask(file, group, RILCONF_DEVMON, &ival,
|
||||
"ds", RIL_DEVMON_DS,
|
||||
"ss", RIL_DEVMON_SS, NULL)) {
|
||||
DBG("%s: " RILCONF_DEVMON " %s", group,
|
||||
ival == RIL_DEVMON_NONE ? "off" :
|
||||
ival == RIL_DEVMON_DS ? "on" :
|
||||
ival == RIL_DEVMON_SS ? "legacy" :
|
||||
"auto");
|
||||
if (ival != RIL_DEVMON_AUTO) {
|
||||
/* Default is automatic, reallocate the object */
|
||||
ril_devmon_free(slot->devmon);
|
||||
slot->devmon =
|
||||
(ival == RIL_DEVMON_DS ? ril_devmon_ds_new() :
|
||||
ival == RIL_DEVMON_SS ? ril_devmon_ss_new() :
|
||||
NULL);
|
||||
"ss", RIL_DEVMON_SS,
|
||||
"ur", RIL_DEVMON_UR, NULL) && ival) {
|
||||
int n = 0;
|
||||
struct ril_devmon *devmon[3];
|
||||
|
||||
if (ival & RIL_DEVMON_DS) {
|
||||
devmon[n++] = ril_devmon_ds_new(config);
|
||||
}
|
||||
if (ival & RIL_DEVMON_SS) {
|
||||
devmon[n++] = ril_devmon_ss_new(config);
|
||||
}
|
||||
if (ival & RIL_DEVMON_UR) {
|
||||
devmon[n++] = ril_devmon_ur_new(config);
|
||||
}
|
||||
DBG("%s: " RILCONF_DEVMON " 0x%x", group, ival);
|
||||
slot->devmon = ril_devmon_combine(devmon, n);
|
||||
} else {
|
||||
/* Try special values */
|
||||
sval = ril_config_get_string(file, group, RILCONF_DEVMON);
|
||||
if (sval) {
|
||||
if (!g_ascii_strcasecmp(sval, "none")) {
|
||||
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
|
||||
} else if (!g_ascii_strcasecmp(sval, "auto")) {
|
||||
DBG("%s: " RILCONF_DEVMON " %s", group, sval);
|
||||
slot->devmon = ril_devmon_auto_new(config);
|
||||
}
|
||||
g_free(sval);
|
||||
} else {
|
||||
/* This is the default */
|
||||
slot->devmon = ril_devmon_auto_new(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1817,6 +1941,12 @@ static GSList *ril_plugin_parse_config_file(GKeyFile *file,
|
||||
RIL_DATA_MANAGER_3GLTE_HANDOVER,
|
||||
&ps->dm_flags);
|
||||
|
||||
/* ForceGsmForNonDataSlots */
|
||||
ril_config_get_flag(file, group,
|
||||
RILCONF_SETTINGS_GSM_NON_DATA_SLOTS,
|
||||
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS,
|
||||
&ps->dm_flags);
|
||||
|
||||
/* SetRadioCapability */
|
||||
if (ril_config_get_enum(file, group,
|
||||
RILCONF_SETTINGS_SET_RADIO_CAP, &ival,
|
||||
@@ -1856,7 +1986,7 @@ static GSList *ril_plugin_load_config(const char *path,
|
||||
GKeyFile *file = g_key_file_new();
|
||||
gboolean empty = FALSE;
|
||||
|
||||
ril_config_merge_files(file, path);
|
||||
config_merge_files(file, path);
|
||||
if (ril_config_get_boolean(file, RILCONF_SETTINGS_GROUP,
|
||||
RILCONF_SETTINGS_EMPTY, &empty) && empty) {
|
||||
DBG("Empty config");
|
||||
@@ -2042,12 +2172,15 @@ static guint ril_plugin_manager_start(ril_plugin *plugin)
|
||||
{
|
||||
struct ril_plugin_settings *ps = &plugin->settings;
|
||||
guint start_timeout = 0;
|
||||
char* config_file = g_build_filename(ofono_config_dir(),
|
||||
RILMODEM_CONF_FILE, NULL);
|
||||
|
||||
DBG("");
|
||||
GASSERT(!plugin->start_timeout_id);
|
||||
plugin->slots = ril_plugin_load_config(RILMODEM_CONF_FILE, ps);
|
||||
plugin->slots = ril_plugin_load_config(config_file, ps);
|
||||
plugin->data_manager = ril_data_manager_new(ps->dm_flags);
|
||||
ril_plugin_init_slots(plugin);
|
||||
g_free(config_file);
|
||||
|
||||
ofono_modem_driver_register(&ril_modem_driver);
|
||||
ofono_sim_driver_register(&ril_sim_driver);
|
||||
@@ -2099,10 +2232,24 @@ static void ril_plugin_manager_free(ril_plugin *plugin)
|
||||
|
||||
static void ril_slot_set_data_role(ril_slot *slot, enum sailfish_data_role r)
|
||||
{
|
||||
ril_data_allow(slot->data,
|
||||
enum ril_data_role role =
|
||||
(r == SAILFISH_DATA_ROLE_INTERNET) ? RIL_DATA_ROLE_INTERNET :
|
||||
(r == SAILFISH_DATA_ROLE_MMS) ? RIL_DATA_ROLE_MMS :
|
||||
RIL_DATA_ROLE_NONE);
|
||||
RIL_DATA_ROLE_NONE;
|
||||
ril_data_allow(slot->data, role);
|
||||
ril_radio_caps_request_free(slot->caps_req);
|
||||
if (role == RIL_DATA_ROLE_NONE) {
|
||||
slot->caps_req = NULL;
|
||||
} else {
|
||||
const enum ofono_radio_access_mode mode =
|
||||
(r == SAILFISH_DATA_ROLE_MMS) ?
|
||||
OFONO_RADIO_ACCESS_MODE_GSM :
|
||||
__ofono_radio_access_max_mode
|
||||
(slot->sim_settings->techs);
|
||||
|
||||
slot->caps_req = ril_radio_caps_request_new
|
||||
(slot->caps, mode, role);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_slot_enabled_changed(struct sailfish_slot_impl *s)
|
||||
@@ -2222,7 +2369,6 @@ static int ril_plugin_init(void)
|
||||
static void ril_plugin_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
GASSERT(ril_driver);
|
||||
|
||||
ofono_ril_transport_unregister(&ril_socket_transport);
|
||||
ofono_modem_driver_unregister(&ril_modem_driver);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -52,6 +53,7 @@ struct ril_modem {
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_vendor *vendor;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
@@ -70,7 +72,7 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct ril_sim_settings *settings, struct ril_vendor *vendor,
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
@@ -239,7 +241,19 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
|
||||
void ril_radio_confirm_power_on(struct ril_radio *self)
|
||||
{
|
||||
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
|
||||
ril_radio_power_request(self, TRUE, TRUE);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_id) {
|
||||
if (!priv->next_state) {
|
||||
/* Wait for the pending request to complete */
|
||||
priv->next_state_valid = TRUE;
|
||||
priv->next_state = TRUE;
|
||||
DBG_(self, "on (queued)");
|
||||
}
|
||||
} else {
|
||||
DBG_(self, "on");
|
||||
ril_radio_submit_power_request(self, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -19,12 +19,16 @@
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_sim_settings;
|
||||
struct ril_radio_caps;
|
||||
struct ril_radio_caps_manager;
|
||||
struct ril_radio_capability;
|
||||
struct ril_radio_caps_request;
|
||||
|
||||
typedef void (*ril_radio_caps_cb_t)(struct ril_radio_caps *caps, void *arg);
|
||||
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
|
||||
void *user_data);
|
||||
|
||||
/* ril_radio_capability pointer is NULL if functionality is unsupported */
|
||||
typedef void (*ril_radio_caps_check_cb_t)
|
||||
(const struct ril_radio_capability *cap, void *user_data);
|
||||
@@ -39,21 +43,47 @@ struct ril_radio_caps_manager *ril_radio_caps_manager_new
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
|
||||
(struct ril_radio_caps_manager *mgr);
|
||||
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
|
||||
gulong ril_radio_caps_manager_add_aborted_handler
|
||||
gulong ril_radio_caps_manager_add_tx_aborted_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
gulong ril_radio_caps_manager_add_tx_done_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
|
||||
gulong id);
|
||||
gulong id);
|
||||
void ril_radio_caps_manager_remove_handlers(struct ril_radio_caps_manager *mgr,
|
||||
gulong *ids, int count);
|
||||
#define ril_radio_caps_manager_remove_all_handlers(mgr, ids) \
|
||||
ril_radio_caps_manager_remove_handlers(mgr, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
/* And one ril_radio_caps object per modem */
|
||||
|
||||
struct ril_radio_caps {
|
||||
struct ril_radio_caps_manager *mgr;
|
||||
enum ofono_radio_access_mode supported_modes;
|
||||
};
|
||||
|
||||
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
const char *log_prefix, GRilIoChannel *io,
|
||||
struct ofono_watch *watch,
|
||||
struct ril_data *data, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim, struct ril_network *net,
|
||||
struct ril_sim_card *sim, struct ril_sim_settings *settings,
|
||||
const struct ril_slot_config *config,
|
||||
const struct ril_radio_capability *cap);
|
||||
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_unref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_drop(struct ril_radio_caps *caps);
|
||||
gulong ril_radio_caps_add_supported_modes_handler
|
||||
(struct ril_radio_caps *caps,
|
||||
ril_radio_caps_cb_t cb, void *arg);
|
||||
void ril_radio_caps_remove_handler(struct ril_radio_caps *caps, gulong id);
|
||||
|
||||
/* Data requests */
|
||||
|
||||
struct ril_radio_caps_request *ril_radio_caps_request_new
|
||||
(struct ril_radio_caps *caps, enum ofono_radio_access_mode mode,
|
||||
enum ril_data_role role);
|
||||
void ril_radio_caps_request_free(struct ril_radio_caps_request *req);
|
||||
|
||||
#endif /* RIL_RADIO_CAPS_H */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include "simutil.h"
|
||||
#include "util.h"
|
||||
#include "ofono.h"
|
||||
@@ -86,6 +88,7 @@ struct ril_sim {
|
||||
gboolean empty_pin_query_allowed;
|
||||
gboolean inserted;
|
||||
guint idle_id; /* Used by register and SIM reset callbacks */
|
||||
guint list_apps_id;
|
||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||
gulong io_event_id[IO_EVENT_COUNT];
|
||||
guint query_pin_retries_id;
|
||||
@@ -118,12 +121,25 @@ struct ril_sim_cbd_io {
|
||||
ofono_sim_write_cb_t write;
|
||||
ofono_sim_imsi_cb_t imsi;
|
||||
ofono_query_facility_lock_cb_t query_facility_lock;
|
||||
ofono_sim_open_channel_cb_t open_channel;
|
||||
ofono_sim_close_channel_cb_t close_channel;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
guint req_id;
|
||||
};
|
||||
|
||||
struct ril_sim_session_cbd {
|
||||
struct ril_sim *sd;
|
||||
struct ril_sim_card *card;
|
||||
ofono_sim_logical_access_cb_t cb;
|
||||
gpointer data;
|
||||
int ref_count;
|
||||
int session_id;
|
||||
int cla;
|
||||
guint req_id;
|
||||
};
|
||||
|
||||
struct ril_sim_pin_cbd {
|
||||
struct ril_sim *sd;
|
||||
ofono_sim_lock_unlock_cb_t cb;
|
||||
@@ -150,6 +166,16 @@ struct ril_sim_retry_query {
|
||||
GRilIoRequest *(*new_req)(struct ril_sim *sd);
|
||||
};
|
||||
|
||||
/* TS 102.221 */
|
||||
#define APP_TEMPLATE_TAG 0x61
|
||||
#define APP_ID_TAG 0x4F
|
||||
|
||||
struct ril_sim_list_apps {
|
||||
struct ril_sim *sd;
|
||||
ofono_sim_list_apps_cb_t cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
|
||||
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
|
||||
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
|
||||
@@ -218,6 +244,45 @@ static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
}
|
||||
|
||||
static struct ril_sim_session_cbd *ril_sim_session_cbd_new(struct ril_sim *sd,
|
||||
int session_id, int cla, ofono_sim_logical_access_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = g_new0(struct ril_sim_session_cbd, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
cbd->card = ril_sim_card_ref(sd->card);
|
||||
cbd->session_id = session_id;
|
||||
cbd->cla = cla;
|
||||
cbd->ref_count = 1;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sim_session_cbd_unref(void *data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = data;
|
||||
|
||||
if (--(cbd->ref_count) < 1) {
|
||||
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
|
||||
ril_sim_card_unref(cbd->card);
|
||||
g_free(cbd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_session_cbd_start(struct ril_sim_session_cbd *cbd,
|
||||
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
const guint finished_req = cbd->req_id;
|
||||
|
||||
cbd->ref_count++;
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code, cb,
|
||||
ril_sim_session_cbd_unref, cbd);
|
||||
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
|
||||
ril_sim_card_sim_io_finished(cbd->card, finished_req);
|
||||
}
|
||||
|
||||
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
@@ -307,30 +372,13 @@ static void ril_sim_append_path(struct ril_sim *sd, GRilIoRequest *req,
|
||||
grilio_request_append_utf8(req, hex_path);
|
||||
DBG_(sd, "%s", hex_path);
|
||||
g_free(hex_path);
|
||||
} else if (fileid == SIM_EF_ICCID_FILEID || fileid == SIM_EFPL_FILEID) {
|
||||
/*
|
||||
* Special catch-all for EF_ICCID (unique card ID)
|
||||
* and EF_PL files which exist in the root directory.
|
||||
* As the sim_info_cb function may not have yet
|
||||
* recorded the app_type for the SIM, and the path
|
||||
* for both files is the same for 2g|3g, just hard-code.
|
||||
*
|
||||
* See 'struct ef_db' in:
|
||||
* ../../src/simutil.c for more details.
|
||||
*/
|
||||
DBG_(sd, "%s", ROOTMF);
|
||||
grilio_request_append_utf8(req, ROOTMF);
|
||||
} else {
|
||||
/*
|
||||
* The only known case of this is EFPHASE_FILED (0x6FAE).
|
||||
* The ef_db table ( see /src/simutil.c ) entry for
|
||||
* EFPHASE contains a value of 0x0000 for it's
|
||||
* 'parent3g' member. This causes a NULL path to
|
||||
* be returned.
|
||||
* Catch-all for EF_ICCID, EF_PL and other files absent
|
||||
* from ef_db table in src/simutil.c, hard-code ROOTMF.
|
||||
*/
|
||||
|
||||
DBG_(sd, "returning empty path.");
|
||||
grilio_request_append_utf8(req, NULL);
|
||||
DBG_(sd, "%s (default)", ROOTMF);
|
||||
grilio_request_append_utf8(req, ROOTMF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1131,9 +1179,9 @@ static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
|
||||
} else {
|
||||
DBG_(sd, "success, passwd_state=%d", ps);
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
ofono_sim_initialized_notify(sd->sim);
|
||||
}
|
||||
|
||||
ofono_sim_initialized_notify(sd->sim);
|
||||
sd->pin_cbd_list = g_list_remove(sd->pin_cbd_list, cbd);
|
||||
ril_sim_pin_cbd_free(cbd);
|
||||
} else {
|
||||
@@ -1172,7 +1220,10 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
ril_sim_check_perm_lock(sd);
|
||||
cbd->ril_status = ril_status;
|
||||
if (cbd->card_status_id && (!cbd->state_event_count ||
|
||||
|
||||
/* RIL_E_PASSWORD_INCORRECT is the final result, no need to wait */
|
||||
if (ril_status != RIL_E_PASSWORD_INCORRECT &&
|
||||
cbd->card_status_id && (!cbd->state_event_count ||
|
||||
ril_sim_app_in_transient_state(sd))) {
|
||||
|
||||
GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
|
||||
@@ -1207,6 +1258,9 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
cbd->card_status_id);
|
||||
cbd->card_status_id = 0;
|
||||
}
|
||||
|
||||
/* Tell the core that we are ready to accept more requests */
|
||||
ofono_sim_initialized_notify(sd->sim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1416,6 +1470,294 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_list_apps_cb(void *data)
|
||||
{
|
||||
struct ril_sim_list_apps *rd = data;
|
||||
struct ril_sim *sd = rd->sd;
|
||||
const struct ril_sim_card_status *status = sd->card->status;
|
||||
struct ofono_error error;
|
||||
|
||||
GASSERT(sd->list_apps_id);
|
||||
sd->list_apps_id = 0;
|
||||
|
||||
if (status) {
|
||||
int i, n = status->num_apps;
|
||||
GByteArray *tlv = g_byte_array_sized_new(n * 20);
|
||||
|
||||
/* Reconstruct EFdir contents */
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *hex = status->apps[i].aid;
|
||||
gsize hex_len = hex ? strlen(hex) : 0;
|
||||
long aid_size;
|
||||
guint8 aid[16];
|
||||
|
||||
if (hex_len >= 2 && hex_len <= 2 * sizeof(aid) &&
|
||||
!(hex_len & 0x01) && decode_hex_own_buf(hex,
|
||||
hex_len, &aid_size, 0, aid)) {
|
||||
guint8 buf[4];
|
||||
|
||||
/*
|
||||
* TS 102.221
|
||||
* 13 Application independent files
|
||||
* 13.1 EFdir
|
||||
*
|
||||
* Application template TLV object.
|
||||
*/
|
||||
buf[0] = APP_TEMPLATE_TAG;
|
||||
buf[1] = (guint8)(aid_size + 2);
|
||||
buf[2] = APP_ID_TAG;
|
||||
buf[3] = (guint8)(aid_size);
|
||||
g_byte_array_append(tlv, buf, sizeof(buf));
|
||||
g_byte_array_append(tlv, aid, aid_size);
|
||||
}
|
||||
}
|
||||
DBG_(sd, "reporting %u apps %u bytes", n, tlv->len);
|
||||
rd->cb(ril_error_ok(&error), tlv->data, tlv->len, rd->data);
|
||||
g_byte_array_unref(tlv);
|
||||
} else {
|
||||
DBG_(sd, "no SIM card, no apps");
|
||||
rd->cb(ril_error_failure(&error), NULL, 0, rd->data);
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void ril_sim_list_apps(struct ofono_sim *sim,
|
||||
ofono_sim_list_apps_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_list_apps *rd = g_new(struct ril_sim_list_apps, 1);
|
||||
|
||||
rd->sd = sd;
|
||||
rd->cb = cb;
|
||||
rd->data = data;
|
||||
if (sd->list_apps_id) {
|
||||
g_source_remove(sd->list_apps_id);
|
||||
}
|
||||
sd->list_apps_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_sim_list_apps_cb, rd, g_free);
|
||||
}
|
||||
|
||||
static void ril_sim_open_channel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
ofono_sim_open_channel_cb_t cb = cbd->cb.open_channel;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
guint32 n, session_id;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_uint32(&rilp, &n) && n >= 1 &&
|
||||
grilio_parser_get_uint32(&rilp, &session_id)) {
|
||||
DBG_(cbd->sd, "%u", session_id);
|
||||
cb(ril_error_ok(&error), session_id, cbd->data);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ofono_error("Open logical channel failure: %s",
|
||||
ril_error_to_string(status));
|
||||
}
|
||||
|
||||
cb(ril_error_failure(&error), 0, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sim_open_channel(struct ofono_sim *sim,
|
||||
const unsigned char *aid, unsigned int len,
|
||||
ofono_sim_open_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
char *aid_hex = encode_hex(aid, len, 0);
|
||||
|
||||
DBG_(sd, "%s", aid_hex);
|
||||
grilio_request_append_utf8(req, aid_hex);
|
||||
grilio_request_append_int32(req, 0);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_OPEN_CHANNEL,
|
||||
ril_sim_open_channel_cb);
|
||||
grilio_request_unref(req);
|
||||
g_free(aid_hex);
|
||||
}
|
||||
|
||||
static void ril_sim_close_channel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd_io *cbd = user_data;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ofono_error("Close logical channel failure: %s",
|
||||
ril_error_to_string(status));
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
cbd->cb.close_channel(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sim_close_channel(struct ofono_sim *sim, int session_id,
|
||||
ofono_sim_close_channel_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(sd, "%u", session_id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, session_id);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_CLOSE_CHANNEL,
|
||||
ril_sim_close_channel_cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_get_results_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = user_data;
|
||||
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error err;
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&err), res->data, res->data_len, cbd->data);
|
||||
} else if (res) {
|
||||
cb(ril_error_sim(&err, res->sw1, res->sw2), NULL, 0, cbd->data);
|
||||
} else {
|
||||
cb(ril_error_failure(&err), NULL, 0, cbd->data);
|
||||
}
|
||||
ril_sim_io_response_free(res);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_transmit(struct ril_sim_session_cbd *cbd,
|
||||
int ins, int p1, int p2, int p3, const char *hex_data,
|
||||
GRilIoChannelResponseFunc cb)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
DBG_(cbd->sd, "session=%u,cmd=%02X,%02X,%02X,%02X,%02X,%s",
|
||||
cbd->session_id, cbd->cla, ins, p1, p2, p3,
|
||||
hex_data ? hex_data : "");
|
||||
grilio_request_append_int32(req, cbd->session_id);
|
||||
grilio_request_append_int32(req, cbd->cla);
|
||||
grilio_request_append_int32(req, ins);
|
||||
grilio_request_append_int32(req, p1);
|
||||
grilio_request_append_int32(req, p2);
|
||||
grilio_request_append_int32(req, p3);
|
||||
grilio_request_append_utf8(req, hex_data);
|
||||
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
|
||||
ril_sim_session_cbd_start(cbd, req,
|
||||
RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, cb);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_session_cbd *cbd = user_data;
|
||||
ofono_sim_logical_access_cb_t cb = cbd->cb;
|
||||
struct ril_sim_io_response *res;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
cbd->req_id = 0;
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (res && status == RIL_E_SUCCESS) {
|
||||
/*
|
||||
* TS 102 221
|
||||
* 7.3.1.1.5.2 Case 4 commands
|
||||
*
|
||||
* If the UICC receives a case 4 command, after processing
|
||||
* the data sent with the C-APDU, it shall return:
|
||||
*
|
||||
* a) procedure bytes '61 xx' instructing the transport
|
||||
* layer of the terminal to issue a GET RESPONSE command
|
||||
* with a maximum length of 'xx'; or
|
||||
* b) status indicating a warning or error condition (but
|
||||
* not SW1 SW2 = '90 00').
|
||||
*
|
||||
* The GET RESPONSE command so issued is then treated as
|
||||
* described for case 2 commands.
|
||||
*/
|
||||
if (res->sw1 == 0x61) {
|
||||
ril_sim_logical_access_transmit(cbd,
|
||||
CMD_GET_RESPONSE, 0, 0, res->sw2, NULL,
|
||||
ril_sim_logical_access_get_results_cb);
|
||||
} else if (ril_sim_io_response_ok(res)) {
|
||||
cb(ril_error_ok(&error), res->data, res->data_len,
|
||||
cbd->data);
|
||||
} else {
|
||||
cb(ril_error_sim(&error, res->sw1, res->sw2), NULL, 0,
|
||||
cbd->data);
|
||||
}
|
||||
} else {
|
||||
cb(ril_error_failure(&error), NULL, 0, cbd->data);
|
||||
}
|
||||
ril_sim_io_response_free(res);
|
||||
}
|
||||
|
||||
static void ril_sim_logical_access(struct ofono_sim *sim, int session_id,
|
||||
const unsigned char *pdu, unsigned int len,
|
||||
ofono_sim_logical_access_cb_t cb, void *data)
|
||||
{
|
||||
/* SIM Command APDU: CLA INS P1 P2 P3 Data */
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
const char* hex_data;
|
||||
char *tmp;
|
||||
struct ril_sim_session_cbd *cbd = ril_sim_session_cbd_new(sd,
|
||||
session_id, pdu[0], cb, data);
|
||||
|
||||
GASSERT(len >= 5);
|
||||
if (len > 5) {
|
||||
hex_data = tmp = encode_hex(pdu + 5, len - 5, 0);
|
||||
} else {
|
||||
tmp = NULL;
|
||||
hex_data = "";
|
||||
}
|
||||
|
||||
ril_sim_logical_access_transmit(cbd, pdu[1], pdu[2], pdu[3], pdu[4],
|
||||
hex_data, ril_sim_logical_access_cb);
|
||||
ril_sim_session_cbd_unref(cbd);
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_binary(struct ofono_sim *sim, int session,
|
||||
int fileid, int start, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_binary not implemented");
|
||||
cb(ril_error_failure(&error), NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_record(struct ofono_sim *sim, int session_id,
|
||||
int fileid, int record, int length,
|
||||
const unsigned char *path, unsigned int path_len,
|
||||
ofono_sim_read_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_record not implemented");
|
||||
cb(ril_error_failure(&error), NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_session_read_info(struct ofono_sim *sim, int session_id,
|
||||
int fileid, const unsigned char *path,
|
||||
unsigned int path_len, ofono_sim_file_info_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
|
||||
ofono_error("session_read_info not implemented");
|
||||
cb(ril_error_failure(&error), -1, -1, -1, NULL, 0, data);
|
||||
}
|
||||
|
||||
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
@@ -1497,6 +1839,9 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
grilio_queue_cancel_all(sd->q, FALSE);
|
||||
ofono_sim_set_data(sim, NULL);
|
||||
|
||||
if (sd->list_apps_id) {
|
||||
g_source_remove(sd->list_apps_id);
|
||||
}
|
||||
if (sd->idle_id) {
|
||||
g_source_remove(sd->idle_id);
|
||||
}
|
||||
@@ -1541,7 +1886,14 @@ const struct ofono_sim_driver ril_sim_driver = {
|
||||
.reset_passwd = ril_sim_pin_send_puk,
|
||||
.change_passwd = ril_sim_change_passwd,
|
||||
.query_pin_retries = ril_sim_query_pin_retries,
|
||||
.query_facility_lock = ril_sim_query_facility_lock
|
||||
.query_facility_lock = ril_sim_query_facility_lock,
|
||||
.list_apps = ril_sim_list_apps,
|
||||
.open_channel2 = ril_sim_open_channel,
|
||||
.close_channel = ril_sim_close_channel,
|
||||
.session_read_binary = ril_sim_session_read_binary,
|
||||
.session_read_record = ril_sim_session_read_record,
|
||||
.session_read_info = ril_sim_session_read_info,
|
||||
.logical_access = ril_sim_logical_access
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_card.h"
|
||||
#include "ril_radio.h"
|
||||
#include "ril_util.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -45,6 +45,8 @@ gulong ril_sim_settings_add_pref_mode_changed_handler(struct ril_sim_settings *s
|
||||
void ril_sim_settings_remove_handler(struct ril_sim_settings *s, gulong id);
|
||||
void ril_sim_settings_remove_handlers(struct ril_sim_settings *s, gulong *ids,
|
||||
int count);
|
||||
#define ril_sim_settings_remove_all_handlers(s,ids) \
|
||||
ril_sim_settings_remove_handlers(s, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_SIM_SETTINGS_H */
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
# If this option is on, preferred technology is set to GSM for non-data
|
||||
# slots.
|
||||
#
|
||||
# Default true (for historical reasons)
|
||||
#
|
||||
#ForceGsmForNonDataSlots=true
|
||||
|
||||
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# It's involved in 3G/LTE handover between the modems, meaning that it only
|
||||
@@ -224,12 +231,36 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#lteNetworkMode=9
|
||||
|
||||
# UMTS network mode.
|
||||
#
|
||||
# Default 3 (PREF_NET_TYPE_GSM_WCDMA_AUTO)
|
||||
#
|
||||
#umtsNetworkMode=3
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
|
||||
#
|
||||
# Default 20000 (20 seconds)
|
||||
#
|
||||
#networkModeTimeout=20000
|
||||
|
||||
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
|
||||
#
|
||||
# Default 100000 (100 seconds)
|
||||
#
|
||||
#networkSelectionTimeout=100000
|
||||
|
||||
# Comma-separated signal strength range, in dBm.
|
||||
#
|
||||
# These values are used for translating dBm values returned by the modem in
|
||||
# LTE mode into signal strength percentage. If you are getting significantly
|
||||
# different signal strength readings in GSM and LTE modes, you may need to
|
||||
# tweak those.
|
||||
#
|
||||
# Default -100,-60
|
||||
#
|
||||
#signalStrengthRange=-100,-60
|
||||
|
||||
# Cycle radio power at startup.
|
||||
#
|
||||
# Default true (cycle the power)
|
||||
@@ -257,6 +288,16 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#singleDataContext=false
|
||||
|
||||
# With some RILs, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS returns strange
|
||||
# operator names, i.e. numeric MCC+MNC values or the same name for all
|
||||
# operators (which is actually SPN fetched from the SIM). Such strange
|
||||
# names can be replaced with operator names from MBPI database, based
|
||||
# on the operator's MCC and MNC. That may not be 100% accurate, though.
|
||||
#
|
||||
# Default false (i.e. trust RIL to report the actual names)
|
||||
#
|
||||
#replaceStrangeOperatorNames=false
|
||||
|
||||
# Configures whether +0 is added to MCCMNC string passed to
|
||||
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL. Some Qualcomm RILs
|
||||
# require it, some MediaTek RILs don't like it.
|
||||
@@ -284,9 +325,49 @@ socket=/dev/socket/rild
|
||||
#
|
||||
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
|
||||
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
|
||||
# auto = Choose one of the above based on the RIL version
|
||||
# ur = Use URC filter (RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER)
|
||||
# This may be useful on devices with RIL version >= 15 if auto
|
||||
# method fails
|
||||
# auto = Choose ss or ds based on the RIL version
|
||||
# none = Disable device state management
|
||||
#
|
||||
# In addition to specifying ss, ds or ur method, one can specify a
|
||||
# combination of methods, e.g. ds+ur
|
||||
#
|
||||
# Default auto
|
||||
#
|
||||
#deviceStateTracking=auto
|
||||
|
||||
# On some phones (such as Jolla C), even if the slot which has been
|
||||
# using LTE gets powered off, we still need to explicitely set its
|
||||
# preferred mode to GSM, to make LTE machinery available to the other slot.
|
||||
#
|
||||
# Default true (false for MTK RILs)
|
||||
#
|
||||
#forceGsmWhenRadioOff=true
|
||||
|
||||
# Configures a period between RIL_UNSOL_CELL_INFO_LIST events when the device
|
||||
# is awake. Possible values are:
|
||||
#
|
||||
# 0 = invoke RIL_UNSOL_CELL_INFO_LIST when any of the reported information
|
||||
# changes
|
||||
# 1..INT_MAX-1 (2147483646) = sets update period in milliseconds
|
||||
# negative value or INT_MAX = never issue a RIL_UNSOL_CELL_INFO_LIST
|
||||
#
|
||||
# On MediaTek devices the period of RIL_UNSOL_CELL_INFO_LIST events can't be
|
||||
# configured. The parameter RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE has
|
||||
# non-standard meaning:
|
||||
#
|
||||
# 0 = enable RIL_UNSOL_CELL_INFO_LIST
|
||||
# any other value = disable RIL_UNSOL_CELL_INFO_LIST
|
||||
#
|
||||
# Default 2000
|
||||
#
|
||||
#cellInfoIntervalShortMs=2000
|
||||
|
||||
# Configures period between RIL_UNSOL_CELL_INFO_LIST events when the device is
|
||||
# in a power saving mode. For possible values, look cellInfoIntervalShortMs.
|
||||
#
|
||||
# Default 30000
|
||||
#
|
||||
#cellInfoIntervalLongMs=30000
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -23,6 +24,7 @@
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct ofono_watch;
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
@@ -48,12 +50,21 @@ struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_vendor;
|
||||
|
||||
enum ril_data_role {
|
||||
RIL_DATA_ROLE_NONE, /* Mobile data not required */
|
||||
RIL_DATA_ROLE_MMS, /* Data is needed at any speed */
|
||||
RIL_DATA_ROLE_INTERNET /* Data is needed at full speed */
|
||||
};
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ril_pref_net_type lte_network_mode;
|
||||
enum ril_pref_net_type umts_network_mode;
|
||||
int network_mode_timeout;
|
||||
int network_selection_timeout;
|
||||
int signal_strength_dbm_weak;
|
||||
int signal_strength_dbm_strong;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean empty_pin_query;
|
||||
gboolean radio_power_cycle;
|
||||
@@ -61,11 +72,15 @@ struct ril_slot_config {
|
||||
gboolean enable_voicecall;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean network_selection_manual_0;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
gboolean use_data_profiles;
|
||||
guint mms_data_profile_id;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
int cell_info_interval_short_ms;
|
||||
int cell_info_interval_long_ms;
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2018 Jolla Ltd.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -20,48 +21,77 @@
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
#define USSD_REQUEST_TIMEOUT_SEC (30)
|
||||
#define USSD_CANCEL_TIMEOUT_SEC (20)
|
||||
|
||||
struct ril_ussd {
|
||||
struct ofono_ussd *ussd;
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
guint request_id;
|
||||
guint cancel_id;
|
||||
guint timer_id;
|
||||
gulong event_id;
|
||||
};
|
||||
|
||||
struct ril_ussd_cbd {
|
||||
struct ril_ussd *ud;
|
||||
ofono_ussd_cb_t cb;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define ril_ussd_cbd_free g_free
|
||||
|
||||
static inline struct ril_ussd *ril_ussd_get_data(struct ofono_ussd *ussd)
|
||||
{
|
||||
return ofono_ussd_get_data(ussd);
|
||||
}
|
||||
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
|
||||
static struct ril_ussd_cbd *ril_ussd_cbd_new(struct ril_ussd *ud,
|
||||
ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1);
|
||||
struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
|
||||
|
||||
cbd->ud = ud;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_ussd_cbd_free(void *cbd)
|
||||
{
|
||||
g_slice_free(struct ril_ussd_cbd, cbd);
|
||||
}
|
||||
|
||||
static void ril_ussd_cancel_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
/* Always report sucessful completion, otherwise ofono may get
|
||||
* stuck in the USSD_STATE_ACTIVE state */
|
||||
GASSERT(ud->cancel_id);
|
||||
ud->cancel_id = 0;
|
||||
cbd->cb(ril_error_ok(&error), cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_response(GRilIoChannel* channel, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_ussd_cbd *cbd = user_data;
|
||||
struct ril_ussd *ud = cbd->ud;
|
||||
|
||||
GASSERT(ud->request_id);
|
||||
ud->request_id = 0;
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
cbd->cb(&error, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
const unsigned char *pdu, int len, ofono_ussd_cb_t cb, void *data)
|
||||
{
|
||||
@@ -70,6 +100,12 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
|
||||
struct ril_ussd *ud = ril_ussd_get_data(ussd);
|
||||
|
||||
ofono_info("send ussd, len:%d", len);
|
||||
GASSERT(!ud->request_id);
|
||||
if (ud->request_id) {
|
||||
grilio_queue_cancel_request(ud->q, ud->request_id, FALSE);
|
||||
ud->request_id = 0;
|
||||
}
|
||||
|
||||
if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
|
||||
if (charset == SMS_CHARSET_7BIT) {
|
||||
unsigned char unpacked_buf[182];
|
||||
@@ -100,10 +136,15 @@ 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(ud->q, req,
|
||||
RIL_REQUEST_SEND_USSD);
|
||||
grilio_request_set_timeout(req,
|
||||
USSD_REQUEST_TIMEOUT_SEC * 1000);
|
||||
ud->request_id =
|
||||
grilio_queue_send_request_full(ud->q,
|
||||
req, RIL_REQUEST_SEND_USSD,
|
||||
ril_ussd_response,
|
||||
ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -119,10 +160,12 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
ofono_info("send ussd cancel");
|
||||
GASSERT(!ud->cancel_id);
|
||||
grilio_queue_cancel_request(ud->q, ud->cancel_id, FALSE);
|
||||
grilio_request_set_timeout(req, USSD_CANCEL_TIMEOUT_SEC * 1000);
|
||||
grilio_queue_send_request_full(ud->q, req, RIL_REQUEST_CANCEL_USSD,
|
||||
ril_ussd_cancel_cb, ril_ussd_cbd_free,
|
||||
ril_ussd_cbd_new(cb, data));
|
||||
ud->cancel_id = grilio_queue_send_request_full(ud->q, req,
|
||||
RIL_REQUEST_CANCEL_USSD, ril_ussd_cancel_cb,
|
||||
ril_ussd_cbd_free, ril_ussd_cbd_new(ud, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
|
||||
@@ -409,6 +409,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
|
||||
break;
|
||||
case RADIO_TECH_LTE:
|
||||
case RADIO_TECH_LTE_CA:
|
||||
access_tech = ACCESS_TECHNOLOGY_EUTRAN;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -116,6 +117,14 @@ gboolean ril_vendor_data_call_parse(RilVendor *self,
|
||||
data_call_parse(self, call, ver, rilp);
|
||||
}
|
||||
|
||||
gboolean ril_vendor_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
|
||||
signal_strength_parse(self, signal_strength, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_default_set_network(RilVendor *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
@@ -160,6 +169,13 @@ static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_default_signal_strength_parse(RilVendor *self,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ril_vendor_init_base(RilVendor *self, GRilIoChannel *io)
|
||||
{
|
||||
self->io = grilio_channel_ref(io);
|
||||
@@ -190,6 +206,7 @@ static void ril_vendor_class_init(RilVendorClass* klass)
|
||||
klass->set_attach_apn_req = ril_vendor_default_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_default_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_default_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_default_signal_strength_parse;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -23,8 +24,10 @@ struct ril_vendor_defaults {
|
||||
gboolean legacy_imei_query;
|
||||
gboolean enable_cbs;
|
||||
gboolean enable_stk;
|
||||
gboolean replace_strange_oper;
|
||||
gboolean query_available_band_mode;
|
||||
gboolean use_data_profiles;
|
||||
gboolean force_gsm_when_radio_off;
|
||||
guint mms_data_profile_id;
|
||||
};
|
||||
|
||||
@@ -37,6 +40,12 @@ struct ril_vendor_driver {
|
||||
const struct ril_slot_config *cfg);
|
||||
};
|
||||
|
||||
struct ril_vendor_signal_strength {
|
||||
gint32 gsm; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 lte; /* (0-31, 99) per TS 27.007 8.5 */
|
||||
gint32 qdbm; /* 4*dBm, 0 if none */
|
||||
};
|
||||
|
||||
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
|
||||
struct ril_vendor *ril_vendor_create
|
||||
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
|
||||
@@ -63,6 +72,9 @@ GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
|
||||
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean ril_vendor_signal_strength_parse(struct ril_vendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
|
||||
/* Put vendor driver descriptors to the "__vendor" section */
|
||||
#define RIL_VENDOR_DRIVER_DEFINE(name) const struct ril_vendor_driver name \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -42,6 +43,9 @@ typedef struct ril_vendor_class {
|
||||
gboolean (*data_call_parse)(RilVendor *vendor,
|
||||
struct ril_data_call *call, int version,
|
||||
GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_parse)(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal_strength,
|
||||
GRilIoParser *rilp);
|
||||
} RilVendorClass;
|
||||
|
||||
GType ril_vendor_get_type(void);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2019 Jolla Ltd.
|
||||
* Copyright (C) 2016-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -79,6 +80,8 @@ struct ril_mtk_flavor {
|
||||
enum ril_auth auth, const char *proto);
|
||||
gboolean (*data_call_parse_fn)(struct ril_data_call *call,
|
||||
int version, GRilIoParser *rilp);
|
||||
gboolean (*signal_strength_fn)(struct ril_vendor_signal_strength *sig,
|
||||
GRilIoParser *rilp);
|
||||
};
|
||||
|
||||
/* MTK specific RIL messages (actual codes differ from model to model!) */
|
||||
@@ -401,6 +404,96 @@ static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
|
||||
data_call_parse(vendor, call, version, rilp);
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_1
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, rssi = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* ???? */
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, &rssi);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
grilio_parser_get_int32(rilp, NULL);
|
||||
|
||||
signal->qdbm = (rssi > 0 && rssi != INT_MAX) ? (-4 * rssi) :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_2
|
||||
(struct ril_vendor_signal_strength *signal, GRilIoParser *rilp)
|
||||
{
|
||||
if (grilio_parser_bytes_remaining(rilp) == 64) {
|
||||
gint32 rsrp = 0, is_gsm = 0, rssi_qdbm = 0;
|
||||
|
||||
/* GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->gsm);
|
||||
grilio_parser_get_int32(rilp, NULL); /* bitErrorRate */
|
||||
|
||||
/* CDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
|
||||
/* EVDO_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, NULL); /* dbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* ecio */
|
||||
grilio_parser_get_int32(rilp, NULL); /* signalNoiseRatio */
|
||||
|
||||
/* LTE_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &signal->lte);
|
||||
grilio_parser_get_int32(rilp, &rsrp); /* rsrp */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rsrq */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rssnr */
|
||||
grilio_parser_get_int32(rilp, NULL); /* cqi */
|
||||
|
||||
/* WCDMA_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &is_gsm); /* isGsm */
|
||||
grilio_parser_get_int32(rilp, &rssi_qdbm); /* rssiQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* rscpQdbm */
|
||||
grilio_parser_get_int32(rilp, NULL); /* Ecn0Qdbm*/
|
||||
|
||||
signal->qdbm = (is_gsm == 1 && rssi_qdbm < 0) ? rssi_qdbm :
|
||||
(rsrp >= 44 && rsrp <= 140) ? (-4 * rsrp) : 0;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_vendor_mtk_signal_strength_parse(RilVendor *vendor,
|
||||
struct ril_vendor_signal_strength *signal,
|
||||
GRilIoParser *rilp)
|
||||
{
|
||||
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
|
||||
|
||||
return flavor->signal_strength_fn ?
|
||||
flavor->signal_strength_fn(signal, rilp) :
|
||||
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
|
||||
signal_strength_parse(vendor, signal, rilp);
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
{
|
||||
/*
|
||||
@@ -415,6 +508,8 @@ static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
|
||||
defaults->query_available_band_mode = FALSE;
|
||||
defaults->empty_pin_query = FALSE;
|
||||
defaults->legacy_imei_query = TRUE;
|
||||
defaults->force_gsm_when_radio_off = FALSE;
|
||||
defaults->replace_strange_oper = TRUE;
|
||||
}
|
||||
|
||||
static void ril_vendor_mtk_base_init(RilVendorMtk *self, GRilIoChannel *io,
|
||||
@@ -496,20 +591,23 @@ static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
|
||||
klass->set_attach_apn_req = ril_vendor_mtk_set_attach_apn_req;
|
||||
klass->data_call_req = ril_vendor_mtk_data_call_req;
|
||||
klass->data_call_parse = ril_vendor_mtk_data_call_parse;
|
||||
klass->signal_strength_parse = ril_vendor_mtk_signal_strength_parse;
|
||||
}
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor1 = {
|
||||
.name = "mtk1",
|
||||
.msg = &msg_mtk1,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_1,
|
||||
.data_call_parse_fn = NULL
|
||||
.data_call_parse_fn = NULL,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_1
|
||||
};
|
||||
|
||||
static const struct ril_mtk_flavor ril_mtk_flavor2 = {
|
||||
.name = "mtk2",
|
||||
.msg = &msg_mtk2,
|
||||
.build_attach_apn_req_fn = &ril_vendor_mtk_build_attach_apn_req_2,
|
||||
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6
|
||||
.data_call_parse_fn = &ril_vendor_mtk_data_call_parse_v6,
|
||||
.signal_strength_fn = &ril_vendor_mtk_signal_strength_2
|
||||
};
|
||||
|
||||
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)
|
||||
|
||||
0
ofono/drivers/xmm7modem/ims.c
Executable file → Normal file
0
ofono/drivers/xmm7modem/ims.c
Executable file → Normal file
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -25,7 +26,7 @@ extern "C" {
|
||||
enum ofono_dbus_access {
|
||||
OFONO_DBUS_ACCESS_DENY, /* Deny access */
|
||||
OFONO_DBUS_ACCESS_ALLOW, /* Allow access */
|
||||
OFONO_DBUS_ACCESS_DONT_CARE, /* No decision */
|
||||
OFONO_DBUS_ACCESS_DONT_CARE /* No decision */
|
||||
};
|
||||
|
||||
enum ofono_dbus_access_intf {
|
||||
@@ -38,6 +39,8 @@ enum ofono_dbus_access_intf {
|
||||
OFONO_DBUS_ACCESS_INTF_SIMMGR, /* org.ofono.SimManager */
|
||||
OFONO_DBUS_ACCESS_INTF_MODEM, /* org.ofono.Modem */
|
||||
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
|
||||
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
|
||||
OFONO_DBUS_ACCESS_INTF_OEMRAW, /* org.ofono.OemRaw */
|
||||
OFONO_DBUS_ACCESS_INTF_COUNT
|
||||
};
|
||||
|
||||
@@ -116,6 +119,18 @@ enum ofono_dbus_access_radiosettings_method {
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_STK */
|
||||
enum ofono_dbus_access_stk_method {
|
||||
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
|
||||
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
|
||||
};
|
||||
|
||||
/* OFONO_DBUS_ACCESS_INTF_OEMRAW */
|
||||
enum ofono_dbus_access_oemraw_method {
|
||||
OFONO_DBUS_ACCESS_OEMRAW_SEND,
|
||||
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
|
||||
};
|
||||
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
|
||||
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)
|
||||
|
||||
55
ofono/include/dbus-clients.h
Normal file
55
ofono/include/dbus-clients.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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 OFONO_DBUS_CLIENTS_H
|
||||
#define OFONO_DBUS_CLIENTS_H
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
/* Since mer/1.23+git31 */
|
||||
|
||||
struct ofono_dbus_clients;
|
||||
|
||||
typedef void (*ofono_dbus_clients_notify_func)(const char *name,
|
||||
void *user_data);
|
||||
|
||||
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
|
||||
ofono_dbus_clients_notify_func notify, void *user_data);
|
||||
void ofono_dbus_clients_free(struct ofono_dbus_clients *clients);
|
||||
|
||||
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *clients);
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *clients,
|
||||
const char *name);
|
||||
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *clients,
|
||||
const char *name);
|
||||
|
||||
void ofono_dbus_clients_signal(struct ofono_dbus_clients *clients,
|
||||
DBusMessage *signal);
|
||||
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *dc,
|
||||
const char *path, const char *interface, const char *name,
|
||||
int type, const void *value);
|
||||
|
||||
#endif /* OFONO_DBUS_CLIENTS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Telephony stack for Linux
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
* Copyright (C) 2013-2021 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
|
||||
@@ -14,10 +14,6 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OFONO_DBUS_H
|
||||
@@ -83,6 +79,8 @@ extern "C" {
|
||||
DBUS_TYPE_VARIANT_AS_STRING \
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
|
||||
|
||||
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
|
||||
|
||||
DBusConnection *ofono_dbus_get_connection(void);
|
||||
|
||||
void ofono_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
|
||||
@@ -110,6 +108,11 @@ int ofono_dbus_signal_dict_property_changed(DBusConnection *conn,
|
||||
const char *name, int type,
|
||||
const void *value);
|
||||
|
||||
/* Since mer/1.23+git31 */
|
||||
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -128,6 +129,8 @@ void ofono_gprs_context_set_ipv4_gateway(struct ofono_gprs_context *gc,
|
||||
const char *gateway);
|
||||
void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
|
||||
const char **dns);
|
||||
void ofono_gprs_context_set_ipv4_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf); /* Since mer/1.23+git30 */
|
||||
|
||||
void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
|
||||
const char *address);
|
||||
@@ -137,6 +140,8 @@ void ofono_gprs_context_set_ipv6_gateway(struct ofono_gprs_context *gc,
|
||||
const char *gateway);
|
||||
void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
|
||||
const char **dns);
|
||||
void ofono_gprs_context_set_ipv6_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf); /* Since mer/1.23+git30 */
|
||||
|
||||
void ofono_gprs_context_signal_change(struct ofono_gprs_context *gc,
|
||||
unsigned int cid);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -210,6 +211,10 @@ struct ofono_sim_driver {
|
||||
void (*logical_access)(struct ofono_sim *sim, int session_id,
|
||||
const unsigned char *pdu, unsigned int len,
|
||||
ofono_sim_logical_access_cb_t cb, void *data);
|
||||
/* Since mer/1.23+git28 */
|
||||
void (*open_channel2)(struct ofono_sim *sim, const unsigned char *aid,
|
||||
unsigned int len, ofono_sim_open_channel_cb_t cb,
|
||||
void *data);
|
||||
};
|
||||
|
||||
int ofono_sim_driver_register(const struct ofono_sim_driver *d);
|
||||
|
||||
@@ -139,7 +139,12 @@ struct ofono_voicecall_driver {
|
||||
/* Dials the last number again, this handles the hfp profile last number
|
||||
* dialing with the +BLDN AT command
|
||||
*/
|
||||
void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data);
|
||||
void (*dial_last)(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
/* dials a number at a given memory location */
|
||||
void (*dial_memory)(struct ofono_voicecall *vc,
|
||||
unsigned int memory_location, ofono_voicecall_cb_t cb,
|
||||
void *data);
|
||||
};
|
||||
|
||||
void ofono_voicecall_en_list_notify(struct ofono_voicecall *vc,
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <ofono/ussd.h>
|
||||
#include <ofono/gprs.h>
|
||||
#include <ofono/gprs-context.h>
|
||||
#include <ofono/lte.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
#include <ofono/log.h>
|
||||
@@ -483,6 +484,8 @@ static void gobi_post_sim(struct ofono_modem *modem)
|
||||
|
||||
DBG("%p", modem);
|
||||
|
||||
ofono_lte_create(modem, "qmimodem", data->device);
|
||||
|
||||
if (data->features & GOBI_CAT)
|
||||
ofono_stk_create(modem, 0, "qmimodem", data->device);
|
||||
else if (data->features & GOBI_CAT_OLD)
|
||||
|
||||
@@ -495,8 +495,6 @@ static void hfp_ag_enable(DBusConnection *conn)
|
||||
connection_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, connection_destroy);
|
||||
|
||||
ofono_handsfree_audio_ref();
|
||||
|
||||
hfp_ag_enabled = TRUE;
|
||||
}
|
||||
|
||||
@@ -525,7 +523,6 @@ static void hfp_ag_disable(DBusConnection *conn)
|
||||
g_dbus_unregister_interface(conn, HFP_AG_EXT_PROFILE_PATH,
|
||||
BLUEZ_PROFILE_INTERFACE);
|
||||
ofono_handsfree_card_driver_unregister(&hfp_ag_driver);
|
||||
ofono_handsfree_audio_unref();
|
||||
}
|
||||
|
||||
hfp_ag_enabled = FALSE;
|
||||
@@ -545,13 +542,14 @@ static int hfp_ag_init(void)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
|
||||
hfp_ag_enable(conn);
|
||||
|
||||
/* g_dbus_add_service_watch immediately checks for bluetooth service
|
||||
* and calls connect callback if the service exists. */
|
||||
service_watch_id = g_dbus_add_service_watch(conn, "org.bluez",
|
||||
bluez_connect_cb,
|
||||
bluez_disconnect_cb,
|
||||
NULL, NULL);
|
||||
|
||||
ofono_handsfree_audio_ref();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -565,6 +563,7 @@ static void hfp_ag_exit(void)
|
||||
}
|
||||
|
||||
hfp_ag_disable(conn);
|
||||
ofono_handsfree_audio_unref();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(hfp_ag_bluez5, "Hands-Free Audio Gateway Profile Plugins",
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#include <ofono/handsfree.h>
|
||||
#include <ofono/handsfree-audio.h>
|
||||
#include <ofono/siri.h>
|
||||
#include <ofono.h>
|
||||
|
||||
#include <drivers/atmodem/atutil.h>
|
||||
#include <drivers/hfpmodem/slc.h>
|
||||
@@ -833,8 +832,6 @@ static int hfp_init(void)
|
||||
if (DBUS_TYPE_UNIX_FD < 0)
|
||||
return -EBADF;
|
||||
|
||||
__ofono_handsfree_audio_manager_init();
|
||||
|
||||
/* Registers External Profile handler */
|
||||
if (!g_dbus_register_interface(conn, HFP_EXT_PROFILE_PATH,
|
||||
BLUEZ_PROFILE_INTERFACE,
|
||||
@@ -890,8 +887,6 @@ static void hfp_exit(void)
|
||||
g_dbus_client_unref(bluez);
|
||||
|
||||
ofono_handsfree_audio_unref();
|
||||
|
||||
__ofono_handsfree_audio_manager_cleanup();
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -60,6 +60,7 @@ const char *mbpi_database = MBPI_DATABASE;
|
||||
*/
|
||||
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
|
||||
enum ofono_gprs_proto mbpi_default_ims_proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
|
||||
enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
|
||||
|
||||
@@ -246,6 +247,9 @@ static void usage_start(GMarkupParseContext *context,
|
||||
} else if (strcmp(text, "mms") == 0) {
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_MMS;
|
||||
apn->proto = mbpi_default_mms_proto;
|
||||
} else if (strcmp(text, "ims") == 0) {
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_IMS;
|
||||
apn->proto = mbpi_default_ims_proto;
|
||||
} else if (strcmp(text, "wap") == 0)
|
||||
apn->type = OFONO_GPRS_CONTEXT_TYPE_WAP;
|
||||
else
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -22,6 +23,7 @@
|
||||
extern const char *mbpi_database;
|
||||
extern enum ofono_gprs_proto mbpi_default_internet_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_mms_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_ims_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_proto;
|
||||
extern enum ofono_gprs_auth_method mbpi_default_auth_method;
|
||||
|
||||
|
||||
@@ -128,6 +128,14 @@ void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
|
||||
gboolean enabled)
|
||||
{
|
||||
if (info && info->proc->set_enabled) {
|
||||
info->proc->set_enabled(info, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -89,6 +89,7 @@ struct sailfish_cell_info_proc {
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
|
||||
void (*set_update_interval)(struct sailfish_cell_info *info, int ms);
|
||||
void (*set_enabled)(struct sailfish_cell_info *info, gboolean enabled);
|
||||
};
|
||||
|
||||
/* Utilities */
|
||||
@@ -107,6 +108,8 @@ void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id);
|
||||
void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
|
||||
int ms);
|
||||
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
|
||||
gboolean enabled);
|
||||
|
||||
#endif /* SAILFISH_CELINFO_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016-2018 Jolla Ltd.
|
||||
* Copyright (C) 2016-2021 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
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/dbus-clients.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
@@ -35,11 +36,13 @@ struct sailfish_cell_info_dbus {
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
struct ofono_dbus_clients *clients;
|
||||
};
|
||||
|
||||
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
#define CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL "Unsubscribed"
|
||||
|
||||
#define CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
@@ -322,21 +325,24 @@ static void sailfish_cell_info_dbus_emit_path_list
|
||||
(struct sailfish_cell_info_dbus *dbus, const char *name,
|
||||
GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
if (ofono_dbus_clients_count(dbus->clients)) {
|
||||
guint i;
|
||||
DBusMessageIter it, a;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
dbus_message_iter_append_basic(&a,
|
||||
DBUS_TYPE_OBJECT_PATH, &path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &a);
|
||||
ofono_dbus_clients_signal(dbus->clients, signal);
|
||||
dbus_message_unref(signal);
|
||||
}
|
||||
}
|
||||
|
||||
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
@@ -366,6 +372,23 @@ static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_emit_signal
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const char *path, const char *intf,
|
||||
const char *name, int type, ...)
|
||||
{
|
||||
if (ofono_dbus_clients_count(dbus->clients)) {
|
||||
va_list args;
|
||||
DBusMessage *signal = dbus_message_new_signal(path, intf, name);
|
||||
|
||||
va_start(args, type);
|
||||
dbus_message_append_args_valist(signal, type, args);
|
||||
ofono_dbus_clients_signal(dbus->clients, signal);
|
||||
dbus_message_unref(signal);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_property_changed
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell_entry *entry, int mask)
|
||||
@@ -377,7 +400,8 @@ static void sailfish_cell_info_dbus_property_changed
|
||||
|
||||
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
|
||||
const dbus_bool_t registered = (cell->registered != FALSE);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
|
||||
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
@@ -386,9 +410,10 @@ static void sailfish_cell_info_dbus_property_changed
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
ofono_dbus_clients_signal_property_changed(
|
||||
dbus->clients, entry->path,
|
||||
CELL_DBUS_INTERFACE, prop[i].name,
|
||||
DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
@@ -411,7 +436,7 @@ static void sailfish_cell_info_dbus_update_entries
|
||||
sailfish_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
@@ -492,29 +517,67 @@ static void sailfish_cell_info_dbus_cells_changed_cb
|
||||
((struct sailfish_cell_info_dbus *)arg, TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_error_failed(DBusMessage *msg,
|
||||
const char *explanation)
|
||||
{
|
||||
return g_dbus_create_error(msg, OFONO_ERROR_INTERFACE ".Failed", "%s",
|
||||
explanation);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
const char *sender = dbus_message_get_sender(msg);
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
if (ofono_dbus_clients_add(dbus->clients, sender)) {
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, a;
|
||||
GSList *l;
|
||||
|
||||
sailfish_cell_info_set_enabled(dbus->info, TRUE);
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
|
||||
dbus_message_iter_append_basic(&a,
|
||||
DBUS_TYPE_OBJECT_PATH, &entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &a);
|
||||
return reply;
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
return sailfish_cell_info_dbus_error_failed(msg, "Operation failed");
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_unsubscribe(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
const char *sender = dbus_message_get_sender(msg);
|
||||
|
||||
DBG("%s", sender);
|
||||
if (ofono_dbus_clients_remove(dbus->clients, sender)) {
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE,
|
||||
CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL);
|
||||
|
||||
if (!ofono_dbus_clients_count(dbus->clients)) {
|
||||
sailfish_cell_info_set_enabled(dbus->info, FALSE);
|
||||
}
|
||||
dbus_message_set_destination(signal, sender);
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
return sailfish_cell_info_dbus_error_failed(msg, "Not subscribed");
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
sailfish_cell_info_dbus_get_cells) },
|
||||
{ GDBUS_METHOD("Unsubscribe", NULL, NULL,
|
||||
sailfish_cell_info_dbus_unsubscribe) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -523,9 +586,20 @@ static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void sailfish_cell_info_dbus_disconnect_cb(const char *name, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
|
||||
if (!ofono_dbus_clients_count(dbus->clients)) {
|
||||
sailfish_cell_info_set_enabled(dbus->info, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info)
|
||||
{
|
||||
@@ -550,6 +624,8 @@ struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
ofono_modem_add_interface(modem,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
dbus->clients = ofono_dbus_clients_new(dbus->conn,
|
||||
sailfish_cell_info_dbus_disconnect_cb, dbus);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
@@ -565,6 +641,7 @@ void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
ofono_dbus_clients_free(dbus->clients);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <gutil_macros.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ofono/storage.h>
|
||||
#include <ofono/watch.h>
|
||||
|
||||
#include "src/ofono.h"
|
||||
@@ -44,6 +46,12 @@ enum ofono_watch_events {
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum sim_auto_select {
|
||||
SIM_AUTO_SELECT_OFF,
|
||||
SIM_AUTO_SELECT_ON,
|
||||
SIM_AUTO_SELECT_ONCE
|
||||
};
|
||||
|
||||
struct sailfish_manager_priv {
|
||||
struct sailfish_manager pub; /* Public part */
|
||||
struct sailfish_slot_driver_reg *drivers;
|
||||
@@ -52,6 +60,8 @@ struct sailfish_manager_priv {
|
||||
struct sailfish_slot_priv *data_slot;
|
||||
struct sailfish_slot_priv *mms_slot;
|
||||
sailfish_slot_ptr *slots;
|
||||
enum sim_auto_select auto_data_sim;
|
||||
gboolean auto_data_sim_done;
|
||||
int slot_count;
|
||||
guint init_countdown;
|
||||
guint init_id;
|
||||
@@ -99,6 +109,11 @@ struct sailfish_slot_priv {
|
||||
int index;
|
||||
};
|
||||
|
||||
/* Read-only config */
|
||||
#define SF_CONFIG_FILE "main.conf"
|
||||
#define SF_CONFIG_GROUP "ModemManager"
|
||||
#define SF_CONFIG_KEY_AUTO_DATA_SIM "AutoSelectDataSim"
|
||||
|
||||
/* "ril" is used for historical reasons */
|
||||
#define SF_STORE "ril"
|
||||
#define SF_STORE_GROUP "Settings"
|
||||
@@ -106,6 +121,7 @@ struct sailfish_slot_priv {
|
||||
#define SF_STORE_DEFAULT_VOICE_SIM "DefaultVoiceSim"
|
||||
#define SF_STORE_DEFAULT_DATA_SIM "DefaultDataSim"
|
||||
#define SF_STORE_SLOTS_SEP ","
|
||||
#define SF_STORE_AUTO_DATA_SIM_DONE "AutoSelectDataSimDone"
|
||||
|
||||
/* The file where error statistics is stored. Again "rilerror" is historical */
|
||||
#define SF_ERROR_STORAGE "rilerror" /* File name */
|
||||
@@ -145,6 +161,50 @@ static inline void sailfish_slot_set_data_role(struct sailfish_slot_priv *s,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(str);
|
||||
if (strcasecmp(str, name)) {
|
||||
va_list args;
|
||||
va_start(args, value);
|
||||
while ((name = va_arg(args, char*)) != NULL) {
|
||||
value = va_arg(args, int);
|
||||
if (!strcasecmp(str, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
ofono_error("Invalid %s config value (%s)", key, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
|
||||
if (name) {
|
||||
if (result) {
|
||||
*result = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update modem paths and emit D-Bus signal if necessary */
|
||||
static void sailfish_manager_update_modem_paths_full
|
||||
(struct sailfish_manager_priv *p)
|
||||
@@ -588,6 +648,27 @@ static struct sailfish_slot_priv *sailfish_manager_find_slot_imsi
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_all_sims_are_initialized_proc
|
||||
(struct sailfish_slot_priv *s, void *user_data)
|
||||
{
|
||||
if (s->pub.sim_present && s->pub.enabled && !s->watch->imsi) {
|
||||
*((gboolean*)user_data) = FALSE;
|
||||
return SF_LOOP_DONE;
|
||||
} else {
|
||||
return SF_LOOP_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean sailfish_manager_all_sims_are_initialized
|
||||
(struct sailfish_manager_priv *p)
|
||||
{
|
||||
gboolean result = TRUE;
|
||||
|
||||
sailfish_manager_foreach_slot(p,
|
||||
sailfish_manager_all_sims_are_initialized_proc, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns the event mask to be passed to sailfish_manager_dbus_signal.
|
||||
* The caller has a chance to OR it with other bits */
|
||||
static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
@@ -615,7 +696,7 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
* previously selected voice SIM is inserted, we will switch
|
||||
* back to it.
|
||||
*
|
||||
* There is no such fallback for the data.
|
||||
* A similar behavior can be configured for data SIM too.
|
||||
*/
|
||||
if (!slot) {
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
@@ -648,13 +729,52 @@ static int sailfish_manager_update_modem_paths(struct sailfish_manager_priv *p)
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Should we automatically select the default data sim
|
||||
* on a multisim phone that has only one sim inserted?
|
||||
*/
|
||||
slot = NULL;
|
||||
}
|
||||
|
||||
/* Check if we need to auto-select data SIM (always or once) */
|
||||
if (!slot && (p->auto_data_sim == SIM_AUTO_SELECT_ON ||
|
||||
(p->auto_data_sim == SIM_AUTO_SELECT_ONCE &&
|
||||
!p->auto_data_sim_done))) {
|
||||
/*
|
||||
* To actually make a selection we need all present SIMs
|
||||
* to be initialized. Otherwise we may end up endlessly
|
||||
* switching data SIMs back and forth.
|
||||
*/
|
||||
if (sailfish_manager_all_sims_are_initialized(p)) {
|
||||
slot = sailfish_manager_find_slot_imsi(p, NULL);
|
||||
if (slot && slot->watch->imsi && slot->watch->online &&
|
||||
p->auto_data_sim == SIM_AUTO_SELECT_ONCE) {
|
||||
const char *imsi = slot->watch->imsi;
|
||||
|
||||
/*
|
||||
* Data SIM only needs to be auto-selected
|
||||
* once and it's done. Write that down.
|
||||
*/
|
||||
DBG("Default data sim set to %s once", imsi);
|
||||
p->auto_data_sim_done = TRUE;
|
||||
g_key_file_set_boolean(p->storage,
|
||||
SF_STORE_GROUP,
|
||||
SF_STORE_AUTO_DATA_SIM_DONE,
|
||||
p->auto_data_sim_done);
|
||||
|
||||
g_free(p->default_data_imsi);
|
||||
p->pub.default_data_imsi =
|
||||
p->default_data_imsi = g_strdup(imsi);
|
||||
g_key_file_set_string(p->storage,
|
||||
SF_STORE_GROUP,
|
||||
SF_STORE_DEFAULT_DATA_SIM,
|
||||
imsi);
|
||||
|
||||
storage_sync(NULL, SF_STORE, p->storage);
|
||||
sailfish_manager_dbus_signal(p->dbus,
|
||||
SAILFISH_MANAGER_SIGNAL_DATA_IMSI);
|
||||
}
|
||||
} else {
|
||||
DBG("Skipping auto-selection of data SIM");
|
||||
}
|
||||
}
|
||||
|
||||
if (slot && !slot->watch->online) {
|
||||
slot = NULL;
|
||||
}
|
||||
@@ -1274,6 +1394,29 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
|
||||
|
||||
struct sailfish_manager_priv *p =
|
||||
g_slice_new0(struct sailfish_manager_priv);
|
||||
GKeyFile *conf = g_key_file_new();
|
||||
char* fn = g_build_filename(ofono_config_dir(), SF_CONFIG_FILE, NULL);
|
||||
|
||||
/* Load config */
|
||||
if (g_key_file_load_from_file(conf, fn, 0, NULL)) {
|
||||
int ival;
|
||||
|
||||
DBG("Loading configuration file %s", fn);
|
||||
if (sailfish_config_get_enum(conf, SF_CONFIG_GROUP,
|
||||
SF_CONFIG_KEY_AUTO_DATA_SIM, &ival,
|
||||
"off", SIM_AUTO_SELECT_OFF,
|
||||
"once", SIM_AUTO_SELECT_ONCE,
|
||||
"always", SIM_AUTO_SELECT_ON,
|
||||
"on", SIM_AUTO_SELECT_ON, NULL)) {
|
||||
DBG("Automatic data SIM selection: %s",
|
||||
ival == SIM_AUTO_SELECT_ONCE ? "once":
|
||||
ival == SIM_AUTO_SELECT_ON ? "on":
|
||||
"off");
|
||||
p->auto_data_sim = ival;
|
||||
}
|
||||
}
|
||||
g_key_file_free(conf);
|
||||
g_free(fn);
|
||||
|
||||
/* Load settings */
|
||||
p->storage = storage_open(NULL, SF_STORE);
|
||||
@@ -1283,6 +1426,8 @@ static struct sailfish_manager_priv *sailfish_manager_priv_new()
|
||||
p->pub.default_data_imsi = p->default_data_imsi =
|
||||
g_key_file_get_string(p->storage, SF_STORE_GROUP,
|
||||
SF_STORE_DEFAULT_DATA_SIM, NULL);
|
||||
p->auto_data_sim_done = g_key_file_get_boolean(p->storage,
|
||||
SF_STORE_GROUP, SF_STORE_AUTO_DATA_SIM_DONE, NULL);
|
||||
|
||||
DBG("Default voice sim is %s", p->default_voice_imsi ?
|
||||
p->default_voice_imsi : "(auto)");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2019 Jolla Ltd.
|
||||
* Copyright (C) 2017-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -13,6 +13,8 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2017 Jolla Ltd.
|
||||
* Copyright (C) 2013-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -136,38 +136,56 @@ static GSList *provision_pick_best_ap(GSList *list, const char *spn,
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the list containing exactly one INTERNET and one MMS access point */
|
||||
/**
|
||||
* Returns the list containing INTERNET, MMS and IMS access points,
|
||||
* always all three of them and always in this order.
|
||||
*/
|
||||
static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
|
||||
{
|
||||
static const struct provision_ap_defaults internet_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
|
||||
static const struct provision_ap_defaults mms_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
|
||||
static const struct provision_ap_defaults ims_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_IMS, "IMS", "ims" };
|
||||
|
||||
GSList *internet_apns = NULL;
|
||||
GSList *mms_apns = NULL;
|
||||
GSList *ims_apns = NULL;
|
||||
|
||||
/* Split internet and mms apns, delete all others */
|
||||
/* Build separate apn list for each type */
|
||||
while (apns) {
|
||||
GSList *link = apns;
|
||||
struct ofono_gprs_provision_data *ap = link->data;
|
||||
|
||||
apns = g_slist_remove_link(apns, link);
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
|
||||
switch (ap->type) {
|
||||
case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
|
||||
internet_apns = g_slist_concat(internet_apns, link);
|
||||
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
break;
|
||||
case OFONO_GPRS_CONTEXT_TYPE_MMS:
|
||||
mms_apns = g_slist_concat(mms_apns, link);
|
||||
} else {
|
||||
break;
|
||||
case OFONO_GPRS_CONTEXT_TYPE_IMS:
|
||||
ims_apns = g_slist_concat(ims_apns, link);
|
||||
break;
|
||||
default:
|
||||
g_slist_free_full(link, provision_free_ap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pick the best ap of each type and concatenate them */
|
||||
return g_slist_concat(
|
||||
provision_pick_best_ap(internet_apns, spn,
|
||||
mbpi_default_internet_proto, &internet_defaults),
|
||||
provision_pick_best_ap(mms_apns, spn,
|
||||
mbpi_default_mms_proto, &mms_defaults));
|
||||
/* Pick the best ap of each type */
|
||||
internet_apns = provision_pick_best_ap(internet_apns, spn,
|
||||
mbpi_default_internet_proto, &internet_defaults);
|
||||
mms_apns = provision_pick_best_ap(mms_apns, spn,
|
||||
mbpi_default_mms_proto, &mms_defaults);
|
||||
ims_apns = provision_pick_best_ap(ims_apns, spn,
|
||||
mbpi_default_ims_proto, &ims_defaults);
|
||||
|
||||
/* And concatenate them in the right order */
|
||||
return g_slist_concat(internet_apns, g_slist_concat(mms_apns,
|
||||
ims_apns));
|
||||
}
|
||||
|
||||
int provision_get_settings(const char *mcc, const char *mnc,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013 Jolla Ltd. All rights reserved.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLС. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
@@ -40,58 +42,42 @@
|
||||
|
||||
#define SMS_HISTORY_INTERFACE "org.ofono.SmsHistory"
|
||||
|
||||
gboolean sms_history_interface_registered = FALSE;
|
||||
|
||||
static const GDBusSignalTable sms_history_signals[] = {
|
||||
{ GDBUS_SIGNAL("StatusReport",
|
||||
GDBUS_ARGS({ "message", "s" }, { "Delivered", "a{b}" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void sms_history_cleanup(gpointer user)
|
||||
static int sms_history_probe(struct ofono_history_context *context)
|
||||
{
|
||||
struct ofono_modem *modem = user;
|
||||
DBG("modem %p", modem);
|
||||
ofono_modem_remove_interface(modem, SMS_HISTORY_INTERFACE);
|
||||
sms_history_interface_registered = FALSE;
|
||||
}
|
||||
|
||||
static gboolean sms_history_ensure_interface(
|
||||
struct ofono_modem *modem) {
|
||||
|
||||
if (sms_history_interface_registered)
|
||||
return TRUE;
|
||||
|
||||
/* Late initialization of the D-Bus interface */
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
if (conn == NULL)
|
||||
return FALSE;
|
||||
struct ofono_modem *modem = context->modem;
|
||||
|
||||
ofono_debug("SMS History Probe for modem: %p", modem);
|
||||
|
||||
if (!g_dbus_register_interface(conn,
|
||||
ofono_modem_get_path(modem),
|
||||
SMS_HISTORY_INTERFACE,
|
||||
NULL, sms_history_signals, NULL,
|
||||
modem, sms_history_cleanup)) {
|
||||
NULL, sms_history_signals,
|
||||
NULL, NULL, NULL)) {
|
||||
ofono_error("Could not create %s interface",
|
||||
SMS_HISTORY_INTERFACE);
|
||||
return FALSE;
|
||||
return -EIO;
|
||||
}
|
||||
sms_history_interface_registered = TRUE;
|
||||
|
||||
ofono_modem_add_interface(modem, SMS_HISTORY_INTERFACE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int sms_history_probe(struct ofono_history_context *context)
|
||||
{
|
||||
ofono_debug("SMS History Probe for modem: %p", context->modem);
|
||||
sms_history_ensure_interface(context->modem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sms_history_remove(struct ofono_history_context *context)
|
||||
{
|
||||
ofono_debug("SMS History Remove for modem: %p", context->modem);
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = context->modem;
|
||||
|
||||
ofono_debug("SMS History remove for modem: %p", modem);
|
||||
ofono_modem_remove_interface(modem, SMS_HISTORY_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, ofono_modem_get_path(modem),
|
||||
SMS_HISTORY_INTERFACE);
|
||||
}
|
||||
|
||||
static void sms_history_sms_send_status(
|
||||
@@ -102,9 +88,6 @@ static void sms_history_sms_send_status(
|
||||
{
|
||||
DBG("");
|
||||
|
||||
if (!sms_history_ensure_interface(context->modem))
|
||||
return;
|
||||
|
||||
if ((s == OFONO_HISTORY_SMS_STATUS_DELIVERED)
|
||||
|| (s == OFONO_HISTORY_SMS_STATUS_DELIVER_FAILED)) {
|
||||
|
||||
@@ -174,4 +157,3 @@ static void sms_history_exit(void)
|
||||
OFONO_PLUGIN_DEFINE(sms_history, "SMS History Plugin",
|
||||
VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
sms_history_init, sms_history_exit)
|
||||
|
||||
|
||||
@@ -1731,6 +1731,8 @@ static gboolean create_modem(gpointer key, gpointer value, gpointer user_data)
|
||||
continue;
|
||||
|
||||
if (driver_list[i].setup(modem) == TRUE) {
|
||||
ofono_modem_set_string(modem->modem, "SystemPath",
|
||||
syspath);
|
||||
ofono_modem_register(modem->modem);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
365
ofono/src/config.c
Normal file
365
ofono/src/config.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* The config_merge_files() function does the following:
|
||||
*
|
||||
* 1. Loads the specified key file (say, "/etc/foo.conf")
|
||||
* 2. Scans the subdirectory named after the file (e.g. "/etc/foo.d/")
|
||||
* for the files with the same suffix as the main file (e.g. "*.conf")
|
||||
* 3. Sorts the files from the subdirectory (alphabetically)
|
||||
* 4. Merges the contents of the additional files with the main file
|
||||
* according to their sort order.
|
||||
*
|
||||
* When the entries are merged, keys and groups overwrite the exising
|
||||
* ones by default. Keys can be suffixed with special characters to
|
||||
* remove or modify the existing entries instead:
|
||||
*
|
||||
* ':' Sets the (default) value if the key is missing
|
||||
* '+' Appends values to the string list
|
||||
* '?' Appends only new (non-existent) values to the string list
|
||||
* '-' Removes the values from the string list
|
||||
*
|
||||
* Both keys and groups can be prefixed with '!' to remove the entire key
|
||||
* or group.
|
||||
*
|
||||
* For example if we merge these two files:
|
||||
*
|
||||
* /etc/foo.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=4
|
||||
* d=5
|
||||
* [bar]
|
||||
* e=5
|
||||
*
|
||||
* /etc/foo.d/bar.conf:
|
||||
*
|
||||
* [foo]
|
||||
* a+=2
|
||||
* b-=2
|
||||
* c=5
|
||||
* !d
|
||||
* [!bar]
|
||||
*
|
||||
* we end up with this:
|
||||
*
|
||||
* [foo]
|
||||
* a=1
|
||||
* b=2,3
|
||||
* c=5
|
||||
*
|
||||
* Note that the list separator is assumed to be ',' (rather than default ';').
|
||||
* The keyfile passed to config_merge_files() should use the same list
|
||||
* separator, because the default values are copied from the config files
|
||||
* as is.
|
||||
*/
|
||||
|
||||
static gint config_sort_files(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
/* The comparison function for g_ptr_array_sort() doesn't take
|
||||
* the pointers from the array as arguments, it takes pointers
|
||||
* to the pointers in the array. */
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static char **config_collect_files(const char *path, const char *suffix)
|
||||
{
|
||||
/* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found. */
|
||||
char **files = NULL;
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
GPtrArray *list = g_ptr_array_new();
|
||||
const struct dirent *p;
|
||||
|
||||
while ((p = readdir(d)) != NULL) {
|
||||
/* No need to even stat . and .. */
|
||||
if (strcmp(p->d_name, ".") &&
|
||||
strcmp(p->d_name, "..") && (!suffix ||
|
||||
g_str_has_suffix(p->d_name, suffix))) {
|
||||
struct stat st;
|
||||
char *buf = g_strconcat(path, "/", p->d_name,
|
||||
NULL);
|
||||
|
||||
if (!stat(buf, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, buf);
|
||||
} else {
|
||||
g_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_sort(list, config_sort_files);
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**)g_ptr_array_free(list, FALSE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static int config_list_find(char **list, gsize len, const char *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(list[i], value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void config_list_append(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key,
|
||||
char **values, gsize n, gboolean unique)
|
||||
{
|
||||
/* Note: will steal strings from values */
|
||||
if (n > 0) {
|
||||
int i;
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
GPtrArray *newlist = g_ptr_array_new_full(0, g_free);
|
||||
|
||||
for (i = 0; i < (int)len; i++) {
|
||||
g_ptr_array_add(newlist, list[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)n; i++) {
|
||||
char *val = values[i];
|
||||
|
||||
if (!unique || config_list_find((char**)
|
||||
newlist->pdata, newlist->len, val) < 0) {
|
||||
/* Move the string to the new list */
|
||||
g_ptr_array_add(newlist, val);
|
||||
memmove(values + i, values + i + 1,
|
||||
sizeof(char*) * (n - i));
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (newlist->len > len) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) newlist->pdata,
|
||||
newlist->len);
|
||||
}
|
||||
|
||||
/* Strings are deallocated by GPtrArray */
|
||||
g_ptr_array_free(newlist, TRUE);
|
||||
g_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void config_list_remove(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group, const char *key, char **values, gsize n)
|
||||
{
|
||||
if (n > 0) {
|
||||
gsize len = 0;
|
||||
gchar **list = g_key_file_get_string_list(conf, group, key,
|
||||
&len, NULL);
|
||||
|
||||
if (len > 0) {
|
||||
gsize i;
|
||||
const gsize oldlen = len;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int pos;
|
||||
|
||||
/* Remove all matching values */
|
||||
while ((pos = config_list_find(list, len,
|
||||
values[i])) >= 0) {
|
||||
g_free(list[pos]);
|
||||
memmove(list + pos, list + pos + 1,
|
||||
sizeof(char*) * (len - pos));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < oldlen) {
|
||||
g_key_file_set_string_list(conf, group, key,
|
||||
(const gchar * const *) list, len);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
}
|
||||
|
||||
static void config_merge_group(GKeyFile *conf, GKeyFile *k,
|
||||
const char *group)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **keys = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
char *key = keys[i];
|
||||
|
||||
if (key[0] == '!') {
|
||||
if (key[1]) {
|
||||
g_key_file_remove_key(conf, group, key+1, NULL);
|
||||
}
|
||||
} else {
|
||||
const gsize len = strlen(key);
|
||||
const char last = (len > 0) ? key[len-1] : 0;
|
||||
|
||||
if (last == '+' || last == '?') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
config_list_append(conf, k, group, key,
|
||||
values, count, last == '?');
|
||||
g_strfreev(values);
|
||||
} else if (last == '-') {
|
||||
gsize count = 0;
|
||||
gchar **values = g_key_file_get_string_list(k,
|
||||
group, key, &count, NULL);
|
||||
|
||||
key[len-1] = 0;
|
||||
config_list_remove(conf, k, group, key,
|
||||
values, count);
|
||||
g_strfreev(values);
|
||||
} else {
|
||||
/* Overwrite the value (it must exist in k) */
|
||||
gchar *value = g_key_file_get_value(k, group,
|
||||
key, NULL);
|
||||
|
||||
if (last == ':') {
|
||||
/* Default value */
|
||||
key[len-1] = 0;
|
||||
if (!g_key_file_has_key(conf,
|
||||
group, key, NULL)) {
|
||||
g_key_file_set_value(conf,
|
||||
group, key, value);
|
||||
}
|
||||
} else {
|
||||
g_key_file_set_value(conf, group, key,
|
||||
value);
|
||||
}
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
static void config_merge_keyfile(GKeyFile *conf, GKeyFile *k)
|
||||
{
|
||||
gsize i, n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
const char *group = groups[i];
|
||||
|
||||
if (group[0] == '!') {
|
||||
g_key_file_remove_group(conf, group + 1, NULL);
|
||||
} else {
|
||||
config_merge_group(conf, k, group);
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
}
|
||||
|
||||
static void config_merge_file(GKeyFile *conf, const char *file)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
|
||||
if (g_key_file_load_from_file(k, file, 0, NULL)) {
|
||||
config_merge_keyfile(conf, k);
|
||||
}
|
||||
|
||||
g_key_file_unref(k);
|
||||
}
|
||||
|
||||
void config_merge_files(GKeyFile *conf, const char *file)
|
||||
{
|
||||
if (conf && file && file[0]) {
|
||||
char *dot = strrchr(file, '.');
|
||||
const char *suffix;
|
||||
char *dir;
|
||||
char **files;
|
||||
|
||||
if (!dot) {
|
||||
dir = g_strconcat(file, ".d", NULL);
|
||||
suffix = NULL;
|
||||
} else if (!dot[1]) {
|
||||
dir = g_strconcat(file, "d", NULL);
|
||||
suffix = NULL;
|
||||
} else {
|
||||
/* 2 bytes for ".d" and 1 for NULL terminator */
|
||||
dir = g_malloc(dot - file + 3);
|
||||
strncpy(dir, file, dot - file);
|
||||
strcpy(dir + (dot - file), ".d");
|
||||
suffix = dot + 1;
|
||||
}
|
||||
|
||||
files = config_collect_files(dir, suffix);
|
||||
g_free(dir);
|
||||
|
||||
/* Load the main config */
|
||||
if (g_file_test(file, G_FILE_TEST_EXISTS)) {
|
||||
DBG("Loading %s", file);
|
||||
config_merge_file(conf, file);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
char **ptr;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
DBG("Merging %s", *ptr);
|
||||
config_merge_file(conf, *ptr);
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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,6 +42,10 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf)
|
||||
return OFONO_MODEM_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS:
|
||||
return OFONO_RADIO_SETTINGS_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_STK:
|
||||
return OFONO_STK_INTERFACE;
|
||||
case OFONO_DBUS_ACCESS_INTF_OEMRAW:
|
||||
return "org.ofono.OemRaw";
|
||||
case OFONO_DBUS_ACCESS_INTF_COUNT:
|
||||
break;
|
||||
}
|
||||
@@ -165,6 +170,22 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OFONO_DBUS_ACCESS_INTF_STK:
|
||||
switch ((enum ofono_dbus_access_stk_method)method) {
|
||||
case OFONO_DBUS_ACCESS_STK_REGISTER_AGENT:
|
||||
return "RegisterAgent";
|
||||
case OFONO_DBUS_ACCESS_STK_METHOD_COUNT:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OFONO_DBUS_ACCESS_INTF_OEMRAW:
|
||||
switch ((enum ofono_dbus_access_oemraw_method)method) {
|
||||
case OFONO_DBUS_ACCESS_OEMRAW_SEND:
|
||||
return "Send";
|
||||
case OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OFONO_DBUS_ACCESS_INTF_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
182
ofono/src/dbus-clients.c
Normal file
182
ofono/src/dbus-clients.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017-2018 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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 <ofono/dbus-clients.h>
|
||||
#include <ofono/gdbus.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
struct ofono_dbus_client {
|
||||
struct ofono_dbus_clients *clients;
|
||||
char *name;
|
||||
unsigned int watch_id;
|
||||
};
|
||||
|
||||
struct ofono_dbus_clients {
|
||||
DBusConnection* conn;
|
||||
GHashTable* table;
|
||||
ofono_dbus_clients_notify_func notify;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
/* Compatible with GDestroyNotify */
|
||||
static void ofono_dbus_client_free(struct ofono_dbus_client *client)
|
||||
{
|
||||
struct ofono_dbus_clients *clients = client->clients;
|
||||
|
||||
/* Callers make sure that client parameter is not NULL */
|
||||
if (client->watch_id) {
|
||||
g_dbus_remove_watch(clients->conn, client->watch_id);
|
||||
}
|
||||
g_free(client->name);
|
||||
g_slice_free(struct ofono_dbus_client, client);
|
||||
}
|
||||
|
||||
static void ofono_dbus_clients_disconnect_notify(DBusConnection *connection,
|
||||
void *user_data)
|
||||
{
|
||||
struct ofono_dbus_client *client = user_data;
|
||||
struct ofono_dbus_clients *self = client->clients;
|
||||
char *name = client->name;
|
||||
|
||||
/*
|
||||
* Steal the name so that it doesn't get freed by
|
||||
* ofono_dbus_client_free(). We want to pass it to
|
||||
* the callback but first we need to delete client's
|
||||
* entry from the hashtable.
|
||||
*/
|
||||
client->name = NULL;
|
||||
DBG("%s is gone", name);
|
||||
g_hash_table_remove(self->table, name);
|
||||
if (self->notify) {
|
||||
self->notify(name, self->user_data);
|
||||
}
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
|
||||
ofono_dbus_clients_notify_func notify, void *user_data)
|
||||
{
|
||||
if (conn) {
|
||||
struct ofono_dbus_clients *self =
|
||||
g_slice_new0(struct ofono_dbus_clients);
|
||||
|
||||
self->conn = dbus_connection_ref(conn);
|
||||
self->table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) ofono_dbus_client_free);
|
||||
self->notify = notify;
|
||||
self->user_data = user_data;
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_free(struct ofono_dbus_clients *self)
|
||||
{
|
||||
if (self) {
|
||||
g_hash_table_destroy(self->table);
|
||||
dbus_connection_unref(self->conn);
|
||||
g_slice_free(struct ofono_dbus_clients, self);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *self)
|
||||
{
|
||||
return self ? g_hash_table_size(self->table) : 0;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *self,
|
||||
const char *name)
|
||||
{
|
||||
if (self && name) {
|
||||
struct ofono_dbus_client *client =
|
||||
g_slice_new0(struct ofono_dbus_client);
|
||||
|
||||
client->clients = self;
|
||||
client->name = g_strdup(name);
|
||||
client->watch_id = g_dbus_add_disconnect_watch(self->conn,
|
||||
client->name, ofono_dbus_clients_disconnect_notify,
|
||||
client, NULL);
|
||||
|
||||
if (client->watch_id) {
|
||||
DBG("%s is registered", client->name);
|
||||
g_hash_table_replace(self->table, (gpointer)
|
||||
client->name, client);
|
||||
return TRUE;
|
||||
} else {
|
||||
DBG("failed to register %s", client->name);
|
||||
ofono_dbus_client_free(client);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *self,
|
||||
const char *name)
|
||||
{
|
||||
return self && name && g_hash_table_remove(self->table, name);
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_signal(struct ofono_dbus_clients *self,
|
||||
DBusMessage *signal)
|
||||
{
|
||||
if (self && signal && g_hash_table_size(self->table)) {
|
||||
GHashTableIter it;
|
||||
gpointer key;
|
||||
const char *last_name = NULL;
|
||||
|
||||
g_hash_table_iter_init(&it, self->table);
|
||||
g_hash_table_iter_next(&it, &key, NULL);
|
||||
last_name = key;
|
||||
|
||||
while (g_hash_table_iter_next(&it, &key, NULL)) {
|
||||
DBusMessage *copy = dbus_message_copy(signal);
|
||||
|
||||
dbus_message_set_destination(copy, key);
|
||||
g_dbus_send_message(self->conn, copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* The last one. Note that g_dbus_send_message() unrefs
|
||||
* the message, we need compensate for that by adding a
|
||||
* reference. The caller still owns the message when this
|
||||
* function returns.
|
||||
*/
|
||||
dbus_message_ref(signal);
|
||||
dbus_message_set_destination(signal, last_name);
|
||||
g_dbus_send_message(self->conn, signal);
|
||||
}
|
||||
}
|
||||
|
||||
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *self,
|
||||
const char *path, const char *interface, const char *name,
|
||||
int type, const void *value)
|
||||
{
|
||||
if (self && g_hash_table_size(self->table)) {
|
||||
DBusMessage *sig = ofono_dbus_signal_new_property_changed(path,
|
||||
interface, name, type, value);
|
||||
|
||||
ofono_dbus_clients_signal(self, sig);
|
||||
dbus_message_unref(sig);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -121,6 +121,30 @@ void __ofono_dbus_queue_request(struct ofono_dbus_queue *q,
|
||||
}
|
||||
}
|
||||
|
||||
static void __ofono_dbus_queue_submit_next(struct ofono_dbus_queue *q)
|
||||
{
|
||||
struct ofono_dbus_queue_request *next = q->requests;
|
||||
|
||||
while (next) {
|
||||
struct ofono_dbus_queue_request *done;
|
||||
DBusMessage *reply = next->fn(next->msg, next->data);
|
||||
|
||||
/* The request has been sent, no reply yet */
|
||||
if (!reply)
|
||||
break;
|
||||
|
||||
/* The request has completed synchronously */
|
||||
done = next;
|
||||
next = done->next;
|
||||
q->requests = next;
|
||||
done->next = NULL;
|
||||
|
||||
/* Send the reply */
|
||||
__ofono_dbus_pending_reply(&done->msg, reply);
|
||||
__ofono_dbus_queue_req_free(done);
|
||||
}
|
||||
}
|
||||
|
||||
/* Consumes one reference to the reply */
|
||||
void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
|
||||
DBusMessage *reply)
|
||||
@@ -150,20 +174,7 @@ void __ofono_dbus_queue_reply_msg(struct ofono_dbus_queue *q,
|
||||
__ofono_dbus_queue_req_free(done);
|
||||
|
||||
/* Submit the next request if there is any */
|
||||
while (next && reply) {
|
||||
reply = next->fn(next->msg, next->data);
|
||||
if (reply) {
|
||||
/* The request has completed synchronously */
|
||||
done = next;
|
||||
next = done->next;
|
||||
q->requests = next;
|
||||
done->next = NULL;
|
||||
|
||||
/* Send the reply */
|
||||
__ofono_dbus_pending_reply(&done->msg, reply);
|
||||
__ofono_dbus_queue_req_free(done);
|
||||
}
|
||||
}
|
||||
__ofono_dbus_queue_submit_next(q);
|
||||
}
|
||||
|
||||
void __ofono_dbus_queue_reply_ok(struct ofono_dbus_queue *q)
|
||||
@@ -250,8 +261,10 @@ void __ofono_dbus_queue_reply_all_fn_param(struct ofono_dbus_queue *q,
|
||||
* Find all other requests with the same handler and the same data
|
||||
* and complete those too (except when the handler is NULL)
|
||||
*/
|
||||
if (!handler)
|
||||
if (!handler) {
|
||||
__ofono_dbus_queue_submit_next(q);
|
||||
return;
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
req = q->requests;
|
||||
@@ -274,6 +287,7 @@ void __ofono_dbus_queue_reply_all_fn_param(struct ofono_dbus_queue *q,
|
||||
|
||||
req = next;
|
||||
}
|
||||
__ofono_dbus_queue_submit_next(q);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2021 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
|
||||
@@ -13,10 +14,6 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -29,8 +26,6 @@
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
|
||||
|
||||
static DBusConnection *g_connection;
|
||||
|
||||
struct error_mapping_entry {
|
||||
@@ -209,8 +204,8 @@ void ofono_dbus_dict_append_dict(DBusMessageIter *dict, const char *key,
|
||||
dbus_message_iter_close_container(dict, &entry);
|
||||
}
|
||||
|
||||
int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
const char *path,
|
||||
/* Since mer/1.23+git31 */
|
||||
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value)
|
||||
@@ -219,11 +214,8 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
DBusMessageIter iter;
|
||||
|
||||
signal = dbus_message_new_signal(path, interface, "PropertyChanged");
|
||||
if (signal == NULL) {
|
||||
ofono_error("Unable to allocate new %s.PropertyChanged signal",
|
||||
interface);
|
||||
return -1;
|
||||
}
|
||||
if (signal == NULL)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
|
||||
@@ -231,6 +223,24 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
|
||||
append_variant(&iter, type, value);
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
int ofono_dbus_signal_property_changed(DBusConnection *conn,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *name,
|
||||
int type, const void *value)
|
||||
{
|
||||
DBusMessage *signal = ofono_dbus_signal_new_property_changed(path,
|
||||
interface, name, type, value);
|
||||
|
||||
if (signal == NULL) {
|
||||
ofono_error("Unable to allocate new %s.PropertyChanged signal",
|
||||
interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return g_dbus_send_message(conn, signal);
|
||||
}
|
||||
|
||||
|
||||
137
ofono/src/gprs.c
137
ofono/src/gprs.c
@@ -3,7 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -97,6 +97,7 @@ struct ipv4_settings {
|
||||
char *netmask;
|
||||
char *gateway;
|
||||
char **dns;
|
||||
char **pcscf;
|
||||
char *proxy;
|
||||
};
|
||||
|
||||
@@ -105,6 +106,7 @@ struct ipv6_settings {
|
||||
unsigned char prefix_len;
|
||||
char *gateway;
|
||||
char **dns;
|
||||
char **pcscf;
|
||||
};
|
||||
|
||||
struct context_settings {
|
||||
@@ -410,6 +412,7 @@ static void context_settings_free(struct context_settings *settings)
|
||||
g_free(settings->ipv4->netmask);
|
||||
g_free(settings->ipv4->gateway);
|
||||
g_strfreev(settings->ipv4->dns);
|
||||
g_strfreev(settings->ipv4->pcscf);
|
||||
g_free(settings->ipv4->proxy);
|
||||
|
||||
g_free(settings->ipv4);
|
||||
@@ -420,6 +423,7 @@ static void context_settings_free(struct context_settings *settings)
|
||||
g_free(settings->ipv6->ip);
|
||||
g_free(settings->ipv6->gateway);
|
||||
g_strfreev(settings->ipv6->dns);
|
||||
g_strfreev(settings->ipv6->pcscf);
|
||||
|
||||
g_free(settings->ipv6);
|
||||
settings->ipv6 = NULL;
|
||||
@@ -484,6 +488,11 @@ static void context_settings_append_ipv4(struct context_settings *settings,
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv4->dns);
|
||||
|
||||
if (settings->ipv4->pcscf)
|
||||
ofono_dbus_dict_append_array(&array, "ProxyCSCF",
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv4->pcscf);
|
||||
|
||||
done:
|
||||
dbus_message_iter_close_container(&variant, &array);
|
||||
|
||||
@@ -549,6 +558,11 @@ static void context_settings_append_ipv6(struct context_settings *settings,
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv6->dns);
|
||||
|
||||
if (settings->ipv6->pcscf)
|
||||
ofono_dbus_dict_append_array(&array, "ProxyCSCF",
|
||||
DBUS_TYPE_STRING,
|
||||
&settings->ipv6->pcscf);
|
||||
|
||||
done:
|
||||
dbus_message_iter_close_container(&variant, &array);
|
||||
|
||||
@@ -2874,12 +2888,53 @@ static void provision_contexts(struct ofono_gprs *gprs, const char *mcc,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
provision_context(&settings[i], gprs);
|
||||
for (i = 0; i < count; i++) {
|
||||
const struct ofono_gprs_provision_data *ap = settings + i;
|
||||
|
||||
if (!ofono_gprs_context_settings_by_type(gprs, ap->type)) {
|
||||
provision_context(ap, gprs);
|
||||
}
|
||||
}
|
||||
|
||||
__ofono_gprs_provision_free_settings(settings, count);
|
||||
}
|
||||
|
||||
static gboolean all_contexts_configured(struct ofono_gprs *gprs)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = gprs->context_drivers; l; l = l->next) {
|
||||
struct ofono_gprs_context *gc = l->data;
|
||||
|
||||
if (gc->type != OFONO_GPRS_CONTEXT_TYPE_ANY &&
|
||||
!ofono_gprs_context_settings_by_type(gprs, gc->type)) {
|
||||
return FALSE; /* Not yet */
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void configure_remaining_contexts(struct ofono_gprs *gprs)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = gprs->context_drivers; l; l = l->next) {
|
||||
struct ofono_gprs_context *gc = l->data;
|
||||
|
||||
if (gc->type != OFONO_GPRS_CONTEXT_TYPE_ANY &&
|
||||
!ofono_gprs_context_settings_by_type(gprs, gc->type)) {
|
||||
add_context(gprs, NULL, gc->type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure internet context is there */
|
||||
if (!ofono_gprs_context_settings_by_type(gprs,
|
||||
OFONO_GPRS_CONTEXT_TYPE_INTERNET)) {
|
||||
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_non_active_context(struct ofono_gprs *gprs,
|
||||
struct pri_context *ctx, DBusConnection *conn)
|
||||
{
|
||||
@@ -2960,8 +3015,7 @@ static DBusMessage *gprs_reset_contexts(DBusConnection *conn,
|
||||
provision_contexts(gprs, ofono_sim_get_mcc(sim),
|
||||
ofono_sim_get_mnc(sim), ofono_sim_get_spn(sim));
|
||||
|
||||
if (gprs->contexts == NULL) /* Automatic provisioning failed */
|
||||
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
configure_remaining_contexts(gprs);
|
||||
|
||||
for (l = gprs->contexts; l; l = l->next) {
|
||||
struct pri_context *ctx = l->data;
|
||||
@@ -3377,6 +3431,18 @@ void ofono_gprs_context_set_ipv4_dns_servers(struct ofono_gprs_context *gc,
|
||||
settings->ipv4->dns = g_strdupv((char **) dns);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv4_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf)
|
||||
{
|
||||
struct context_settings *settings = gc->settings;
|
||||
|
||||
if (settings->ipv4 == NULL)
|
||||
return;
|
||||
|
||||
g_strfreev(settings->ipv4->pcscf);
|
||||
settings->ipv4->pcscf = g_strdupv((char **) pcscf);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
|
||||
const char *address)
|
||||
{
|
||||
@@ -3424,6 +3490,18 @@ void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
|
||||
settings->ipv6->dns = g_strdupv((char **) dns);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_set_ipv6_proxy_cscf(struct ofono_gprs_context *gc,
|
||||
const char **pcscf)
|
||||
{
|
||||
struct context_settings *settings = gc->settings;
|
||||
|
||||
if (settings->ipv6 == NULL)
|
||||
return;
|
||||
|
||||
g_strfreev(settings->ipv6->pcscf);
|
||||
settings->ipv6->pcscf = g_strdupv((char **) pcscf);
|
||||
}
|
||||
|
||||
void ofono_gprs_context_signal_change(struct ofono_gprs_context *gc,
|
||||
unsigned int cid)
|
||||
{
|
||||
@@ -3832,8 +3910,7 @@ static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
|
||||
const char *path = __ofono_atom_get_path(gprs->atom);
|
||||
|
||||
if (gprs->contexts == NULL) /* Automatic provisioning failed */
|
||||
add_context(gprs, NULL, OFONO_GPRS_CONTEXT_TYPE_INTERNET);
|
||||
configure_remaining_contexts(gprs);
|
||||
|
||||
if (!g_dbus_register_interface(conn, path,
|
||||
OFONO_CONNECTION_MANAGER_INTERFACE,
|
||||
@@ -3856,56 +3933,14 @@ static void ofono_gprs_finish_register(struct ofono_gprs *gprs)
|
||||
__ofono_atom_register(gprs->atom, gprs_unregister);
|
||||
}
|
||||
|
||||
static gboolean mms_context_configured(struct ofono_gprs *gprs)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = gprs->contexts; l; l = l->next) {
|
||||
struct pri_context *ctx = l->data;
|
||||
|
||||
if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void provision_mms_context(struct ofono_gprs *gprs, const char *mcc,
|
||||
const char *mnc, const char *spn)
|
||||
{
|
||||
struct ofono_gprs_provision_data *settings;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (__ofono_gprs_provision_get_settings(mcc, mnc, spn,
|
||||
&settings, &count) == FALSE) {
|
||||
ofono_warn("Provisioning failed");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (settings[i].type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
provision_context(&settings[i], gprs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
__ofono_gprs_provision_free_settings(settings, count);
|
||||
}
|
||||
|
||||
static void spn_read_cb(const char *spn, const char *dc, void *data)
|
||||
{
|
||||
struct ofono_gprs *gprs = data;
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(gprs->atom);
|
||||
struct ofono_sim *sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
|
||||
|
||||
if (gprs->contexts == NULL) {
|
||||
provision_contexts(gprs, ofono_sim_get_mcc(sim),
|
||||
provision_contexts(gprs, ofono_sim_get_mcc(sim),
|
||||
ofono_sim_get_mnc(sim), spn);
|
||||
} else if (!mms_context_configured(gprs)) {
|
||||
provision_mms_context(gprs, ofono_sim_get_mcc(sim),
|
||||
ofono_sim_get_mnc(sim), spn);
|
||||
}
|
||||
|
||||
ofono_sim_remove_spn_watch(sim, &gprs->spn_watch);
|
||||
|
||||
@@ -3927,7 +3962,7 @@ void ofono_gprs_register(struct ofono_gprs *gprs)
|
||||
|
||||
gprs_load_settings(gprs, ofono_sim_get_imsi(sim));
|
||||
|
||||
if (mms_context_configured(gprs))
|
||||
if (all_contexts_configured(gprs))
|
||||
goto finish;
|
||||
|
||||
ofono_sim_add_spn_watch(sim, &gprs->spn_watch, spn_read_cb, gprs, NULL);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -281,7 +283,7 @@ int main(int argc, char **argv)
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, OFONO_SERVICE, &error);
|
||||
conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &error);
|
||||
if (conn == NULL) {
|
||||
if (dbus_error_is_set(&error) == TRUE) {
|
||||
ofono_error("Unable to hop onto D-Bus: %s",
|
||||
@@ -308,7 +310,12 @@ int main(int argc, char **argv)
|
||||
g_free(option_plugin);
|
||||
g_free(option_noplugin);
|
||||
|
||||
g_main_loop_run(event_loop);
|
||||
if (g_dbus_request_name(conn, OFONO_SERVICE, &error)) {
|
||||
g_main_loop_run(event_loop);
|
||||
} else {
|
||||
ofono_error("Unable to register D-Bus name: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
__ofono_plugin_cleanup();
|
||||
|
||||
|
||||
@@ -805,6 +805,7 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
|
||||
struct ofono_devinfo *info;
|
||||
dbus_bool_t emergency = ofono_modem_get_emergency_mode(modem);
|
||||
const char *strtype;
|
||||
const char *system_path;
|
||||
|
||||
ofono_dbus_dict_append(dict, "Online", DBUS_TYPE_BOOLEAN,
|
||||
&modem->online);
|
||||
@@ -845,6 +846,11 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
|
||||
&info->svn);
|
||||
}
|
||||
|
||||
system_path = ofono_modem_get_string(modem, "SystemPath");
|
||||
if (system_path)
|
||||
ofono_dbus_dict_append(dict, "SystemPath", DBUS_TYPE_STRING,
|
||||
&system_path);
|
||||
|
||||
interfaces = g_new0(char *, g_slist_length(modem->interface_list) + 1);
|
||||
for (i = 0, l = modem->interface_list; l; l = l->next, i++)
|
||||
interfaces[i] = l->data;
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 Jolla Ltd.
|
||||
* Copyright (C) 2015-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -282,6 +283,10 @@ enum ofono_gprs_context_type __ofono_gprs_context_get_assigned_type(
|
||||
struct ofono_gprs_context *gc);
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
enum ofono_radio_access_mode __ofono_radio_access_max_mode(
|
||||
enum ofono_radio_access_mode modes);
|
||||
|
||||
#include <ofono/audio-settings.h>
|
||||
#include <ofono/ctm.h>
|
||||
#include <ofono/location-reporting.h>
|
||||
@@ -383,6 +388,7 @@ unsigned short __ofono_sms_get_next_ref(struct ofono_sms *sms);
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
struct sim_aid;
|
||||
struct ofono_sim_aid_session;
|
||||
enum sim_app_type;
|
||||
|
||||
@@ -421,7 +427,7 @@ void __ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
|
||||
unsigned int id);
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_aid(
|
||||
struct ofono_sim *sim, unsigned char *aid);
|
||||
struct ofono_sim *sim, const struct sim_aid *aid);
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_type(
|
||||
struct ofono_sim *sim, enum sim_app_type type);
|
||||
@@ -431,7 +437,7 @@ int __ofono_sim_session_get_id(struct ofono_sim_aid_session *session);
|
||||
enum sim_app_type __ofono_sim_session_get_type(
|
||||
struct ofono_sim_aid_session *session);
|
||||
|
||||
unsigned char *__ofono_sim_session_get_aid(
|
||||
const struct sim_aid *__ofono_sim_session_get_aid(
|
||||
struct ofono_sim_aid_session *session);
|
||||
|
||||
const char *__ofono_sim_get_impi(struct ofono_sim *sim);
|
||||
@@ -684,3 +690,6 @@ int mnclength(int mcc, int mnc);
|
||||
#include <ofono/netmon.h>
|
||||
#include <ofono/lte.h>
|
||||
#include <ofono/ims.h>
|
||||
|
||||
void __ofono_set_config_dir(const char *dir);
|
||||
void config_merge_files(GKeyFile *conf, const char *file);
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#pragma message("PLUGINDIR="PLUGINDIR)
|
||||
|
||||
static GSList *plugins = NULL;
|
||||
|
||||
struct ofono_plugin {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* Copyright (C) 2014-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -61,10 +62,22 @@ struct ofono_radio_settings {
|
||||
struct ofono_atom *atom;
|
||||
};
|
||||
|
||||
enum ofono_radio_access_mode __ofono_radio_access_max_mode(
|
||||
enum ofono_radio_access_mode mask)
|
||||
{
|
||||
return (mask & OFONO_RADIO_ACCESS_MODE_LTE) ?
|
||||
OFONO_RADIO_ACCESS_MODE_LTE :
|
||||
(mask & OFONO_RADIO_ACCESS_MODE_UMTS) ?
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS :
|
||||
(mask & OFONO_RADIO_ACCESS_MODE_GSM) ?
|
||||
OFONO_RADIO_ACCESS_MODE_GSM :
|
||||
OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
|
||||
#define radio_access_mode_to_string ofono_radio_access_mode_to_string
|
||||
const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
|
||||
{
|
||||
switch (m) {
|
||||
switch (__ofono_radio_access_max_mode(m)) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
return "any";
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
@@ -76,6 +89,10 @@ const char *ofono_radio_access_mode_to_string(enum ofono_radio_access_mode m)
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return (m == OFONO_RADIO_ACCESS_MODE_ANY) ? "any" :
|
||||
(m & OFONO_RADIO_ACCESS_MODE_LTE) ? "lte" :
|
||||
(m & OFONO_RADIO_ACCESS_MODE_UMTS) ? "umts" :
|
||||
(m & OFONO_RADIO_ACCESS_MODE_GSM) ? "gsm" : NULL;
|
||||
}
|
||||
#define radio_access_mode_from_string ofono_radio_access_mode_from_string
|
||||
ofono_bool_t ofono_radio_access_mode_from_string(const char *str,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -62,7 +63,7 @@ struct auth_request {
|
||||
};
|
||||
|
||||
struct aid_object {
|
||||
uint8_t aid[16];
|
||||
struct sim_aid aid;
|
||||
char *path;
|
||||
enum sim_app_type type;
|
||||
};
|
||||
@@ -82,7 +83,7 @@ struct ofono_sim_auth {
|
||||
/*
|
||||
* Find an application by path. 'path' should be a DBusMessage object path.
|
||||
*/
|
||||
static uint8_t *find_aid_by_path(GSList *aid_objects,
|
||||
static const struct aid_object *find_aid_by_path(GSList *aid_objects,
|
||||
const char *path)
|
||||
{
|
||||
GSList *iter = aid_objects;
|
||||
@@ -91,7 +92,7 @@ static uint8_t *find_aid_by_path(GSList *aid_objects,
|
||||
struct aid_object *obj = iter->data;
|
||||
|
||||
if (!strcmp(path, obj->path))
|
||||
return obj->aid;
|
||||
return obj;
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
}
|
||||
@@ -139,8 +140,17 @@ static void sim_auth_unregister(struct ofono_atom *atom)
|
||||
struct ofono_sim_auth *sa = __ofono_atom_get_data(atom);
|
||||
|
||||
free_apps(sa);
|
||||
g_free(sa->nai);
|
||||
|
||||
g_free(sa->pending);
|
||||
if (sa->pending) {
|
||||
__ofono_dbus_pending_reply(&sa->pending->msg,
|
||||
__ofono_error_sim_not_ready(sa->pending->msg));
|
||||
|
||||
__ofono_sim_remove_session_watch(sa->pending->session,
|
||||
sa->pending->watch_id);
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sim_auth_remove(struct ofono_atom *atom)
|
||||
@@ -199,14 +209,10 @@ static void handle_umts(struct ofono_sim_auth *sa, const uint8_t *resp,
|
||||
DBusMessage *reply = NULL;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter dict;
|
||||
const uint8_t *res = NULL;
|
||||
const uint8_t *ck = NULL;
|
||||
const uint8_t *ik = NULL;
|
||||
const uint8_t *auts = NULL;
|
||||
const uint8_t *kc = NULL;
|
||||
struct data_block res, ck, ik, auts, sres, kc;
|
||||
|
||||
if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik,
|
||||
&auts, &kc))
|
||||
&auts, &sres, &kc))
|
||||
goto umts_end;
|
||||
|
||||
reply = dbus_message_new_method_return(sa->pending->msg);
|
||||
@@ -216,15 +222,23 @@ static void handle_umts(struct ofono_sim_auth *sa, const uint8_t *resp,
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
"{say}", &dict);
|
||||
|
||||
if (auts) {
|
||||
append_dict_byte_array(&dict, "AUTS", auts, 14);
|
||||
} else {
|
||||
append_dict_byte_array(&dict, "RES", res, 8);
|
||||
append_dict_byte_array(&dict, "CK", ck, 16);
|
||||
append_dict_byte_array(&dict, "IK", ik, 16);
|
||||
if (kc)
|
||||
append_dict_byte_array(&dict, "Kc", kc, 8);
|
||||
}
|
||||
if (auts.data)
|
||||
append_dict_byte_array(&dict, "AUTS", auts.data, auts.len);
|
||||
|
||||
if (sres.data)
|
||||
append_dict_byte_array(&dict, "SRES", sres.data, sres.len);
|
||||
|
||||
if (res.data)
|
||||
append_dict_byte_array(&dict, "RES", res.data, res.len);
|
||||
|
||||
if (ck.data)
|
||||
append_dict_byte_array(&dict, "CK", ck.data, ck.len);
|
||||
|
||||
if (ik.data)
|
||||
append_dict_byte_array(&dict, "IK", ik.data, ik.len);
|
||||
|
||||
if (kc.data)
|
||||
append_dict_byte_array(&dict, "Kc", kc.data, kc.len);
|
||||
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
|
||||
@@ -359,6 +373,8 @@ static void get_session_cb(ofono_bool_t active, int session_id,
|
||||
error:
|
||||
__ofono_dbus_pending_reply(&sa->pending->msg,
|
||||
__ofono_error_failed(sa->pending->msg));
|
||||
__ofono_sim_remove_session_watch(sa->pending->session,
|
||||
sa->pending->watch_id);
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
}
|
||||
@@ -369,7 +385,7 @@ static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
|
||||
struct ofono_sim_auth *sa = data;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter array;
|
||||
uint8_t *aid;
|
||||
const struct aid_object *obj;
|
||||
|
||||
if (sa->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
@@ -409,13 +425,20 @@ static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
|
||||
/*
|
||||
* retrieve session from SIM
|
||||
*/
|
||||
aid = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim, aid);
|
||||
obj = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim,
|
||||
&obj->aid);
|
||||
sa->pending->msg = dbus_message_ref(msg);
|
||||
sa->pending->watch_id = __ofono_sim_add_session_watch(
|
||||
sa->pending->session, get_session_cb, sa, NULL);
|
||||
|
||||
return NULL;
|
||||
if (!sa->pending->watch_id) {
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
return __ofono_error_not_supported(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
format_error:
|
||||
g_free(sa->pending);
|
||||
@@ -431,7 +454,7 @@ static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
|
||||
uint32_t rlen;
|
||||
uint32_t alen;
|
||||
struct ofono_sim_auth *sa = data;
|
||||
uint8_t *aid;
|
||||
const struct aid_object *obj;
|
||||
|
||||
if (sa->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
@@ -456,12 +479,18 @@ static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
|
||||
/*
|
||||
* retrieve session from SIM
|
||||
*/
|
||||
aid = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim, aid);
|
||||
|
||||
obj = find_aid_by_path(sa->aid_objects, dbus_message_get_path(msg));
|
||||
sa->pending->session = __ofono_sim_get_session_by_aid(sa->sim,
|
||||
&obj->aid);
|
||||
sa->pending->watch_id = __ofono_sim_add_session_watch(
|
||||
sa->pending->session, get_session_cb, sa, NULL);
|
||||
|
||||
if (!sa->pending->watch_id) {
|
||||
g_free(sa->pending);
|
||||
sa->pending = NULL;
|
||||
return __ofono_error_not_supported(msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -691,14 +720,15 @@ static void sim_auth_register(struct ofono_sim_auth *sa)
|
||||
|
||||
ret = sprintf(new->path, "%s/", path);
|
||||
|
||||
encode_hex_own_buf(r->aid, 16, 0, new->path + ret);
|
||||
encode_hex_own_buf(r->aid.aid, r->aid.len, 0,
|
||||
new->path + ret);
|
||||
|
||||
g_dbus_register_interface(conn, new->path,
|
||||
OFONO_USIM_APPLICATION_INTERFACE,
|
||||
sim_auth_usim_app, NULL, NULL,
|
||||
sa, NULL);
|
||||
|
||||
memcpy(new->aid, r->aid, 16);
|
||||
new->aid = r->aid;
|
||||
|
||||
break;
|
||||
case SIM_APP_TYPE_ISIM:
|
||||
@@ -706,14 +736,15 @@ static void sim_auth_register(struct ofono_sim_auth *sa)
|
||||
|
||||
ret = sprintf(new->path, "%s/", path);
|
||||
|
||||
encode_hex_own_buf(r->aid, 16, 0, new->path + ret);
|
||||
encode_hex_own_buf(r->aid.aid, r->aid.len, 0,
|
||||
new->path + ret);
|
||||
|
||||
g_dbus_register_interface(conn, new->path,
|
||||
OFONO_ISIM_APPLICATION_INTERFACE,
|
||||
sim_auth_isim_app, NULL, NULL,
|
||||
sa, NULL);
|
||||
|
||||
memcpy(new->aid, r->aid, 16);
|
||||
new->aid = r->aid;
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -2441,7 +2442,7 @@ struct ofono_sim_context *ofono_sim_context_create_isim(
|
||||
|
||||
if (session->record->type == SIM_APP_TYPE_ISIM) {
|
||||
return sim_fs_context_new_with_aid(sim->simfs_isim,
|
||||
session->record->aid);
|
||||
&session->record->aid);
|
||||
}
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
@@ -3667,6 +3668,26 @@ const char *__ofono_sim_get_impi(struct ofono_sim *sim)
|
||||
static void open_channel_cb(const struct ofono_error *error, int session_id,
|
||||
void *data);
|
||||
|
||||
static gboolean open_channel(struct ofono_sim_aid_session *session)
|
||||
{
|
||||
struct ofono_sim *sim = session->sim;
|
||||
const struct ofono_sim_driver *driver = sim->driver;
|
||||
const struct sim_aid *aid = &session->record->aid;
|
||||
|
||||
if (driver->open_channel2) {
|
||||
driver->open_channel2(sim, aid->aid, aid->len, open_channel_cb,
|
||||
session);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (driver->open_channel && aid->len == 16) {
|
||||
driver->open_channel(sim, aid->aid, open_channel_cb, session);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void close_channel_cb(const struct ofono_error *error, void *data)
|
||||
{
|
||||
struct ofono_sim_aid_session *session = data;
|
||||
@@ -3680,10 +3701,8 @@ static void close_channel_cb(const struct ofono_error *error, void *data)
|
||||
* An atom requested to open during a close, we can re-open
|
||||
* here.
|
||||
*/
|
||||
session->sim->driver->open_channel(session->sim,
|
||||
session->record->aid, open_channel_cb,
|
||||
session);
|
||||
return;
|
||||
if (open_channel(session))
|
||||
return;
|
||||
}
|
||||
|
||||
session->state = SESSION_STATE_INACTIVE;
|
||||
@@ -3758,10 +3777,12 @@ unsigned int __ofono_sim_add_session_watch(
|
||||
* If the session is inactive and there are no watchers, open
|
||||
* a new session.
|
||||
*/
|
||||
session->state = SESSION_STATE_OPENING;
|
||||
session->sim->driver->open_channel(session->sim,
|
||||
session->record->aid, open_channel_cb,
|
||||
session);
|
||||
if (open_channel(session)) {
|
||||
session->state = SESSION_STATE_OPENING;
|
||||
} else {
|
||||
g_free(item);
|
||||
return 0;
|
||||
}
|
||||
} else if (session->state == SESSION_STATE_OPEN) {
|
||||
/*
|
||||
* Session is already open and available, just call the
|
||||
@@ -3784,7 +3805,8 @@ void __ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
|
||||
{
|
||||
__ofono_watchlist_remove_item(session->watches, id);
|
||||
|
||||
if (g_slist_length(session->watches->items) == 0) {
|
||||
if (g_slist_length(session->watches->items) == 0 &&
|
||||
session->state == SESSION_STATE_OPEN) {
|
||||
/* last watcher, close session */
|
||||
session->state = SESSION_STATE_CLOSING;
|
||||
session->sim->driver->close_channel(session->sim,
|
||||
@@ -3793,14 +3815,15 @@ void __ofono_sim_remove_session_watch(struct ofono_sim_aid_session *session,
|
||||
}
|
||||
|
||||
struct ofono_sim_aid_session *__ofono_sim_get_session_by_aid(
|
||||
struct ofono_sim *sim, unsigned char *aid)
|
||||
struct ofono_sim *sim, const struct sim_aid *aid)
|
||||
{
|
||||
GSList *iter = sim->aid_sessions;
|
||||
|
||||
while (iter) {
|
||||
struct ofono_sim_aid_session *session = iter->data;
|
||||
|
||||
if (!memcmp(session->record->aid, aid, 16))
|
||||
if (session->record->aid.len == aid->len &&
|
||||
!memcmp(session->record->aid.aid, aid->aid, aid->len))
|
||||
return session;
|
||||
|
||||
iter = g_slist_next(iter);
|
||||
@@ -3837,10 +3860,10 @@ enum sim_app_type __ofono_sim_session_get_type(
|
||||
return session->record->type;
|
||||
}
|
||||
|
||||
unsigned char *__ofono_sim_session_get_aid(
|
||||
const struct sim_aid *__ofono_sim_session_get_aid(
|
||||
struct ofono_sim_aid_session *session)
|
||||
{
|
||||
return session->record->aid;
|
||||
return &session->record->aid;
|
||||
}
|
||||
|
||||
GSList *__ofono_sim_get_aid_list(struct ofono_sim *sim)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -95,13 +96,6 @@ struct sim_fs {
|
||||
static void sim_fs_op_free(gpointer pointer)
|
||||
{
|
||||
struct sim_fs_op *node = pointer;
|
||||
struct sim_fs *fs = node->context->fs;
|
||||
|
||||
/* only release the session if there are no pending reads */
|
||||
if (fs->session && g_queue_is_empty(fs->op_q)) {
|
||||
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
|
||||
fs->watch_id = 0;
|
||||
}
|
||||
|
||||
g_free(node->buffer);
|
||||
g_free(node);
|
||||
@@ -129,6 +123,9 @@ void sim_fs_free(struct sim_fs *fs)
|
||||
while (fs->contexts)
|
||||
sim_fs_context_free(fs->contexts->data);
|
||||
|
||||
if (fs->watch_id)
|
||||
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
|
||||
|
||||
g_free(fs);
|
||||
}
|
||||
|
||||
@@ -168,7 +165,7 @@ struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs)
|
||||
}
|
||||
|
||||
struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs,
|
||||
unsigned char *aid)
|
||||
const struct sim_aid *aid)
|
||||
{
|
||||
struct ofono_sim_context *context = sim_fs_context_new(fs);
|
||||
|
||||
@@ -199,6 +196,7 @@ void sim_fs_context_free(struct ofono_sim_context *context)
|
||||
|
||||
if (n == 0) {
|
||||
op->cb = NULL;
|
||||
op->context = NULL;
|
||||
|
||||
n += 1;
|
||||
continue;
|
||||
@@ -274,6 +272,8 @@ static void sim_fs_end_current(struct sim_fs *fs)
|
||||
|
||||
if (g_queue_get_length(fs->op_q) > 0)
|
||||
fs->op_source = g_idle_add(sim_fs_op_next, fs);
|
||||
else if (fs->watch_id) /* release the session if no pending reads */
|
||||
__ofono_sim_remove_session_watch(fs->session, fs->watch_id);
|
||||
|
||||
if (fs->fd != -1) {
|
||||
TFR(close(fs->fd));
|
||||
@@ -923,6 +923,13 @@ static void session_read_info_cb(const struct ofono_error *error,
|
||||
}
|
||||
}
|
||||
|
||||
static void session_destroy_cb(void *userdata)
|
||||
{
|
||||
struct sim_fs *fs = userdata;
|
||||
|
||||
fs->watch_id = 0;
|
||||
}
|
||||
|
||||
static void get_session_cb(ofono_bool_t active, int session_id,
|
||||
void *data)
|
||||
{
|
||||
@@ -999,7 +1006,7 @@ static gboolean sim_fs_op_next(gpointer user_data)
|
||||
else
|
||||
fs->watch_id = __ofono_sim_add_session_watch(
|
||||
fs->session, get_session_cb,
|
||||
fs, NULL);
|
||||
fs, session_destroy_cb);
|
||||
}
|
||||
} else {
|
||||
switch (op->structure) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -20,6 +21,7 @@
|
||||
*/
|
||||
|
||||
struct sim_fs;
|
||||
struct sim_aid;
|
||||
|
||||
typedef void (*sim_fs_read_info_cb_t)(int ok, unsigned char file_status,
|
||||
int total_length, int record_length,
|
||||
@@ -30,7 +32,7 @@ struct sim_fs *sim_fs_new(struct ofono_sim *sim,
|
||||
struct ofono_sim_context *sim_fs_context_new(struct sim_fs *fs);
|
||||
|
||||
struct ofono_sim_context *sim_fs_context_new_with_aid(struct sim_fs *fs,
|
||||
unsigned char *aid);
|
||||
const struct sim_aid *aid);
|
||||
|
||||
unsigned int sim_fs_file_watch_add(struct ofono_sim_context *context,
|
||||
int id, ofono_sim_file_changed_cb_t cb,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2021 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
|
||||
@@ -1419,7 +1420,7 @@ gboolean sim_parse_3g_get_response(const unsigned char *data, int len,
|
||||
if (tlv[1] != 0x21)
|
||||
return FALSE;
|
||||
|
||||
switch (tlv[0] & 0x3) {
|
||||
switch (tlv[0] & 0x7) {
|
||||
case 1: /* Transparent */
|
||||
str = 0x00;
|
||||
break;
|
||||
@@ -1572,20 +1573,17 @@ GSList *sim_parse_app_template_entries(const unsigned char *buffer, int len)
|
||||
/* Find all the application entries */
|
||||
while ((dataobj = ber_tlv_find_by_tag(buffer, 0x61, len,
|
||||
&dataobj_len)) != NULL) {
|
||||
struct sim_app_record app;
|
||||
struct sim_app_record *app;
|
||||
const unsigned char *aid, *label;
|
||||
int label_len;
|
||||
int label_len, aid_len;
|
||||
char *app_label;
|
||||
|
||||
/* Find the aid (mandatory) */
|
||||
aid = ber_tlv_find_by_tag(dataobj, 0x4f, dataobj_len,
|
||||
&app.aid_len);
|
||||
if (!aid || app.aid_len < 0x01 || app.aid_len > 0x10)
|
||||
&aid_len);
|
||||
if (!aid || aid_len < 0x01 || aid_len > 0x10)
|
||||
goto error;
|
||||
|
||||
memcpy(app.aid, aid, app.aid_len);
|
||||
|
||||
app.type = (app.aid[5] << 8) | app.aid[6];
|
||||
|
||||
/* Find the label (optional) */
|
||||
label = ber_tlv_find_by_tag(dataobj, 0x50, dataobj_len,
|
||||
&label_len);
|
||||
@@ -1594,14 +1592,21 @@ GSList *sim_parse_app_template_entries(const unsigned char *buffer, int len)
|
||||
* Label field uses the extra complicated
|
||||
* encoding in 102.221 Annex A
|
||||
*/
|
||||
app.label = sim_string_to_utf8(label, label_len);
|
||||
app_label = sim_string_to_utf8(label, label_len);
|
||||
|
||||
if (app.label == NULL)
|
||||
if (app_label == NULL)
|
||||
goto error;
|
||||
} else
|
||||
app.label = NULL;
|
||||
app_label = NULL;
|
||||
|
||||
ret = g_slist_prepend(ret, g_memdup(&app, sizeof(app)));
|
||||
app = g_new0(struct sim_app_record, 1);
|
||||
|
||||
memcpy(app->aid.aid, aid, aid_len);
|
||||
app->aid.len = aid_len;
|
||||
app->label = app_label;
|
||||
app->type = (aid[5] << 8) | aid[6];
|
||||
|
||||
ret = g_slist_prepend(ret, app);
|
||||
|
||||
len -= (dataobj - buffer) + dataobj_len;
|
||||
buffer = dataobj + dataobj_len;
|
||||
@@ -1667,67 +1672,135 @@ int sim_build_gsm_authenticate(unsigned char *buffer, int len,
|
||||
return build_authenticate(buffer, rand, NULL);
|
||||
}
|
||||
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer,
|
||||
int len, const unsigned char **res, const unsigned char **ck,
|
||||
const unsigned char **ik, const unsigned char **auts,
|
||||
const unsigned char **kc)
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer, int len,
|
||||
struct data_block *res, struct data_block *ck,
|
||||
struct data_block *ik, struct data_block *auts,
|
||||
struct data_block *sres, struct data_block *kc)
|
||||
{
|
||||
if (len < 16 || !buffer)
|
||||
const unsigned char *ptr = buffer;
|
||||
const unsigned char *end = ptr + len;
|
||||
unsigned int l;
|
||||
|
||||
if (!buffer || len < 2)
|
||||
return FALSE;
|
||||
|
||||
switch (buffer[0]) {
|
||||
memset(res, 0, sizeof(*res));
|
||||
memset(ck, 0, sizeof(*ck));
|
||||
memset(ik, 0, sizeof(*ik));
|
||||
memset(kc, 0, sizeof(*kc));
|
||||
memset(auts, 0, sizeof(*auts));
|
||||
memset(sres, 0, sizeof(*sres));
|
||||
|
||||
/*
|
||||
* TS 31.102
|
||||
* 7.1.2.1 GSM/3G security context
|
||||
*/
|
||||
switch (*ptr++) {
|
||||
case 0xdb:
|
||||
/* 'DB' + '08' + RES(16) + '10' + CK(32) + '10' + IK(32) = 43 */
|
||||
if (len < 43)
|
||||
goto umts_end;
|
||||
/*
|
||||
* Response parameters/data, case 1, 3G security context,
|
||||
* command successful:
|
||||
*
|
||||
* "Successful 3G authentication" tag = 'DB'
|
||||
* 'DB' + L3 + RES(L3) + L4 + CK(L4) + L5 + IK(L5) + 8 + Kc(8)
|
||||
*/
|
||||
l = *ptr++; /* L3 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
/* success */
|
||||
if (buffer[1] != 0x08)
|
||||
goto umts_end;
|
||||
res->data = ptr;
|
||||
res->len = l;
|
||||
ptr += l;
|
||||
|
||||
*res = buffer + 2;
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
if (buffer[10] != 0x10)
|
||||
goto umts_end;
|
||||
l = *ptr++; /* L4 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
*ck = buffer + 11;
|
||||
ck->data = ptr;
|
||||
ck->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (buffer[27] != 0x10)
|
||||
goto umts_end;
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
*ik = buffer + 28;
|
||||
l = *ptr++; /* L5 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
if (len >= 53 && kc) {
|
||||
if (buffer[44] != 0x08)
|
||||
goto umts_end;
|
||||
ik->data = ptr;
|
||||
ik->len = l;
|
||||
ptr += l;
|
||||
|
||||
*kc = buffer + 45;
|
||||
} else {
|
||||
*kc = NULL;
|
||||
if (ptr < end) {
|
||||
l = *ptr++;
|
||||
if (l != 8 || (ptr + l) != end)
|
||||
return FALSE;
|
||||
|
||||
kc->data = ptr;
|
||||
kc->len = l;
|
||||
ptr += l;
|
||||
}
|
||||
|
||||
*auts = NULL;
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
case 0xdc:
|
||||
/* 'DC' + '0E' + AUTS(14) = 16 */
|
||||
if (len < 16)
|
||||
goto umts_end;
|
||||
/*
|
||||
* Response parameters/data, case 2, 3G security context,
|
||||
* synchronisation failure:
|
||||
*
|
||||
* "Synchronisation failure" tag = 'DC'
|
||||
* 'DC' + L1 + AUTS(L1)
|
||||
*/
|
||||
l = *ptr++; /* L1 */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
/* sync error */
|
||||
if (buffer[1] != 0x0e)
|
||||
goto umts_end;
|
||||
auts->data = ptr;
|
||||
auts->len = l;
|
||||
ptr += l;
|
||||
|
||||
*auts = buffer + 2;
|
||||
if (ptr != end)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
case 0x04:
|
||||
/*
|
||||
* Response parameters/data, case 3, GSM security context,
|
||||
* command successful:
|
||||
*
|
||||
* 4 + SRES(4) + 8 + Kc(8)
|
||||
*/
|
||||
l = 4; /* Already skipped this one */
|
||||
if ((ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
sres->data = ptr;
|
||||
sres->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (ptr == end)
|
||||
return FALSE;
|
||||
|
||||
l = *ptr++; /* 8 */
|
||||
if (l != 8 || (ptr + l) > end)
|
||||
return FALSE;
|
||||
|
||||
kc->data = ptr;
|
||||
kc->len = l;
|
||||
ptr += l;
|
||||
|
||||
if (ptr != end)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
default:
|
||||
goto umts_end;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
umts_end:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,9 +314,13 @@ struct sim_ef_info {
|
||||
enum sim_file_access perm_update;
|
||||
};
|
||||
|
||||
struct sim_app_record {
|
||||
struct sim_aid {
|
||||
unsigned char aid[16];
|
||||
int aid_len;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct sim_app_record {
|
||||
struct sim_aid aid;
|
||||
char *label;
|
||||
enum sim_app_type type;
|
||||
};
|
||||
@@ -371,6 +375,11 @@ struct comprehension_tlv_builder {
|
||||
struct ber_tlv_builder *parent;
|
||||
};
|
||||
|
||||
struct data_block {
|
||||
const unsigned char *data;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
void simple_tlv_iter_init(struct simple_tlv_iter *iter,
|
||||
const unsigned char *pdu, unsigned int len);
|
||||
gboolean simple_tlv_iter_next(struct simple_tlv_iter *iter);
|
||||
@@ -526,10 +535,10 @@ int sim_build_umts_authenticate(unsigned char *buffer, int len,
|
||||
int sim_build_gsm_authenticate(unsigned char *buffer, int len,
|
||||
const unsigned char *rand);
|
||||
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer,
|
||||
int len, const unsigned char **res, const unsigned char **ck,
|
||||
const unsigned char **ik, const unsigned char **auts,
|
||||
const unsigned char **kc);
|
||||
gboolean sim_parse_umts_authenticate(const unsigned char *buffer, int len,
|
||||
struct data_block *res, struct data_block *ck,
|
||||
struct data_block *ik, struct data_block *auts,
|
||||
struct data_block *sres, struct data_block *kc);
|
||||
|
||||
gboolean sim_parse_gsm_authenticate(const unsigned char *buffer, int len,
|
||||
const unsigned char **sres, const unsigned char **kc);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -1757,7 +1758,7 @@ gboolean sms_udh_iter_init_from_cbs(const struct cbs *cbs,
|
||||
return FALSE;
|
||||
|
||||
hdr = cbs->ud;
|
||||
max_ud_len = 82;
|
||||
max_ud_len = cbs->udlen;
|
||||
|
||||
/* Must have at least one information-element if udhi is true */
|
||||
if (hdr[0] < 2)
|
||||
@@ -3856,8 +3857,8 @@ gboolean cbs_dcs_decode(guint8 dcs, gboolean *udhi, enum sms_class *cls,
|
||||
|
||||
gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
|
||||
{
|
||||
/* CBS is always a fixed length of 88 bytes */
|
||||
if (len != 88)
|
||||
/* CBS is (almost) always a fixed length of 88 bytes */
|
||||
if (len < 6 || len > 88)
|
||||
return FALSE;
|
||||
|
||||
out->gs = (enum cbs_geo_scope) ((pdu[0] >> 6) & 0x03);
|
||||
@@ -3868,6 +3869,10 @@ gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
|
||||
out->max_pages = pdu[5] & 0xf;
|
||||
out->page = (pdu[5] >> 4) & 0xf;
|
||||
|
||||
/* Allow the last fragment to be truncated */
|
||||
if (len != 88 && out->max_pages != out->page)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* If a mobile receives the code 0000 in either the first field or
|
||||
* the second field then it shall treat the CBS message exactly the
|
||||
@@ -3879,7 +3884,10 @@ gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
|
||||
out->page = 1;
|
||||
}
|
||||
|
||||
memcpy(out->ud, pdu + 6, 82);
|
||||
out->udlen = (guint8)(len - 6);
|
||||
memcpy(out->ud, pdu + 6, out->udlen);
|
||||
if (out->udlen < 82)
|
||||
memset(out->ud + out->udlen, 0, 82 - out->udlen);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -4072,7 +4080,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
|
||||
if (iso639)
|
||||
bufsize -= 3;
|
||||
} else {
|
||||
bufsize += 82;
|
||||
bufsize += cbs->udlen;
|
||||
|
||||
if (iso639)
|
||||
bufsize -= 2;
|
||||
@@ -4089,7 +4097,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
|
||||
if (sms_udh_iter_init_from_cbs(cbs, &iter))
|
||||
taken = sms_udh_iter_get_udh_length(&iter) + 1;
|
||||
|
||||
unpack_7bit_own_buf(cbs->ud + taken, 82 - taken,
|
||||
unpack_7bit_own_buf(cbs->ud + taken, cbs->udlen - taken,
|
||||
taken, FALSE, 2,
|
||||
NULL, 0,
|
||||
(unsigned char *)iso639_lang);
|
||||
@@ -4122,7 +4130,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
|
||||
max_chars =
|
||||
sms_text_capacity_gsm(CBS_MAX_GSM_CHARS, taken);
|
||||
|
||||
unpack_7bit_own_buf(ud + taken, 82 - taken,
|
||||
unpack_7bit_own_buf(ud + taken, cbs->udlen - taken,
|
||||
taken, FALSE, max_chars,
|
||||
&written, 0, unpacked);
|
||||
|
||||
@@ -4156,7 +4164,7 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
|
||||
* the check here since the specification isn't clear
|
||||
*/
|
||||
} else {
|
||||
int num_ucs2_chars = (82 - taken) >> 1;
|
||||
int num_ucs2_chars = (cbs->udlen - taken) >> 1;
|
||||
int i = taken;
|
||||
int max_offset = taken + num_ucs2_chars * 2;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2020 Jolla Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -398,6 +399,7 @@ struct cbs {
|
||||
guint8 dcs; /* 8 bits */
|
||||
guint8 max_pages; /* 4 bits */
|
||||
guint8 page; /* 4 bits */
|
||||
guint8 udlen;
|
||||
guint8 ud[82];
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -725,6 +727,12 @@ static DBusMessage *stk_register_agent(DBusConnection *conn,
|
||||
if (!dbus_validate_path(agent_path, NULL))
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (!__ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
|
||||
OFONO_DBUS_ACCESS_INTF_STK,
|
||||
OFONO_DBUS_ACCESS_STK_REGISTER_AGENT,
|
||||
agent_path))
|
||||
return __ofono_error_access_denied(msg);
|
||||
|
||||
stk->default_agent = stk_agent_new(agent_path,
|
||||
dbus_message_get_sender(msg),
|
||||
FALSE);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-2019 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
|
||||
@@ -36,10 +37,19 @@
|
||||
#include <glib.h>
|
||||
|
||||
#include "storage.h"
|
||||
#include "ofono.h"
|
||||
|
||||
static char* config_dir = NULL;
|
||||
|
||||
void __ofono_set_config_dir(const char *dir)
|
||||
{
|
||||
g_free(config_dir);
|
||||
config_dir = g_strdup(dir);
|
||||
}
|
||||
|
||||
const char *ofono_config_dir(void)
|
||||
{
|
||||
return CONFIGDIR;
|
||||
return config_dir ? config_dir : CONFIGDIR;
|
||||
}
|
||||
|
||||
const char *ofono_storage_dir(void)
|
||||
|
||||
@@ -349,12 +349,12 @@ static int tone_queue(struct ofono_voicecall *vc, const char *tone_str,
|
||||
|
||||
/*
|
||||
* Tones can be 0-9, *, #, A-D according to 27.007 C.2.11,
|
||||
* and p for Pause.
|
||||
* and p for Pause (also , for Pause as per ITU-T V.250 6.3.1.2).
|
||||
*/
|
||||
for (i = 0; tone_str[i]; i++)
|
||||
if (!g_ascii_isdigit(tone_str[i]) && tone_str[i] != 'p' &&
|
||||
tone_str[i] != 'P' && tone_str[i] != '*' &&
|
||||
tone_str[i] != '.' && tone_str[i] != ',' &&
|
||||
tone_str[i] != ',' &&
|
||||
tone_str[i] != '#' && (tone_str[i] < 'A' ||
|
||||
tone_str[i] > 'D'))
|
||||
return -EINVAL;
|
||||
@@ -1798,7 +1798,7 @@ static DBusMessage *manager_dial(DBusConnection *conn,
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static void manager_dial_last_callback(const struct ofono_error *error,
|
||||
static void manager_dial_hfp_callback(const struct ofono_error *error,
|
||||
void *data)
|
||||
{
|
||||
struct ofono_voicecall *vc = data;
|
||||
@@ -1827,8 +1827,8 @@ error:
|
||||
__ofono_error_failed(vc->pending));
|
||||
}
|
||||
|
||||
static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
static int voicecall_dial_hfp(struct ofono_voicecall *vc, unsigned int position,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom);
|
||||
|
||||
@@ -1838,9 +1838,6 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
if (ofono_modem_get_online(modem) == FALSE)
|
||||
return -ENETDOWN;
|
||||
|
||||
if (vc->driver->dial_last == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (voicecalls_have_incoming(vc))
|
||||
return -EBUSY;
|
||||
|
||||
@@ -1851,7 +1848,18 @@ static int voicecall_dial_last(struct ofono_voicecall *vc,
|
||||
if (voicecalls_have_active(vc) && voicecalls_have_held(vc))
|
||||
return -EBUSY;
|
||||
|
||||
vc->driver->dial_last(vc, cb, vc);
|
||||
/* when position is not given we dial the last called number */
|
||||
if (position == 0) {
|
||||
if (vc->driver->dial_last == NULL)
|
||||
return -ENOTSUP;
|
||||
|
||||
vc->driver->dial_last(vc, cb, vc);
|
||||
} else {
|
||||
if (vc->driver->dial_memory == NULL )
|
||||
return -ENOTSUP;
|
||||
|
||||
vc->driver->dial_memory(vc, position, cb, vc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1867,7 +1875,7 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
|
||||
|
||||
vc->pending = dbus_message_ref(msg);
|
||||
|
||||
err = voicecall_dial_last(vc, manager_dial_last_callback, vc);
|
||||
err = voicecall_dial_hfp(vc, 0, manager_dial_hfp_callback, vc);
|
||||
|
||||
if (err >= 0)
|
||||
return NULL;
|
||||
@@ -1889,6 +1897,44 @@ static DBusMessage *manager_dial_last(DBusConnection *conn,
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *manager_dial_memory(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ofono_voicecall *vc = data;
|
||||
int memory_location;
|
||||
int err;
|
||||
|
||||
if (vc->pending || vc->dial_req || vc->pending_em)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &memory_location,
|
||||
DBUS_TYPE_INVALID) == FALSE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
vc->pending = dbus_message_ref(msg);
|
||||
|
||||
err = voicecall_dial_hfp(vc, memory_location,
|
||||
manager_dial_hfp_callback, vc);
|
||||
if (err >= 0)
|
||||
return NULL;
|
||||
|
||||
vc->pending = NULL;
|
||||
dbus_message_unref(msg);
|
||||
|
||||
switch (err) {
|
||||
case -EINVAL:
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
case -ENETDOWN:
|
||||
return __ofono_error_not_available(msg);
|
||||
|
||||
case -ENOTSUP:
|
||||
return __ofono_error_not_implemented(msg);
|
||||
}
|
||||
|
||||
return __ofono_error_failed(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *manager_transfer(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -2552,6 +2598,9 @@ static const GDBusMethodTable manager_methods[] = {
|
||||
GDBUS_ARGS({ "path", "o" }),
|
||||
manager_dial) },
|
||||
{ GDBUS_ASYNC_METHOD("DialLast", NULL, NULL, manager_dial_last)},
|
||||
{ GDBUS_ASYNC_METHOD("DialMemory",
|
||||
GDBUS_ARGS({"memory_location", "u" }), NULL,
|
||||
manager_dial_memory) },
|
||||
{ GDBUS_ASYNC_METHOD("Transfer", NULL, NULL, manager_transfer) },
|
||||
{ GDBUS_ASYNC_METHOD("SwapCalls", NULL, NULL, manager_swap_calls) },
|
||||
{ GDBUS_ASYNC_METHOD("ReleaseAndAnswer", NULL, NULL,
|
||||
@@ -4340,7 +4389,7 @@ static void tone_request_cb(const struct ofono_error *error, void *data)
|
||||
goto done;
|
||||
}
|
||||
|
||||
len = strspn(entry->left, "pP.,");
|
||||
len = strspn(entry->left, "pP,");
|
||||
entry->left += len;
|
||||
|
||||
done:
|
||||
@@ -4374,7 +4423,7 @@ static gboolean tone_request_run(gpointer user_data)
|
||||
if (entry == NULL)
|
||||
return FALSE;
|
||||
|
||||
len = strcspn(entry->left, "pP.,");
|
||||
len = strcspn(entry->left, "pP,");
|
||||
|
||||
if (len) {
|
||||
if (len > 8) /* Arbitrary length limit per request */
|
||||
|
||||
@@ -18,11 +18,14 @@ TESTS="\
|
||||
test-caif \
|
||||
test-dbus-queue \
|
||||
test-dbus-access \
|
||||
test-dbus-clients \
|
||||
test-gprs-filter \
|
||||
test-provision \
|
||||
test-config \
|
||||
test-watch \
|
||||
test-ril_util \
|
||||
test-ril_config \
|
||||
test-ril_ecclist \
|
||||
test-ril-transport \
|
||||
test-ril_vendor \
|
||||
test-sms-filter \
|
||||
|
||||
448
ofono/unit/test-config.c
Normal file
448
ofono/unit/test-config.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2019 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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 <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define TMP_DIR_TEMPLATE "test-config-XXXXXX"
|
||||
|
||||
static gboolean test_keyfile_empty(GKeyFile *k)
|
||||
{
|
||||
gsize n = 0;
|
||||
char **groups = g_key_file_get_groups(k, &n);
|
||||
|
||||
g_strfreev(groups);
|
||||
return !n;
|
||||
}
|
||||
|
||||
static void test_merge_ignore(const char *filename, const char *contents,
|
||||
const char *dirname, const char *filename1, const char *contents1)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/", filename, NULL);
|
||||
char *subdir = g_strconcat(dir, "/", dirname, NULL);
|
||||
char *file1 = g_strconcat(subdir, "/", filename1, NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
static void test_merge1(const char *conf, const char *conf1, const char *out)
|
||||
{
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/bar.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, conf, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, conf1, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
g_key_file_set_list_separator(k, ',');
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, out));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_basic ==== */
|
||||
|
||||
static void test_merge_basic(void)
|
||||
{
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *nonexistent = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
|
||||
config_merge_files(NULL, NULL);
|
||||
|
||||
remove(nonexistent);
|
||||
config_merge_files(k, nonexistent);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
config_merge_files(k, NULL);
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
config_merge_files(k, "");
|
||||
g_assert(test_keyfile_empty(k));
|
||||
|
||||
g_key_file_unref(k);
|
||||
g_free(nonexistent);
|
||||
}
|
||||
|
||||
/* ==== merge_simple ==== */
|
||||
|
||||
static void test_merge_simple(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
char *data;
|
||||
GKeyFile *k = g_key_file_new();
|
||||
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
/* ==== merge_empty_dir ==== */
|
||||
|
||||
static void test_merge_empty_dir(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_ignore ==== */
|
||||
|
||||
static void test_merge_ignore0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *subdir2 = g_strconcat(subdir, "/dir.conf", NULL);
|
||||
char *file = g_strconcat(dir, "/foo.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
/* Two empty subdirectories, one with matching name, one not */
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(!mkdir(subdir2, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, contents));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(subdir2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
g_free(subdir2);
|
||||
}
|
||||
|
||||
static void test_merge_ignore1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
|
||||
/* File has no suffix */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "file", contents1);
|
||||
}
|
||||
|
||||
static void test_merge_ignore2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[[[[[[[";
|
||||
|
||||
/* File is not a valid keyfile */
|
||||
test_merge_ignore("foo.conf", contents, "foo.d", "a.conf", contents1);
|
||||
}
|
||||
|
||||
/* ==== merge_sort ==== */
|
||||
|
||||
static void test_merge_sort(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\nb=3\n";
|
||||
static const char contents2 [] = "[foo]\nb=4\n";
|
||||
static const char result [] = "[foo]\na=1\nb=4\n";
|
||||
|
||||
/* Test file sort order */
|
||||
char *dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
|
||||
char *file = g_strconcat(dir, "/foo.", NULL);
|
||||
char *subdir = g_strconcat(dir, "/foo.d", NULL);
|
||||
char *file1 = g_strconcat(subdir, "/1.conf", NULL);
|
||||
char *file2 = g_strconcat(subdir, "/2.conf", NULL);
|
||||
GKeyFile *k = g_key_file_new();
|
||||
char *data;
|
||||
|
||||
g_assert(!mkdir(subdir, 0700));
|
||||
g_assert(g_file_set_contents(file, contents, -1, NULL));
|
||||
g_assert(g_file_set_contents(file1, contents1, -1, NULL));
|
||||
g_assert(g_file_set_contents(file2, contents2, -1, NULL));
|
||||
|
||||
DBG("reading %s", file);
|
||||
config_merge_files(k, file);
|
||||
data = g_key_file_to_data(k, NULL, NULL);
|
||||
DBG("\n%s", data);
|
||||
g_assert(!g_strcmp0(data, result));
|
||||
g_free(data);
|
||||
g_key_file_unref(k);
|
||||
|
||||
remove(file);
|
||||
remove(file1);
|
||||
remove(file2);
|
||||
remove(subdir);
|
||||
remove(dir);
|
||||
|
||||
g_free(file);
|
||||
g_free(file1);
|
||||
g_free(file2);
|
||||
g_free(dir);
|
||||
g_free(subdir);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_group ==== */
|
||||
|
||||
static void test_merge_remove_group(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\n\n[bar]\nb=1\n";
|
||||
static const char contents1 [] = "[!bar]\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_remove_key ==== */
|
||||
|
||||
static void test_merge_remove_key(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\n!b=\n\n!=\n";
|
||||
static const char result [] = "[foo]\na=1\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_default_value ==== */
|
||||
|
||||
static void test_merge_default_value(void)
|
||||
{
|
||||
/* b is assigned the default value, a stays as is */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\na:=2\nb:=3\n";
|
||||
static const char result [] = "[foo]\na=1\nb=3\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_add ==== */
|
||||
|
||||
static void test_merge_list_add0(void)
|
||||
{
|
||||
/* Adding empty list */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add1(void)
|
||||
{
|
||||
/* a=1 turns into a=1,2, */
|
||||
static const char contents [] = "[foo]\na=1\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na+=2,\n";
|
||||
static const char result [] = "[foo]\na=1,2,\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add2(void)
|
||||
{
|
||||
/* 2 is already there */
|
||||
static const char contents [] = "[foo]\na=1,2,\nb=2\n";
|
||||
static const char contents1 [] = "[foo]\na?=2\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_add3(void)
|
||||
{
|
||||
/* 2 is already there, 3 is not */
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1,2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add4(void)
|
||||
{
|
||||
/* b=2,3, is created */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[foo]\nb?=2,3,\n";
|
||||
static const char result [] = "[foo]\na=1\nb=2,3,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_add5(void)
|
||||
{
|
||||
/* Add a new group */
|
||||
static const char contents [] = "[foo]\na=1\n";
|
||||
static const char contents1 [] = "[bar]\nb=2\n";
|
||||
static const char result [] = "[foo]\na=1\n\n[bar]\nb=2\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
/* ==== merge_list_remove ==== */
|
||||
|
||||
static void test_merge_list_remove0(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove1(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=2,\n";
|
||||
static const char result [] = "[foo]\na=1,\n";
|
||||
|
||||
test_merge1(contents, contents1, result);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove2(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\na-=3\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
static void test_merge_list_remove3(void)
|
||||
{
|
||||
static const char contents [] = "[foo]\na=1,2,\n";
|
||||
static const char contents1 [] = "[foo]\nb-=1\n";
|
||||
|
||||
test_merge1(contents, contents1, contents);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/config/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-config",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("merge_basic"), test_merge_basic);
|
||||
g_test_add_func(TEST_("merge_simple"), test_merge_simple);
|
||||
g_test_add_func(TEST_("merge_empty_dir"), test_merge_empty_dir);
|
||||
g_test_add_func(TEST_("merge_ignore0"), test_merge_ignore0);
|
||||
g_test_add_func(TEST_("merge_ignore1"), test_merge_ignore1);
|
||||
g_test_add_func(TEST_("merge_ignore2"), test_merge_ignore2);
|
||||
g_test_add_func(TEST_("merge_sort"), test_merge_sort);
|
||||
g_test_add_func(TEST_("merge_remove_group"), test_merge_remove_group);
|
||||
g_test_add_func(TEST_("merge_remove_key"), test_merge_remove_key);
|
||||
g_test_add_func(TEST_("merge_default_value"), test_merge_default_value);
|
||||
g_test_add_func(TEST_("merge_list_add0"), test_merge_list_add0);
|
||||
g_test_add_func(TEST_("merge_list_add1"), test_merge_list_add1);
|
||||
g_test_add_func(TEST_("merge_list_add2"), test_merge_list_add2);
|
||||
g_test_add_func(TEST_("merge_list_add3"), test_merge_list_add3);
|
||||
g_test_add_func(TEST_("merge_list_add4"), test_merge_list_add4);
|
||||
g_test_add_func(TEST_("merge_list_add5"), test_merge_list_add5);
|
||||
g_test_add_func(TEST_("merge_list_remove0"), test_merge_list_remove0);
|
||||
g_test_add_func(TEST_("merge_list_remove1"), test_merge_list_remove1);
|
||||
g_test_add_func(TEST_("merge_list_remove2"), test_merge_list_remove2);
|
||||
g_test_add_func(TEST_("merge_list_remove3"), test_merge_list_remove3);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 2019-2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Open Mobile Platform LLC.
|
||||
*
|
||||
* 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
|
||||
@@ -33,6 +34,12 @@ static enum ofono_dbus_access deny_method_access(const char *sender,
|
||||
return OFONO_DBUS_ACCESS_DENY;
|
||||
}
|
||||
|
||||
static enum ofono_dbus_access broken_method_access(const char *sender,
|
||||
enum ofono_dbus_access_intf intf, int method, const char *arg)
|
||||
{
|
||||
return (enum ofono_dbus_access)(-1);
|
||||
}
|
||||
|
||||
struct ofono_dbus_access_plugin access_inval;
|
||||
struct ofono_dbus_access_plugin access_dontcare = {
|
||||
.name = "DontCare",
|
||||
@@ -50,6 +57,12 @@ struct ofono_dbus_access_plugin access_deny = {
|
||||
.method_access = deny_method_access
|
||||
};
|
||||
|
||||
struct ofono_dbus_access_plugin access_broken = {
|
||||
.name = "Broken",
|
||||
.priority = OFONO_DBUS_ACCESS_PRIORITY_LOW,
|
||||
.method_access = broken_method_access
|
||||
};
|
||||
|
||||
/*==========================================================================*
|
||||
* Tests
|
||||
*==========================================================================*/
|
||||
@@ -103,6 +116,12 @@ static const struct test_method_name_data method_name_tests[] = {
|
||||
},{
|
||||
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS,
|
||||
OFONO_DBUS_ACCESS_RADIOSETTINGS_METHOD_COUNT
|
||||
},{
|
||||
OFONO_DBUS_ACCESS_INTF_STK,
|
||||
OFONO_DBUS_ACCESS_STK_METHOD_COUNT
|
||||
},{
|
||||
OFONO_DBUS_ACCESS_INTF_OEMRAW,
|
||||
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,6 +171,13 @@ static void test_register()
|
||||
ofono_dbus_access_plugin_unregister(&access_deny);
|
||||
ofono_dbus_access_plugin_unregister(&access_dontcare);
|
||||
|
||||
/* And here too */
|
||||
g_assert(!ofono_dbus_access_plugin_register(&access_broken));
|
||||
g_assert(!ofono_dbus_access_plugin_register(&access_deny));
|
||||
g_assert(!__ofono_dbus_access_method_allowed(":1.0", 0, 1, NULL));
|
||||
ofono_dbus_access_plugin_unregister(&access_deny);
|
||||
ofono_dbus_access_plugin_unregister(&access_dontcare);
|
||||
|
||||
/* DontCare will allow everything */
|
||||
g_assert(!ofono_dbus_access_plugin_register(&access_dontcare));
|
||||
g_assert(__ofono_dbus_access_method_allowed(":1.0", 0, 1, NULL));
|
||||
|
||||
280
ofono/unit/test-dbus-clients.c
Normal file
280
ofono/unit/test-dbus-clients.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2021 Jolla Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "test-dbus.h"
|
||||
|
||||
#include <ofono/dbus-clients.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/log.h>
|
||||
#include "ofono.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define TEST_TIMEOUT (10) /* seconds */
|
||||
#define TEST_SENDER ":1.0"
|
||||
#define TEST_SENDER_1 ":1.1"
|
||||
|
||||
#define TEST_DBUS_PATH "/test"
|
||||
#define TEST_DBUS_INTERFACE "test.interface"
|
||||
#define TEST_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define TEST_PROPERTY_NAME "Test"
|
||||
#define TEST_PROPERTY_VALUE "test"
|
||||
|
||||
struct test_data {
|
||||
struct test_dbus_context dbus;
|
||||
struct ofono_dbus_clients *clients;
|
||||
int count;
|
||||
};
|
||||
|
||||
static gboolean test_debug;
|
||||
|
||||
/* ==== dummy interface ==== */
|
||||
|
||||
#define test_register_interface(methods,signals,data) \
|
||||
g_assert(g_dbus_register_interface(ofono_dbus_get_connection(), \
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE, \
|
||||
methods, signals, NULL, data, NULL))
|
||||
|
||||
#define test_register_dummy_interface() \
|
||||
test_register_interface(test_dummy_methods, \
|
||||
test_property_change_signal, NULL)
|
||||
|
||||
static DBusMessage *test_dummy_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable test_dummy_methods[] = {
|
||||
{ GDBUS_ASYNC_METHOD("Dummy", NULL, NULL, test_dummy_handler) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable test_property_change_signal[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* ==== common ==== */
|
||||
|
||||
static gboolean test_timeout(gpointer param)
|
||||
{
|
||||
g_assert(!"TIMEOUT");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static guint test_setup_timeout(void)
|
||||
{
|
||||
if (test_debug) {
|
||||
return 0;
|
||||
} else {
|
||||
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean test_loop_quit(gpointer data)
|
||||
{
|
||||
g_main_loop_quit(data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void test_loop_quit_later(GMainLoop *loop)
|
||||
{
|
||||
g_idle_add(test_loop_quit, loop);
|
||||
}
|
||||
|
||||
/* ==== null ==== */
|
||||
|
||||
static void test_null(void)
|
||||
{
|
||||
/* We are NULL tolerant: */
|
||||
ofono_dbus_clients_free(NULL);
|
||||
ofono_dbus_clients_signal(NULL, NULL);
|
||||
ofono_dbus_clients_signal_property_changed(NULL,NULL,NULL,NULL,0,NULL);
|
||||
g_assert(!ofono_dbus_clients_new(NULL, NULL, NULL));
|
||||
g_assert(!ofono_dbus_clients_count(NULL));
|
||||
g_assert(!ofono_dbus_clients_add(NULL, NULL));
|
||||
g_assert(!ofono_dbus_clients_remove(NULL, NULL));
|
||||
}
|
||||
|
||||
/* ==== basic ==== */
|
||||
|
||||
static void test_basic_notify_func(const char *name, void *loop)
|
||||
{
|
||||
g_assert_cmpstr(name, == ,TEST_SENDER);
|
||||
g_main_loop_quit(loop);
|
||||
}
|
||||
|
||||
static void test_basic_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
const char *value = TEST_PROPERTY_VALUE;
|
||||
DBusMessage *signal =
|
||||
ofono_dbus_signal_new_property_changed(TEST_DBUS_PATH,
|
||||
TEST_DBUS_INTERFACE, TEST_PROPERTY_NAME,
|
||||
DBUS_TYPE_STRING, &value);
|
||||
|
||||
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
|
||||
test_basic_notify_func, test->dbus.loop);
|
||||
|
||||
g_assert(!ofono_dbus_clients_add(test->clients, NULL));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
|
||||
/* OK to add the same thing twice */
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,1);
|
||||
test_dbus_watch_disconnect_all();
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,0);
|
||||
|
||||
/* There's nothing to remove */
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
|
||||
g_assert(!ofono_dbus_clients_remove(test->clients, NULL));
|
||||
|
||||
/* These have no effect because client list is empty: */
|
||||
ofono_dbus_clients_signal(test->clients, NULL);
|
||||
ofono_dbus_clients_signal(test->clients, signal);
|
||||
ofono_dbus_clients_signal_property_changed(test->clients, NULL, NULL,
|
||||
NULL, 0, NULL);
|
||||
ofono_dbus_clients_signal_property_changed(test->clients,
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
|
||||
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
|
||||
|
||||
/* test_basic_notify_func() has called test_loop_quit_later() */
|
||||
dbus_message_unref(signal);
|
||||
}
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
struct test_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_basic_start;
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
g_assert(test.clients);
|
||||
ofono_dbus_clients_free(test.clients);
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== signal ==== */
|
||||
|
||||
static void test_signal_handle(struct test_dbus_context *dbus, DBusMessage *msg)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
|
||||
g_assert_cmpstr(dbus_message_get_path(msg), == ,TEST_DBUS_PATH);
|
||||
g_assert_cmpstr(dbus_message_get_interface(msg), == ,
|
||||
TEST_DBUS_INTERFACE);
|
||||
g_assert_cmpstr(dbus_message_get_member(msg), == ,
|
||||
TEST_PROPERTY_CHANGED_SIGNAL);
|
||||
test->count++;
|
||||
if (test->count == 2) {
|
||||
test_loop_quit_later(dbus->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_signal_start(struct test_dbus_context *dbus)
|
||||
{
|
||||
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
|
||||
const char *value = TEST_PROPERTY_VALUE;
|
||||
|
||||
test_register_dummy_interface();
|
||||
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
|
||||
NULL, NULL);
|
||||
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
|
||||
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER_1));
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,2);
|
||||
|
||||
ofono_dbus_clients_signal_property_changed(test->clients,
|
||||
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
|
||||
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
|
||||
/* And wait for 2 signals to arrive */
|
||||
}
|
||||
|
||||
static void test_signal(void)
|
||||
{
|
||||
struct test_data test;
|
||||
guint timeout = test_setup_timeout();
|
||||
|
||||
memset(&test, 0, sizeof(test));
|
||||
test_dbus_setup(&test.dbus);
|
||||
test.dbus.start = test_signal_start;
|
||||
test.dbus.handle_signal = test_signal_handle;
|
||||
|
||||
g_main_loop_run(test.dbus.loop);
|
||||
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,2);
|
||||
test_dbus_watch_disconnect_all();
|
||||
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,0);
|
||||
ofono_dbus_clients_free(test.clients);
|
||||
|
||||
test_dbus_shutdown(&test.dbus);
|
||||
if (timeout) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_(name) "/dbus-clients/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
|
||||
test_debug = TRUE;
|
||||
} else {
|
||||
GWARN("Unsupported command line option %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init("test-dbus-clients",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("signal"), test_signal);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -417,7 +417,7 @@ static void test_reply_last_reply(DBusPendingCall *call, void *dbus)
|
||||
G_CAST(dbus, struct test_reply_data, dbus);
|
||||
|
||||
DBG("");
|
||||
test_dbus_check_error_reply(call, TEST_ERROR_FAILED);
|
||||
test_dbus_check_empty_reply(call, NULL);
|
||||
g_main_loop_quit(test->dbus.loop);
|
||||
}
|
||||
|
||||
@@ -445,6 +445,12 @@ static DBusMessage *test_reply_4(DBusMessage *msg, void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *test_reply_5(DBusMessage *msg, void *data)
|
||||
{
|
||||
DBG("");
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
static DBusMessage *test_reply_handler(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -485,10 +491,17 @@ static DBusMessage *test_reply_handler(DBusConnection *conn,
|
||||
case 6:
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_4,
|
||||
msg, NULL);
|
||||
break;
|
||||
case 7:
|
||||
/* Call the same method again */
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_4,
|
||||
msg, NULL);
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
/* Call the last one */
|
||||
__ofono_dbus_queue_request(test->queue, test_reply_5,
|
||||
msg, NULL);
|
||||
|
||||
/* This completes the first one, with NULL handler */
|
||||
__ofono_dbus_queue_reply_all_fn_param(test->queue, NULL, NULL);
|
||||
g_assert(__ofono_dbus_queue_pending(test->queue));
|
||||
@@ -508,10 +521,12 @@ static DBusMessage *test_reply_handler(DBusConnection *conn,
|
||||
/* This one test_reply_3 with Failed */
|
||||
__ofono_dbus_queue_reply_all_error(test->queue, NULL);
|
||||
|
||||
/* This one test_reply_4 with NotSupported */
|
||||
/* This one completes all test_reply_4 with NotSupported */
|
||||
error.type = OFONO_ERROR_TYPE_ERRNO;
|
||||
error.error = -EOPNOTSUPP;
|
||||
__ofono_dbus_queue_reply_all_error(test->queue, &error);
|
||||
|
||||
/* test_reply_5 must be already completed */
|
||||
g_assert(!__ofono_dbus_queue_pending(test->queue));
|
||||
|
||||
/* And this one does nothing */
|
||||
@@ -541,7 +556,8 @@ static void test_reply_start(struct test_dbus_context *dbus)
|
||||
test_client_call(dbus, 4, test_dbus_expect_empty_reply);
|
||||
test_client_call(dbus, 5, test_expect_failed);
|
||||
test_client_call(dbus, 6, test_expect_not_supported);
|
||||
test_client_call(dbus, 7, test_reply_last_reply);
|
||||
test_client_call(dbus, 7, test_expect_not_supported);
|
||||
test_client_call(dbus, 8, test_reply_last_reply);
|
||||
}
|
||||
|
||||
static void test_reply(void)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -133,6 +133,13 @@ guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender,
|
||||
return test_dbus_add_watch(connection, NULL, destroy, user_data);
|
||||
}
|
||||
|
||||
guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
|
||||
GDBusWatchFunction func, void *user_data,
|
||||
GDBusDestroyFunction destroy)
|
||||
{
|
||||
return test_dbus_add_watch(connection, func, destroy, user_data);
|
||||
}
|
||||
|
||||
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
|
||||
{
|
||||
struct test_dbus_watch *prev = NULL;
|
||||
@@ -303,6 +310,9 @@ static DBusHandlerResult test_dbus_client_message_cb(DBusConnection *conn,
|
||||
dbus_message_get_path(msg));
|
||||
test->client_signals = g_slist_append(test->client_signals,
|
||||
dbus_message_ref(msg));
|
||||
if (test->handle_signal) {
|
||||
test->handle_signal(test, msg);
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
} else {
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user