Compare commits

..

3 Commits

Author SHA1 Message Date
Slava Monich
9bede136cc [ril] Handle NITZ string without DST part. Fixes JB#41890 2018-05-16 16:16:31 +03:00
Slava Monich
b3380c6eca [ril] Don't wait for SIM state change after enabling/disabling pin. JB#41508
There's no real need for that, but most importantly no SIM state change
event is generated by MTK RIL in such cases.
2018-05-14 18:51:31 +03:00
Slava Monich
f98e9a2193 ussd: Don't ignore data from TERMINATED response
Typically responses to USSD requests are coming with status
zero (NOTIFY) but some are coming with status 2 (TERMINATED).
If those contain data, the data should be presented to the user.

[ussd] Don't ignore data from TERMINATED response. Fixes JB#41734
2018-04-25 11:07:35 +03:00
212 changed files with 5687 additions and 27944 deletions

12
ofono/.gitignore vendored
View File

@@ -32,8 +32,6 @@ src/ofono.service
dundee/dundee
dundee/dundee.service
test-driver
test-suite.log
unit/test-common
unit/test-util
unit/test-idmap
@@ -44,31 +42,23 @@ unit/test-mux
unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-dbus-access
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
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_access
unit/test-sailfish_cell_info
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-sailfish_watch
unit/test-sms-filter
unit/test-voicecall-filter
unit/test-*.log
unit/test-*.trs
unit/test-mbim
unit/test-grilreply
unit/test-grilrequest

View File

@@ -115,7 +115,6 @@ Antara Borwankar <antara.borwankar@gmail.com>
Martin Chaplet <m.chaplet@kerlink.fr>
Suman Mallela <suman.m@intel.com>
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
Ankit Navik <ankit.p.navik@intel.com>
Antoine Aubert <a.aubert@overkiz.com>
Djalal Harouni <djalal@endocode.com>
Christophe Ronco <c.ronco@kerlink.fr>
@@ -127,6 +126,3 @@ Jonas Bonn <jonas@southpole.se>
Matthijs Kooijman <matthijs@stdin.nl>
Clayton Craft <clayton@craftyguy.net>
Joey Hewitt <joey@joeyhewitt.com>
Richard Röjfors <richard.rojfors@gmail.com>
Philippe De Swert <philippe.deswert@nomovok.com>
Gabriel Lucas <gabriel.lucas@smile.fr>

View File

@@ -1,21 +1,3 @@
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.
Fix issue with data mode and DCD for U-Blox modems.
Fix issue with SMS receive on QMI based Quectel EC21.
Fix issue with HFP support and last call dialed request.
Fix issue with PIM retires handling and Gemalto modems.
Fix issue with atom registration and SIM state handling.
Add support for handling SIM card AID session management.
Add support for handling GSM/UMTS and IMS authentication.
Add support for IP Multimedia Subsystem (IMS) atom.
Add support for MBIM based modems.
ver 1.21:
Fix issue with USSD notification received handling.
Fix issue with crashing SIM filesystem notifications.

View File

@@ -24,14 +24,17 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/sim-mnclength.h \
include/handsfree-audio.h include/siri.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/netmon.h include/lte.h include/ims.h \
include/storage.h
include/netmon.h include/lte.h \
include/storage.h \
gdbus/gdbus.h
nodist_pkginclude_HEADERS = include/version.h
if SAILFISH_MANAGER
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
include/sailfish_manager.h include/sailfish_watch.h
endif
local_headers = $(foreach file,$(pkginclude_HEADERS) \
$(nodist_pkginclude_HEADERS), \
include/ofono/$(notdir $(file)))
@@ -63,7 +66,7 @@ endif
builtin_modules =
builtin_sources =
builtin_libadd =
builtin_cflags = -DSAILFISH_OS
builtin_cflags =
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
@@ -126,13 +129,8 @@ builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_manager_dbus.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c
endif
if SAILFISH_ACCESS
builtin_modules += sailfish_access
builtin_sources += plugins/sailfish_access.c
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
plugins/sailfish_manager/sailfish_watch.c
endif
if RILMODEM
@@ -145,16 +143,9 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_call_volume.c \
drivers/ril/ril_cell_info.c \
drivers/ril/ril_config.c \
drivers/ril/ril_connman.c \
drivers/ril/ril_cbs.c \
drivers/ril/ril_data.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 \
@@ -290,8 +281,7 @@ qmi_sources = drivers/qmimodem/qmi.h drivers/qmimodem/qmi.c \
drivers/qmimodem/wds.h \
drivers/qmimodem/pds.h \
drivers/qmimodem/common.h \
drivers/qmimodem/wda.h \
drivers/qmimodem/voice.h
drivers/qmimodem/wda.h
builtin_modules += qmimodem
builtin_sources += $(qmi_sources) \
@@ -307,7 +297,6 @@ 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
@@ -340,6 +329,7 @@ builtin_sources += drivers/atmodem/atmodem.h \
drivers/atmodem/atutil.c \
drivers/atmodem/gprs.c \
drivers/atmodem/gprs-context.c \
drivers/atmodem/sim-auth.c \
drivers/atmodem/gnss.c \
drivers/atmodem/lte.c
@@ -476,8 +466,7 @@ builtin_modules += xmm7modem
builtin_sources += drivers/atmodem/atutil.h \
drivers/xmm7modem/xmm7modem.h \
drivers/xmm7modem/xmm7modem.c \
drivers/xmm7modem/radio-settings.c \
drivers/xmm7modem/ims.c
drivers/xmm7modem/radio-settings.c
if PHONESIM
builtin_modules += phonesim
@@ -573,6 +562,9 @@ builtin_sources += plugins/samsung.c
builtin_modules += sim900
builtin_sources += plugins/sim900.c
builtin_modules += connman
builtin_sources += plugins/connman.c
builtin_modules += telit
builtin_sources += plugins/telit.c
@@ -715,36 +707,6 @@ builtin_sources += plugins/smshistory.c
builtin_modules += allowed_apns
builtin_sources += plugins/allowed-apns.c
if ELL
builtin_cflags += @ELL_CFLAGS@
builtin_libadd += @ELL_LIBS@
if MBIMMODEM
mbim_sources = drivers/mbimmodem/mbim.h \
drivers/mbimmodem/mbim.c \
drivers/mbimmodem/mbim-desc.h \
drivers/mbimmodem/mbim-desc.c \
drivers/mbimmodem/mbim-message.h \
drivers/mbimmodem/mbim-message.c
builtin_modules += mbimmodem
builtin_sources += $(mbim_sources) \
drivers/mbimmodem/util.h \
drivers/mbimmodem/util.c \
drivers/mbimmodem/mbimmodem.h \
drivers/mbimmodem/mbimmodem.c \
drivers/mbimmodem/devinfo.c \
drivers/mbimmodem/sim.c \
drivers/mbimmodem/network-registration.c \
drivers/mbimmodem/sms.c \
drivers/mbimmodem/gprs.c \
drivers/mbimmodem/gprs-context.c
builtin_modules += mbim
builtin_sources += plugins/mbim.c
endif
endif
sbin_PROGRAMS = src/ofonod
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
@@ -774,11 +736,9 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/cdma-provision.c src/handsfree.c \
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/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 \
src/sms-filter.c src/gprs-filter.c src/dbus-queue.c \
src/hfp.h src/siri.c \
src/netmon.c src/lte.c \
src/netmonagent.c src/netmonagent.h
src_ofonod_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@@ -789,8 +749,7 @@ src_ofonod_LDFLAGS = -Wl,--export-dynamic \
BUILT_SOURCES = $(local_headers) src/builtin.h
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA) \
$(shell find . -name "*.gcda") $(shell find . -name "*.gcno")
CLEANFILES = $(BUILT_SOURCES) $(rules_DATA)
plugindir = $(pkglibdir)/plugins
@@ -806,8 +765,7 @@ 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)/plugins/sailfish_manager
-I$(srcdir)/btio -I$(srcdir)/gril
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 \
@@ -831,8 +789,7 @@ doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
doc/networkmonitor-api.txt \
doc/allowed-apns-api.txt \
doc/lte-api.txt \
doc/cinterion-hardware-monitor-api.txt \
doc/ims-api.txt
doc/cinterion-hardware-monitor-api.txt
test_scripts = test/backtrace \
@@ -941,10 +898,7 @@ test_scripts = test/backtrace \
test/enable-throttling \
test/disable-throttling \
test/set-lte-property \
test/test-serving-cell-info \
test/ims-register \
test/ims-unregister \
test/list-applications
test/test-serving-cell-info
if TEST
@@ -971,7 +925,8 @@ 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)
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-Iplugins/sailfish_manager
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info
@@ -984,78 +939,57 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
gdbus/object.c \
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
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
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_watch.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watchlist.c src/log.c
src/storage.c src/watch.c src/log.c
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-DSTORAGEDIR='"/tmp/ofono"'
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
unit_tests += unit/test-sailfish_sim_info
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
unit/test-dbus.c unit/fake_watch.c \
unit/test-dbus.c unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
gdbus/object.c \
src/dbus.c src/storage.c src/watchlist.c src/log.c
src/dbus.c src/storage.c src/watch.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
-Iplugins/sailfish_manager
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
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
unit/fake_watch.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_manager.c \
plugins/sailfish_manager/sailfish_cell_info.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"'
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
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"'
unit_test_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_watch_OBJECTS)
unit_tests += unit/test-watch
unit_test_sailfish_watch_SOURCES = unit/test-sailfish_watch.c \
plugins/sailfish_manager/sailfish_watch.c \
src/log.c src/watch.c
unit_test_sailfish_watch_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
unit_test_sailfish_watch_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_watch_OBJECTS)
unit_tests += unit/test-sailfish_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
unit_test_sailfish_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_sailfish_access_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_access_OBJECTS)
unit_tests += unit/test-sailfish_access
endif
unit_test_dbus_access_SOURCES = unit/test-dbus-access.c src/dbus-access.c \
src/log.c
unit_test_dbus_access_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_dbus_access_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_access_OBJECTS)
unit_tests += unit/test-dbus-access
if RILMODEM
if SAILFISH_RILMODEM
@@ -1066,13 +1000,6 @@ 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)
@@ -1080,14 +1007,6 @@ unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_util_OBJECTS)
unit_tests += unit/test-ril_util
unit_test_ril_vendor_SOURCES = unit/test-ril_vendor.c unit/fake_watch.c \
drivers/ril/ril_vendor.c drivers/ril/ril_vendor_mtk.c \
drivers/ril/ril_util.c src/log.c
unit_test_ril_vendor_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_vendor_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_vendor_OBJECTS)
unit_tests += unit/test-ril_vendor
else
unit_tests += unit/test-rilmodem-cs \
unit/test-rilmodem-cs \
@@ -1098,13 +1017,6 @@ unit_tests += unit/test-rilmodem-cs \
endif
endif
if ELL
if MBIMMODEM
unit_tests += unit/test-mbim
endif
endif
noinst_PROGRAMS = $(unit_tests) \
unit/test-sms-root unit/test-mux unit/test-caif
@@ -1181,13 +1093,6 @@ unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_provision_OBJECTS)
unit_tests += unit/test-provision
unit_test_ril_transport_SOURCES = unit/test-ril-transport.c \
src/ril-transport.c src/log.c
unit_test_ril_transport_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_ril_transport_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_ril_transport_OBJECTS)
unit_tests += unit/test-ril-transport
unit_test_sms_filter_SOURCES = unit/test-sms-filter.c \
src/sms-filter.c src/log.c
unit_test_sms_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
@@ -1202,14 +1107,6 @@ unit_test_gprs_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_gprs_filter_OBJECTS)
unit_tests += unit/test-gprs-filter
unit_test_voicecall_filter_SOURCES = unit/test-voicecall-filter.c \
src/voicecall-filter.c src/log.c \
src/common.c src/util.c
unit_test_voicecall_filter_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_voicecall_filter_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_voicecall_filter_OBJECTS)
unit_tests += unit/test-voicecall-filter
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
unit/rilmodem-test-server.h \
@@ -1247,12 +1144,6 @@ unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
unit_test_mbim_SOURCES = unit/test-mbim.c \
drivers/mbimmodem/mbim-message.c \
drivers/mbimmodem/mbim.c
unit_test_mbim_LDADD = @ELL_LIBS@
unit_objects += $(unit_test_mbim_OBJECTS)
TESTS = $(unit_tests)
if TOOLS

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(ofono, 1.23)
AC_INIT(ofono, 1.21)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AC_CONFIG_HEADERS(config.h)
@@ -33,7 +33,7 @@ AC_PROG_LIBTOOL
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
[disable code optimization through compiler]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
CFLAGS="$CFLAGS -O0"
fi
])
@@ -183,19 +183,17 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
[enable_sailfish_rilmodem="no"])
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.35, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.35 is required))
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GLIBUTIL_LIBS"
if (test "${enable_sailfish_rilmodem}" = "yes"); then
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))
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.21, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.21 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
AC_MSG_ERROR(libmce-glib >= 1.0.5 is required))
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
enable_sailfish_manager=yes
need_glibutil=yes
fi
AC_ARG_ENABLE(sailfish-manager,
@@ -204,10 +202,12 @@ AC_ARG_ENABLE(sailfish-manager,
[enable_sailfish_manager=${enableval}])
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required by unit tests))
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
if (test "${enable_sailfish_manager}" = "yes"); then
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required by unit tests))
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
@@ -292,25 +292,6 @@ AC_ARG_ENABLE(upower, AC_HELP_STRING([--disable-upower],
[enable_upower=${enableval}])
AM_CONDITIONAL(UPOWER, test "${enable_power}" != "no")
AC_ARG_ENABLE(mbimmodem, AC_HELP_STRING([--enable-mbimmodem],
[enable MBIM based modem support]),
[enable_mbimmodem=${enableval}])
AC_ARG_ENABLE(ell, AC_HELP_STRING([--enable-ell],
[enable support for ell]),
[enable_ell=${enableval}])
if (test "${enable_ell}" = "yes"); then
AC_DEFINE(HAVE_ELL, 1, [Defined if Ell is enabled])
PKG_CHECK_MODULES(ELL, ell >= 0.2, dummy=yes,
AC_MSG_ERROR(ell library >= 0.2 is required))
AC_SUBST(ELL_CFLAGS)
AC_SUBST(ELL_LIBS)
fi
AM_CONDITIONAL(MBIMMODEM, test "${enable_ell}" != "no" && test "${enable_mbimmodem}" = "yes")
AM_CONDITIONAL(ELL, test "${enable_ell}" != "no")
AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
[do not install configuration and data files]),
[enable_datafiles=${enableval}])
@@ -322,23 +303,13 @@ AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforw
[enable_sailfish_pushforwarder="no"])
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
if (test "${enable_sailfish_pushforwarder}" != "no"); then
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
AC_MSG_ERROR(WSP decoder is required))
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
LIBS="$LIBS $WSPCODEC_LIBS"
fi
AC_ARG_ENABLE(sailfish-access, AC_HELP_STRING([--enable-sailfish-access],
[enable Sailfish OS access plugin]),
[enable_sailfish_access=${enableval}],
[enable_sailfish_access="no"])
AM_CONDITIONAL(SAILFISH_ACCESS, test "${enable_sailfish_access}" != "no")
if (test "${enable_sailfish_access}" == "yes"); then
PKG_CHECK_MODULES(DBUSACCESS, libdbusaccess, dummy=yes,
AC_MSG_ERROR(libdbusaccess is required))
CFLAGS="$CFLAGS $DBUSACCESS_CFLAGS"
LIBS="$LIBS $DBUSACCESS_LIBS"
need_glibutil=yes
fi
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
@@ -353,6 +324,11 @@ if (test "${enable_sailfish_debuglog}" = "yes"); then
LIBS="$LIBS $DBUSLOG_LIBS"
fi
if (test "${need_glibutil}" = "yes"); then
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
LIBS="$LIBS $GLIBUTIL_LIBS"
fi
if (test "${prefix}" = "NONE"); then
dnl no prefix and no localstatedir, so default to /var
if (test "$localstatedir" = '${prefix}/var'); then

View File

@@ -1,59 +0,0 @@
IpMultimediaSystem Hierarchy
============================
Service org.ofono
Interface org.ofono.IpMultimediaSystem
Object path [variable prefix]/{modem0,modem1,...}
Methods dict GetProperties()
Returns all IpMultimediaSystem configuration properties.
void SetProperty(string property, variant value)
Changes the value of the specified property. Only
properties that are listed as readwrite are
changeable. On success a PropertyChanged signal
will be emitted.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.Failed
void Register()
Attempts to register to IMS. A successful method return
indicates that the registration process could be
initiated successfully. The actual registration state
will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress
[service].Error.NotImplemented
void Unregister()
Attempts to unregister from IMS. A successful method
return indicates that the unregistration process could
be initiated successfully. The actual unregistration
state will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress
[service].Error.NotImplemented
Signals PropertyChanged(string property, variant value)
This signal indicates a changed value of the given
property.
Properties boolean Registered [readonly]
Contains the current IMS registration state.
boolean VoiceCapable [readonly, optional]
Boolean representing whether voice call transfer over
RTP (IMS) is available.
boolean SmsCapable [readonly, optional]
Boolean representing whether SMS-over-IMS is available.

View File

@@ -95,13 +95,6 @@ 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
@@ -134,8 +127,6 @@ Properties boolean Powered [readwrite]
org.ofono.CallVolume
org.ofono.CellBroadcast
org.ofono.Handsfree
org.ofono.IpMultimediaSystem
org.ofono.LongTermEvolution
org.ofono.LocationReporting
org.ofono.MessageManager
org.ofono.MessageWaiting

View File

@@ -200,8 +200,3 @@ Properties boolean Present [readonly]
might have changed the retry counters, i.e. calls to
ChangePin(), EnterPin(), ResetPin() LockPin(),
UnlockPin().
string ImsPrivateIdentity [readonly, optional]
Contains the SIM's ImsPrivateIdentity, read from the
ISIM.

View File

@@ -1,104 +0,0 @@
SimAuthentication heiarchy [experimental]
===========================================
Service org.ofono
Interface org.ofono.SimAuthentication
Object path [variable prefix]/{modem0,modem1,...}
Methods array{object,dict} GetApplications()
Get an array of all SIM applications found during
discovery. In the format "a{oa{sv}}" where 'o' is
the object path for the application e.g.
o = "/modem1/A0000000871004FFFFFFFF8906190000"
Each dictionary will contain 'Type' e.g. 'Ims' and
'Name' e.g. 'ISim'
For each application there will be a corresponding
object that matches the path (o). The type will
signify which interfaces are under that object (below).
type = Umts --> org.ofono.USimApplication
type = Ims --> org.ofono.ISimApplication
SimAuth USIM application heiarchy [experimental]
===========================================
Service org.ofono
Interface org.ofono.USimApplication
Object path [variable prefix]/{modem0,modem1,...}/{AID name}
Methods dict GetProperties()
Returns properties for the USimApplication. See
properties section for available properties.
array{dict{string, array{byte}}}
GsmAuthenticate(array{array{byte}} rands)
Run the USIM application GSM AUTHENTICATE algorithm
with N random challenges 'rands'. This should be an
array of an array of bytes ("aay"). The number of
random challenges is limited to a maximum of 3.
Returns the derived Kc/SRES values as an array of
dictionaries. The index of each dictionary matches
the index of the rand value in the method call. The
keys for each dictionary are "Kc" and "SRES" and both
are arrays of bytes.
Possible Errors:
[service].Error.NotSupported
[service].Error.Busy
dict{string, array{byte}}
UmtsAuthenticate(array{byte} rand, array{byte} autn)
Run the UMTS AUTHENTICATE algorithm in the 3G
context with 'rand' and 'autn'. A dictionary will be
returned containing 'RES', 'CK', 'IK' and possibly
'Kc' if service 27 is available. If there was a
sync error 'AUTS' will be returned.
Possible Errors: [service].Error.NotSupported
Properties string Type [readonly]
Type of application: 'Umts'
string Name [readonly]
Human readable name: 'USim'
SimAuth ISIM application heiarchy [experimental]
===========================================
Service org.ofono
Interface org.ofono.ISimApplication
Object [variable prefix]/{modem0,modem1,...}/{AID name}
Methods dict GetProperties()
Returns properties for the ISimApplication. See
the properties section for available properties.
dict{string, array{byte}
ImsAuthenticate(array{byte} rand, array{byte} autn)
Run the UMTS AUTHENTICATE algorithm in the IMS
context with 'rand' and 'autn'. A dictionary will be
returned containing 'RES', 'CK', 'IK' and possibly
'Kc' if service 27 is available. If there was a
sync error 'AUTS' will be returned.
Possible Errors: [service].Error.NotSupported
Properties string Type [readonly]
Type of application: 'Ims'
string Name [readonly]
Human readable name: 'ISim'

View File

@@ -59,27 +59,6 @@ Methods dict GetProperties()
[service].Error.NotImplemented
[service].Error.Failed
object DialLast()
Initiates a new outgoing call to the last dialled number.
Possible Errors: [service].Error.InProgress
[service].Error.InvalidArguments
[service].Error.InvalidFormat
[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

View File

@@ -50,6 +50,7 @@ static int atmodem_init(void)
at_call_volume_init();
at_gprs_init();
at_gprs_context_init();
at_sim_auth_init();
at_gnss_init();
at_lte_init();
@@ -58,6 +59,7 @@ static int atmodem_init(void)
static void atmodem_exit(void)
{
at_sim_auth_exit();
at_stk_exit();
at_sim_exit();
at_sms_exit();

View File

@@ -0,0 +1,164 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. 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 <string.h>
#include <glib.h>
#include <ofono/modem.h>
#include <ofono/sim-auth.h>
#include "gatchat.h"
#include "gatresult.h"
#include "simutil.h"
#include "vendor.h"
#include "atmodem.h"
struct sim_auth_data {
GAtChat *chat;
unsigned int vendor;
};
static const char *cuad_prefix[] = { "+CUAD:", NULL };
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_list_apps_cb_t cb = cbd->cb;
struct ofono_error error;
const unsigned char *dataobj;
gint linelen;
unsigned char *buffer;
int len;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, NULL, 0, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
len = 0;
while (g_at_result_iter_next(&iter, "+CUAD:")) {
if (!g_at_result_iter_next_hexstring(&iter, NULL, &linelen))
goto error;
len += linelen;
}
g_at_result_iter_init(&iter, result);
buffer = g_malloc(len);
len = 0;
while (g_at_result_iter_next(&iter, "+CUAD:")) {
g_at_result_iter_next_hexstring(&iter, &dataobj, &linelen);
memcpy(buffer + len, dataobj, linelen);
len += linelen;
}
cb(&error, buffer, len, cbd->data);
g_free(buffer);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
}
static void at_discover_apps(struct ofono_sim_auth *sa,
ofono_sim_list_apps_cb_t cb,
void *data)
{
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(sad->chat, "AT+CUAD", cuad_prefix,
at_discover_apps_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static gboolean at_sim_auth_register(gpointer user)
{
struct ofono_sim_auth *sa = user;
ofono_sim_auth_register(sa);
return FALSE;
}
static int at_sim_auth_probe(struct ofono_sim_auth *sa, unsigned int vendor,
void *data)
{
GAtChat *chat = data;
struct sim_auth_data *sad;
sad = g_new0(struct sim_auth_data, 1);
sad->chat = g_at_chat_clone(chat);
sad->vendor = vendor;
ofono_sim_auth_set_data(sa, sad);
g_idle_add(at_sim_auth_register, sa);
return 0;
}
static void at_sim_auth_remove(struct ofono_sim_auth *sa)
{
struct sim_auth_data *sad = ofono_sim_auth_get_data(sa);
g_idle_remove_by_data(sa);
ofono_sim_auth_set_data(sa, NULL);
g_at_chat_unref(sad->chat);
g_free(sad);
}
static struct ofono_sim_auth_driver driver = {
.name = "atmodem",
.probe = at_sim_auth_probe,
.remove = at_sim_auth_remove,
.list_apps = at_discover_apps,
};
void at_sim_auth_init(void)
{
ofono_sim_auth_driver_register(&driver);
}
void at_sim_auth_exit(void)
{
ofono_sim_auth_driver_unregister(&driver);
}

View File

@@ -39,7 +39,6 @@
#include "gatresult.h"
#include "simutil.h"
#include "vendor.h"
#include "util.h"
#include "atmodem.h"
@@ -51,6 +50,7 @@
struct sim_data {
GAtChat *chat;
unsigned int vendor;
guint ready_id;
guint passwd_type_mask;
struct at_util_sim_state_query *sim_state_query;
};
@@ -65,36 +65,14 @@ static const char *pinnum_prefix[] = { "%PINNUM:", NULL };
static const char *oercn_prefix[] = { "_OERCN:", NULL };
static const char *cpinr_prefixes[] = { "+CPINR:", "+CPINRE:", NULL };
static const char *epin_prefix[] = { "*EPIN:", NULL };
static const char *simcom_spic_prefix[] = { "+SPIC:", NULL };
static const char *cinterion_spic_prefix[] = { "^SPIC:", NULL };
static const char *spic_prefix[] = { "+SPIC:", NULL };
static const char *pct_prefix[] = { "#PCT:", NULL };
static const char *pnnm_prefix[] = { "+PNNM:", NULL };
static const char *qpinc_prefix[] = { "+QPINC:", NULL };
static const char *upincnt_prefix[] = { "+UPINCNT:", NULL };
static const char *cuad_prefix[] = { "+CUAD:", NULL };
static const char *ccho_prefix[] = { "+CCHO:", NULL };
static const char *crla_prefix[] = { "+CRLA:", NULL };
static const char *cgla_prefix[] = { "+CGLA:", NULL };
static const char *none_prefix[] = { NULL };
static void append_file_path(char *buf, const unsigned char *path,
unsigned int path_len)
{
if (path_len > 0) {
*buf++ = ',';
*buf++ = ',';
*buf++ = '\"';
for (; path_len; path_len--)
buf += sprintf(buf, "%02hhX", *path++);
*buf++ = '\"';
*buf = '\0';
}
}
static void get_response_common_cb(gboolean ok, GAtResult *result,
gpointer user_data, const char *prefix)
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
@@ -116,7 +94,7 @@ static void get_response_common_cb(gboolean ok, GAtResult *result,
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, prefix))
if (!g_at_result_iter_next(&iter, "+CRSM:"))
goto error;
g_at_result_iter_next_number(&iter, &sw1);
@@ -157,11 +135,6 @@ error:
EF_STATUS_INVALIDATED, cbd->data);
}
static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
get_response_common_cb(ok, result, user_data, "+CRSM:");
}
static void at_sim_read_info(struct ofono_sim *sim, int fileid,
const unsigned char *path,
unsigned int path_len,
@@ -203,7 +176,15 @@ static void at_sim_read_info(struct ofono_sim *sim, int fileid,
break;
}
append_file_path(buf + len, path, path_len);
if (path_len > 0) {
len += sprintf(buf + len, ",,\"");
for (; path_len; path_len--)
len += sprintf(buf + len, "%02hhX", *path++);
buf[len++] = '\"';
buf[len] = '\0';
}
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
at_crsm_info_cb, cbd, g_free) > 0)
@@ -277,7 +258,17 @@ static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
len = snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
start >> 8, start & 0xff, length);
append_file_path(buf + len, path, path_len);
if (path_len > 0) {
buf[len++] = ',';
buf[len++] = ',';
buf[len++] = '\"';
for (; path_len; path_len--)
len += sprintf(buf + len, "%02hhX", *path++);
buf[len++] = '\"';
buf[len] = '\0';
}
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
at_crsm_read_cb, cbd, g_free) > 0)
@@ -297,13 +288,10 @@ static void at_sim_read_record(struct ofono_sim *sim, int fileid,
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[128];
unsigned int len;
len = snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
record, length);
append_file_path(buf + len, path, path_len);
if (g_at_chat_send(sd->chat, buf, crsm_prefix,
at_crsm_read_cb, cbd, g_free) > 0)
return;
@@ -849,7 +837,7 @@ static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, retries, cbd->data);
}
static void simcom_spic_cb(gboolean ok, GAtResult *result, gpointer user_data)
static void at_spic_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
@@ -1066,46 +1054,6 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void cinterion_spic_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_sim *sim = cbd->user;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
const char *final = g_at_result_final_response(result);
GAtResultIter iter;
struct ofono_error error;
int retries[OFONO_SIM_PASSWORD_INVALID];
size_t i;
int pin_type = ofono_sim_get_password_type(sim);
decode_at_error(&error, final);
if (!ok) {
cb(&error, NULL, cbd->data);
return;
}
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
retries[i] = -1;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "^SPIC:"))
goto error;
if (!g_at_result_iter_next_number(&iter, &retries[pin_type]))
goto error;
DBG("Retry : %d, type : %d", retries[pin_type], pin_type);
cb(&error, retries, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void at_pin_retries_query(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb,
void *data)
@@ -1153,8 +1101,8 @@ static void at_pin_retries_query(struct ofono_sim *sim,
return;
break;
case OFONO_VENDOR_SIMCOM:
if (g_at_chat_send(sd->chat, "AT+SPIC", simcom_spic_prefix,
simcom_spic_cb, cbd, g_free) > 0)
if (g_at_chat_send(sd->chat, "AT+SPIC", spic_prefix,
at_spic_cb, cbd, g_free) > 0)
return;
break;
case OFONO_VENDOR_TELIT:
@@ -1178,11 +1126,6 @@ static void at_pin_retries_query(struct ofono_sim *sim,
upincnt_cb, cbd, g_free) > 0)
return;
break;
case OFONO_VENDOR_CINTERION:
if (g_at_chat_send(sd->chat, "AT^SPIC", cinterion_spic_prefix,
cinterion_spic_cb, cbd, g_free) > 0)
return;
break;
default:
if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
at_cpinr_cb, cbd, g_free) > 0)
@@ -1273,24 +1216,100 @@ static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void at_xsim_notify(GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
GAtResultIter iter;
int state;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XSIM:"))
return;
if (!g_at_result_iter_next_number(&iter, &state))
return;
switch (state) {
case 3: /* PIN verified Ready */
break;
default:
return;
}
cb(&error, cbd->data);
g_at_chat_unregister(sd->chat, sd->ready_id);
sd->ready_id = 0;
}
static void at_epev_notify(GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
cb(&error, cbd->data);
g_at_chat_unregister(sd->chat, sd->ready_id);
sd->ready_id = 0;
}
static void at_qss_notify(GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
GAtResultIter iter;
int state;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "#QSS:"))
return;
if (!g_at_result_iter_next_number(&iter, &state))
return;
switch (state) {
case 3: /* SIM inserted and READY. */
break;
default:
return;
}
cb(&error, cbd->data);
g_at_chat_unregister(sd->chat, sd->ready_id);
sd->ready_id = 0;
}
static void sim_state_cb(gboolean present, gpointer user_data)
{
struct ofono_sim *sim = user_data;
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = user_data;
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
void *data = cbd->data;
at_util_sim_state_query_free(sd->sim_state_query);
sd->sim_state_query = NULL;
if (present == 1)
ofono_sim_initialized_notify(sim);
CALLBACK_WITH_SUCCESS(cb, data);
else
CALLBACK_WITH_FAILURE(cb, data);
}
static void at_pin_send_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
struct ofono_sim *sim = cbd->user;
struct sim_data *sd = ofono_sim_get_data(sim);
struct sim_data *sd = cbd->user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error;
@@ -1300,6 +1319,36 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
goto done;
switch (sd->vendor) {
case OFONO_VENDOR_IFX:
/*
* On the IFX modem, AT+CPIN? can return READY too
* early and so use +XSIM notification to detect
* the ready state of the SIM.
*/
sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
at_xsim_notify,
FALSE, cbd, g_free);
return;
case OFONO_VENDOR_MBM:
/*
* On the MBM modem, AT+CPIN? keeps returning SIM PIN
* for a moment after successful AT+CPIN="..", but then
* sends *EPEV when that changes.
*/
sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
at_epev_notify,
FALSE, cbd, g_free);
return;
case OFONO_VENDOR_TELIT:
/*
* On the Telit modem, AT+CPIN? can return READY too
* early and so use #QSS notification to detect
* the ready state of the SIM.
*/
sd->ready_id = g_at_chat_register(sd->chat, "#QSS",
at_qss_notify,
FALSE, cbd, g_free);
return;
case OFONO_VENDOR_ZTE:
case OFONO_VENDOR_ALCATEL:
case OFONO_VENDOR_HUAWEI:
@@ -1317,12 +1366,15 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
* state.
*/
sd->sim_state_query = at_util_sim_state_query_new(sd->chat,
2, 20, sim_state_cb, sim,
NULL);
2, 20, sim_state_cb, cbd,
g_free);
return;
}
done:
cb(&error, cbd->data);
g_free(cbd);
}
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
@@ -1333,12 +1385,12 @@ static void at_pin_send(struct ofono_sim *sim, const char *passwd,
char buf[64];
int ret;
cbd->user = sim;
cbd->user = sd;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
ret = g_at_chat_send(sd->chat, buf, none_prefix,
at_pin_send_cb, cbd, g_free);
at_pin_send_cb, cbd, NULL);
memset(buf, 0, sizeof(buf));
@@ -1551,327 +1603,6 @@ done:
ofono_sim_register(sim);
}
static void at_discover_apps_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_list_apps_cb_t cb = cbd->cb;
struct ofono_error error;
const unsigned char *buffer;
int len;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, NULL, 0, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CUAD:"))
goto error;
if (!g_at_result_iter_next_hexstring(&iter, &buffer, &len))
goto error;
cb(&error, buffer, len, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
}
static void at_discover_apps(struct ofono_sim *sim,
ofono_sim_list_apps_cb_t cb,
void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(sd->chat, "AT+CUAD", cuad_prefix,
at_discover_apps_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void at_open_channel_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_open_channel_cb_t cb = cbd->cb;
struct ofono_error error;
int session_id = -1;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CCHO:"))
goto error;
if (!g_at_result_iter_next_number(&iter, &session_id))
goto error;
cb(&error, session_id, cbd->data);
return;
error:
cb(&error, -1, cbd->data);
}
static void at_open_channel(struct ofono_sim *sim, const unsigned char *aid,
ofono_sim_open_channel_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char cmd[43];
int ret = 0;
strcpy(cmd, "AT+CCHO=\"");
ret += 9;
encode_hex_own_buf(aid, 16, 0, cmd + ret);
ret += 32;
strcpy(cmd + ret, "\"");
if (g_at_chat_send(sd->chat, cmd, ccho_prefix, at_open_channel_cb,
cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void at_close_channel_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_close_channel_cb_t cb = cbd->cb;
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
if (cb)
cb(&error, cbd->data);
}
static void at_close_channel(struct ofono_sim *sim, int session_id,
ofono_sim_close_channel_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char cmd[15];
sprintf(cmd, "AT+CCHC=%d", session_id);
g_at_chat_send(sd->chat, cmd, NULL, at_close_channel_cb, cbd, g_free);
}
static void at_crla_read_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_read_cb_t cb = cbd->cb;
struct ofono_error error;
const guint8 *response;
gint sw1, sw2, len;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, NULL, 0, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CRLA:")) {
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
return;
}
g_at_result_iter_next_number(&iter, &sw1);
g_at_result_iter_next_number(&iter, &sw2);
if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
(sw1 == 0x90 && sw2 != 0x00)) {
memset(&error, 0, sizeof(error));
error.type = OFONO_ERROR_TYPE_SIM;
error.error = (sw1 << 8) | sw2;
cb(&error, NULL, 0, cbd->data);
return;
}
if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
return;
}
DBG("crla_read_cb: %02x, %02x, %d", sw1, sw2, len);
cb(&error, response, len, cbd->data);
}
static void at_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 sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
unsigned int len;
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,176,%i,%i,%i,%i,,",
session, fileid, start >> 8, start & 0xff, length);
append_file_path(buf + len, path, path_len);
if (g_at_chat_send(sd->chat, buf, crla_prefix,
at_crla_read_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void at_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 sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[128];
unsigned int len;
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,178,%i,%i,4,%i",
session_id, fileid, record, length);
append_file_path(buf + len, path, path_len);
if (g_at_chat_send(sd->chat, buf, crla_prefix,
at_crla_read_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static void at_crla_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
get_response_common_cb(ok, result, user_data, "+CRLA:");
}
static void at_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 sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[128];
unsigned int len;
len = snprintf(buf, sizeof(buf), "AT+CRLA=%i,192,%i", session_id,
fileid);
append_file_path(buf + len, path, path_len);
if (g_at_chat_send(sd->chat, buf, crla_prefix,
at_crla_info_cb, cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
EF_STATUS_INVALIDATED, data);
}
static void logical_access_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_logical_access_cb_t cb = cbd->cb;
struct ofono_error error;
const char *str_data;
unsigned char *raw;
gint len = 0;
GAtResultIter iter;
decode_at_error(&error, g_at_result_final_response(result));
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CGLA:"))
goto error;
if (!g_at_result_iter_next_number(&iter, &len))
goto error;
if (!g_at_result_iter_next_string(&iter, &str_data))
goto error;
raw = alloca(len / 2);
decode_hex_own_buf(str_data, len, NULL, 0, raw);
cb(&error, raw, len / 2, cbd->data);
return;
error:
cb(&error, NULL, 0, cbd->data);
}
static void at_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)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
int ret = 0;
char cmd[(len * 2) + 19];
ret = sprintf(cmd, "AT+CGLA=%d,%d,\"", session_id, len * 2);
encode_hex_own_buf(pdu, len, 0, cmd + ret);
ret += len * 2;
strcpy(cmd + ret, "\"");
if (g_at_chat_send(sd->chat, cmd, cgla_prefix, logical_access_cb,
cbd, g_free) > 0)
return;
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
}
static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
void *data)
{
@@ -1883,6 +1614,9 @@ static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
sd->chat = g_at_chat_clone(chat);
sd->vendor = vendor;
if (sd->vendor == OFONO_VENDOR_MBM)
g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
ofono_sim_set_data(sim, sd);
/* <fac>s supported by default */
@@ -1928,13 +1662,6 @@ static struct ofono_sim_driver driver = {
.lock = at_pin_enable,
.change_passwd = at_change_passwd,
.query_facility_lock = at_query_clck,
.list_apps = at_discover_apps,
.open_channel = at_open_channel,
.close_channel = at_close_channel,
.session_read_binary = at_session_read_binary,
.session_read_record = at_session_read_record,
.session_read_info = at_session_read_info,
.logical_access = at_logical_access
};
static struct ofono_sim_driver driver_noef = {

View File

@@ -125,7 +125,6 @@ static struct ofono_call *create_call(struct ofono_voicecall *vc, int type,
if (clip != 2) {
strncpy(call->phone_number.number, num,
OFONO_MAX_PHONE_NUMBER_LENGTH);
call->phone_number.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
call->phone_number.type = num_type;
}
@@ -405,45 +404,6 @@ static void hfp_dial(struct ofono_voicecall *vc,
CALLBACK_WITH_FAILURE(cb, data);
}
static void hfp_dial_last(struct ofono_voicecall *vc, 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);
cbd->user = vc;
if (g_at_chat_send(vd->chat, "AT+BLDN", none_prefix,
atd_cb, cbd, g_free) > 0)
return;
g_free(cbd);
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)
@@ -1308,8 +1268,6 @@ static struct ofono_voicecall_driver driver = {
.probe = hfp_voicecall_probe,
.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,

View File

@@ -1,107 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/devinfo.h>
#include "drivers/mbimmodem/mbimmodem.h"
struct devinfo_data {
struct l_idle *delayed_register;
};
static void mbim_query_revision(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ofono_modem *modem = ofono_devinfo_get_modem(info);
const char *revision = ofono_modem_get_string(modem, "FirmwareInfo");
if (revision)
CALLBACK_WITH_SUCCESS(cb, revision, data);
else
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void mbim_query_serial(struct ofono_devinfo *info,
ofono_devinfo_query_cb_t cb, void *data)
{
struct ofono_modem *modem = ofono_devinfo_get_modem(info);
const char *serial = ofono_modem_get_string(modem, "DeviceId");
if (serial)
CALLBACK_WITH_SUCCESS(cb, serial, data);
else
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void delayed_register(struct l_idle *idle, void *user_data)
{
struct ofono_devinfo *info = user_data;
struct devinfo_data *dd = ofono_devinfo_get_data(info);
l_idle_remove(idle);
dd->delayed_register = NULL;
ofono_devinfo_register(info);
}
static int mbim_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
void *data)
{
struct devinfo_data *dd = l_new(struct devinfo_data, 1);
dd->delayed_register = l_idle_create(delayed_register, info, NULL);
ofono_devinfo_set_data(info, dd);
return 0;
}
static void mbim_devinfo_remove(struct ofono_devinfo *info)
{
struct devinfo_data *dd = ofono_devinfo_get_data(info);
ofono_devinfo_set_data(info, NULL);
l_idle_remove(dd->delayed_register);
l_free(dd);
}
static struct ofono_devinfo_driver driver = {
.name = "mbim",
.probe = mbim_devinfo_probe,
.remove = mbim_devinfo_remove,
.query_revision = mbim_query_revision,
.query_serial = mbim_query_serial,
};
void mbim_devinfo_init(void)
{
ofono_devinfo_driver_register(&driver);
}
void mbim_devinfo_exit(void)
{
ofono_devinfo_driver_unregister(&driver);
}

View File

@@ -1,464 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. 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 <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/gprs-context.h>
#include "drivers/mbimmodem/mbim.h"
#include "drivers/mbimmodem/mbim-message.h"
#include "drivers/mbimmodem/mbimmodem.h"
enum state {
STATE_IDLE,
STATE_ENABLING,
STATE_DISABLING,
STATE_ACTIVE,
};
struct gprs_context_data {
struct mbim_device *device;
unsigned int active_context;
enum ofono_gprs_proto proto;
enum state state;
ofono_gprs_context_cb_t cb;
void *cb_data;
};
static uint32_t proto_to_context_ip_type(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IP:
return 1; /* MBIMContextIPTypeIPv4 */
case OFONO_GPRS_PROTO_IPV6:
return 2; /* MBIMContextIPTypeIPv6 */
case OFONO_GPRS_PROTO_IPV4V6:
return 3; /* MBIMContextIPTypeIPv4v6 */
}
return 0;
}
static uint32_t auth_method_to_auth_protocol(enum ofono_gprs_auth_method method)
{
switch (method) {
case OFONO_GPRS_AUTH_METHOD_CHAP:
return 2; /* MBIMAuthProtocolChap */
case OFONO_GPRS_AUTH_METHOD_PAP:
return 1; /* MBIMAuthProtocolPap */
}
return 0;
}
static void mbim_deactivate_cb(struct mbim_message *message, void *user)
{
struct ofono_gprs_context *gc = user;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
DBG("");
gcd->active_context = 0;
gcd->state = STATE_IDLE;
if (!gcd->cb)
return;
if (mbim_message_get_error(message) != 0)
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
else
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
}
static void mbim_gprs_deactivate_primary(struct ofono_gprs_context *gc,
unsigned int cid,
ofono_gprs_context_cb_t cb, void *data)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct mbim_message *message;
DBG("cid %u", cid);
gcd->state = STATE_DISABLING;
gcd->cb = cb;
gcd->cb_data = data;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_CONNECT,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "uusssuuu16y",
cid, 0, NULL, NULL, NULL, 0, 0, 0,
mbim_context_type_internet);
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
mbim_deactivate_cb, gc, NULL) > 0)
return;
mbim_message_unref(message);
if (cb)
CALLBACK_WITH_FAILURE(cb, data);
}
static void mbim_ip_configuration_cb(struct mbim_message *message, void *user)
{
struct ofono_gprs_context *gc = user;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct ofono_modem *modem = ofono_gprs_context_get_modem(gc);
const char *interface;
uint32_t session_id;
uint32_t ipv4_config_available;
uint32_t ipv6_config_available;
uint32_t n_ipv4_addr;
uint32_t ipv4_addr_offset;
uint32_t n_ipv6_addr;
uint32_t ipv6_addr_offset;
uint32_t ipv4_gw_offset;
uint32_t ipv6_gw_offset;
uint32_t n_ipv4_dns;
uint32_t ipv4_dns_offset;
uint32_t n_ipv6_dns;
uint32_t ipv6_dns_offset;
uint32_t ipv4_mtu;
uint32_t ipv6_mtu;
struct in6_addr ipv6;
struct in_addr ipv4;
char buf[INET6_ADDRSTRLEN];
DBG("%u", mbim_message_get_error(message));
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "uuuuuuuuuuuuuuu",
&session_id,
&ipv4_config_available, &ipv6_config_available,
&n_ipv4_addr, &ipv4_addr_offset,
&n_ipv6_addr, &ipv6_addr_offset,
&ipv4_gw_offset, &ipv6_gw_offset,
&n_ipv4_dns, &ipv4_dns_offset,
&n_ipv6_dns, &ipv6_dns_offset,
&ipv4_mtu, &ipv6_mtu))
goto error;
if (gcd->proto == OFONO_GPRS_PROTO_IPV6)
goto ipv6;
if (ipv4_config_available & 0x1) { /* Address Info present */
uint32_t prefix;
if (!mbim_message_get_ipv4_element(message, ipv4_addr_offset,
&prefix, &ipv4))
goto error;
inet_ntop(AF_INET, &ipv4, buf, sizeof(buf));
ofono_gprs_context_set_ipv4_address(gc, buf, TRUE);
ofono_gprs_context_set_ipv4_prefix_length(gc, prefix);
} else
ofono_gprs_context_set_ipv4_address(gc, NULL, FALSE);
if (ipv4_config_available & 0x2) { /* IPv4 Gateway info */
if (!mbim_message_get_ipv4_address(message,
ipv4_gw_offset, &ipv4))
goto error;
inet_ntop(AF_INET, &ipv4, buf, sizeof(buf));
ofono_gprs_context_set_ipv4_gateway(gc, buf);
}
if (ipv4_config_available & 0x3) { /* IPv4 DNS Info */
const char *dns[3];
char dns1[INET_ADDRSTRLEN];
char dns2[INET_ADDRSTRLEN];
memset(dns, 0, sizeof(dns));
if (n_ipv4_dns > 1) { /* Grab second DNS */
if (!mbim_message_get_ipv4_address(message,
ipv4_dns_offset + 4,
&ipv4))
goto error;
inet_ntop(AF_INET, &ipv4, dns2, sizeof(dns2));
dns[1] = dns2;
}
if (n_ipv4_dns > 0) { /* Grab first DNS */
if (!mbim_message_get_ipv4_address(message,
ipv4_dns_offset,
&ipv4))
goto error;
inet_ntop(AF_INET, &ipv4, dns1, sizeof(dns1));
dns[0] = dns1;
ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
}
}
if (gcd->proto == OFONO_GPRS_PROTO_IP)
goto done;
ipv6:
if (ipv6_config_available & 0x1) { /* Address Info present */
uint32_t prefix;
if (!mbim_message_get_ipv6_element(message, ipv6_addr_offset,
&prefix, &ipv6))
goto error;
inet_ntop(AF_INET6, &ipv6, buf, sizeof(buf));
ofono_gprs_context_set_ipv6_address(gc, buf);
ofono_gprs_context_set_ipv6_prefix_length(gc, prefix);
}
if (ipv6_config_available & 0x2) { /* IPv6 Gateway info */
if (!mbim_message_get_ipv6_address(message,
ipv6_gw_offset, &ipv6))
goto error;
inet_ntop(AF_INET6, &ipv6, buf, sizeof(buf));
ofono_gprs_context_set_ipv6_gateway(gc, buf);
}
if (ipv6_config_available & 0x3) { /* IPv6 DNS Info */
const char *dns[3];
char dns1[INET6_ADDRSTRLEN];
char dns2[INET6_ADDRSTRLEN];
memset(dns, 0, sizeof(dns));
if (n_ipv6_dns > 1) { /* Grab second DNS */
if (!mbim_message_get_ipv6_address(message,
ipv6_dns_offset + 16,
&ipv6))
goto error;
inet_ntop(AF_INET6, &ipv6, dns2, sizeof(dns2));
dns[1] = dns2;
}
if (n_ipv6_dns > 0) { /* Grab first DNS */
if (!mbim_message_get_ipv6_address(message,
ipv6_dns_offset,
&ipv6))
goto error;
inet_ntop(AF_INET6, &ipv6, dns1, sizeof(dns1));
dns[0] = dns1;
ofono_gprs_context_set_ipv6_dns_servers(gc, dns);
}
}
done:
gcd->state = STATE_ACTIVE;
interface = ofono_modem_get_string(modem, "NetworkInterface");
ofono_gprs_context_set_interface(gc, interface);
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
gcd->cb = NULL;
gcd->cb_data = NULL;
return;
error:
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
gcd->state = STATE_IDLE;
gcd->cb = NULL;
gcd->cb_data = NULL;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_CONNECT,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "uusssuuu16y",
gcd->active_context, 0,
NULL, NULL, NULL, 0, 0, 0,
mbim_context_type_internet);
if (!mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
NULL, NULL, NULL))
mbim_message_unref(message);
}
static void mbim_activate_cb(struct mbim_message *message, void *user)
{
struct ofono_gprs_context *gc = user;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_IP_CONFIGURATION,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "uuuuuuuuuuuuuuu",
gcd->active_context,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
mbim_ip_configuration_cb, gc, NULL) > 0)
return;
error:
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
gcd->state = STATE_IDLE;
gcd->cb = NULL;
gcd->cb_data = NULL;
}
static void mbim_gprs_activate_primary(struct ofono_gprs_context *gc,
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_context_cb_t cb, void *data)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
struct mbim_message *message;
DBG("cid %u", ctx->cid);
gcd->state = STATE_ENABLING;
gcd->cb = cb;
gcd->cb_data = data;
gcd->active_context = ctx->cid;
gcd->proto = ctx->proto;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_CONNECT,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "uusssuuu16y",
ctx->cid,
1, /* MBIMActivationCommandActivate */
ctx->apn,
ctx->username[0] ? ctx->username : NULL,
ctx->password[0] ? ctx->password : NULL,
0, /*MBIMCompressionNone */
auth_method_to_auth_protocol(ctx->auth_method),
proto_to_context_ip_type(ctx->proto),
mbim_context_type_internet);
if (mbim_device_send(gcd->device, GPRS_CONTEXT_GROUP, message,
mbim_activate_cb, gc, NULL) > 0)
return;
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, data);
}
static void mbim_gprs_detach_shutdown(struct ofono_gprs_context *gc,
unsigned int cid)
{
DBG("");
mbim_gprs_deactivate_primary(gc, cid, NULL, NULL);
}
static void mbim_connect_notify(struct mbim_message *message, void *user)
{
uint32_t session_id;
uint32_t activation_state;
uint32_t voice_call_state;
uint32_t ip_type;
uint8_t context_type[16];
uint32_t nw_error;
char uuidstr[37];
DBG("");
if (!mbim_message_get_arguments(message, "uuuu16yu",
&session_id, &activation_state,
&voice_call_state, &ip_type,
context_type, &nw_error))
return;
DBG("session_id: %u, activation_state: %u, ip_type: %u",
session_id, activation_state, ip_type);
l_uuid_to_string(context_type, uuidstr, sizeof(uuidstr));
DBG("context_type: %s, nw_error: %u", uuidstr, nw_error);
}
static int mbim_gprs_context_probe(struct ofono_gprs_context *gc,
unsigned int vendor, void *data)
{
struct mbim_device *device = data;
struct gprs_context_data *gcd;
DBG("");
if (!mbim_device_register(device, GPRS_CONTEXT_GROUP,
mbim_uuid_basic_connect,
MBIM_CID_CONNECT,
mbim_connect_notify, gc, NULL))
return -EIO;
gcd = l_new(struct gprs_context_data, 1);
gcd->device = mbim_device_ref(device);
ofono_gprs_context_set_data(gc, gcd);
return 0;
}
static void mbim_gprs_context_remove(struct ofono_gprs_context *gc)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
DBG("");
ofono_gprs_context_set_data(gc, NULL);
mbim_device_cancel_group(gcd->device, GPRS_CONTEXT_GROUP);
mbim_device_unregister_group(gcd->device, GPRS_CONTEXT_GROUP);
mbim_device_unref(gcd->device);
gcd->device = NULL;
l_free(gcd);
}
static struct ofono_gprs_context_driver driver = {
.name = "mbim",
.probe = mbim_gprs_context_probe,
.remove = mbim_gprs_context_remove,
.activate_primary = mbim_gprs_activate_primary,
.deactivate_primary = mbim_gprs_deactivate_primary,
.detach_shutdown = mbim_gprs_detach_shutdown
};
void mbim_gprs_context_init(void)
{
ofono_gprs_context_driver_register(&driver);
}
void mbim_gprs_context_exit(void)
{
ofono_gprs_context_driver_unregister(&driver);
}

View File

@@ -1,299 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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 <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/gprs.h>
#include "common.h"
#include "drivers/mbimmodem/mbim.h"
#include "drivers/mbimmodem/mbim-message.h"
#include "drivers/mbimmodem/mbimmodem.h"
struct gprs_data {
struct mbim_device *device;
struct l_idle *delayed_register;
};
static void mbim_packet_service_set_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_gprs_cb_t cb = cbd->cb;
DBG("");
if (mbim_message_get_error(message) != 0)
CALLBACK_WITH_FAILURE(cb, cbd->data);
else
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void mbim_gprs_set_attached(struct ofono_gprs *gprs, int attached,
ofono_gprs_cb_t cb, void *data)
{
struct gprs_data *gd = ofono_gprs_get_data(gprs);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
DBG("");
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PACKET_SERVICE,
MBIM_COMMAND_TYPE_SET);
/*
* MBIMPacketServiceActionAttach (0) or
* MBIMPacketServiceActionDetach (1)
*/
mbim_message_set_arguments(message, "u", attached ? 0 : 1);
if (mbim_device_send(gd->device, GPRS_GROUP, message,
mbim_packet_service_set_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, data);
}
static void mbim_packet_service_query_cb(struct mbim_message *message,
void *user)
{
struct cb_data *cbd = user;
ofono_gprs_status_cb_t cb = cbd->cb;
uint32_t dummy;
uint32_t state;
DBG("%u", mbim_message_get_error(message));
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "uu", &dummy, &state))
goto error;
if (state == 2)
CALLBACK_WITH_SUCCESS(cb,
NETWORK_REGISTRATION_STATUS_REGISTERED,
cbd->data);
else
CALLBACK_WITH_SUCCESS(cb, NETWORK_REGISTRATION_STATUS_UNKNOWN,
cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void mbim_gprs_registration_status(struct ofono_gprs *gprs,
ofono_gprs_status_cb_t cb,
void *data)
{
struct gprs_data *gd = ofono_gprs_get_data(gprs);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
DBG("");
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PACKET_SERVICE,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(gd->device, GPRS_GROUP, message,
mbim_packet_service_query_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void mbim_packet_service_changed(struct mbim_message *message,
void *user)
{
struct ofono_gprs *gprs = user;
uint32_t nw_error;
uint32_t packet_service_state;
uint32_t highest_avail_data_class;
uint64_t uplink_speed;
uint64_t downlink_speed;
DBG("");
if (!mbim_message_get_arguments(message, "uuutt",
&nw_error,
&packet_service_state,
&highest_avail_data_class,
&uplink_speed,
&downlink_speed))
return;
DBG("uplink: %"PRIu64", downlink: %"PRIu64,
uplink_speed, downlink_speed);
DBG("nw_error: %u", nw_error);
if (packet_service_state == 2) {
uint32_t bearer =
mbim_data_class_to_tech(highest_avail_data_class);
ofono_gprs_status_notify(gprs,
NETWORK_REGISTRATION_STATUS_REGISTERED);
ofono_gprs_bearer_notify(gprs, bearer);
} else
ofono_gprs_status_notify(gprs,
NETWORK_REGISTRATION_STATUS_UNKNOWN);
}
static void provisioned_contexts_query_cb(struct mbim_message *message,
void *user)
{
struct mbim_message_iter contexts;
uint32_t n_contexts;
uint32_t id;
uint8_t type[16];
char *apn;
char *username;
char *password;
uint32_t compression;
uint32_t auth_protocol;
DBG("");
if (mbim_message_get_error(message) != 0)
return;
if (!mbim_message_get_arguments(message, "a(u16ysssuu)",
&n_contexts, &contexts))
return;
DBG("n_contexts: %u", n_contexts);
while (mbim_message_iter_next_entry(&contexts, &id, type, &apn,
&username, &password,
&compression, &auth_protocol)) {
char uuidstr[37];
l_uuid_to_string(type, uuidstr, sizeof(uuidstr));
DBG("id: %u, type: %s", id, uuidstr);
DBG("apn: %s, username: %s, password: %s",
apn, username, password);
DBG("compression: %u, auth_protocol: %u",
compression, auth_protocol);
l_free(apn);
l_free(username);
l_free(password);
}
}
static void delayed_register(struct l_idle *idle, void *user_data)
{
struct ofono_gprs *gprs = user_data;
struct gprs_data *gd = ofono_gprs_get_data(gprs);
struct mbim_message *message;
DBG("");
l_idle_remove(idle);
gd->delayed_register = NULL;
/* Query provisioned contexts for debugging purposes only */
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PROVISIONED_CONTEXTS,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
mbim_device_send(gd->device, 0, message,
provisioned_contexts_query_cb, gprs, NULL);
if (!mbim_device_register(gd->device, GPRS_GROUP,
mbim_uuid_basic_connect,
MBIM_CID_PACKET_SERVICE,
mbim_packet_service_changed,
gprs, NULL))
goto error;
ofono_gprs_register(gprs);
return;
error:
ofono_gprs_remove(gprs);
}
static int mbim_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor,
void *data)
{
struct mbim_device *device = data;
struct gprs_data *gd;
DBG("");
gd = l_new(struct gprs_data, 1);
gd->device = mbim_device_ref(device);
gd->delayed_register = l_idle_create(delayed_register, gprs, NULL);
ofono_gprs_set_data(gprs, gd);
return 0;
}
static void mbim_gprs_remove(struct ofono_gprs *gprs)
{
struct gprs_data *gd = ofono_gprs_get_data(gprs);
DBG("");
ofono_gprs_set_data(gprs, NULL);
l_idle_remove(gd->delayed_register);
mbim_device_cancel_group(gd->device, GPRS_GROUP);
mbim_device_unregister_group(gd->device, GPRS_GROUP);
mbim_device_unref(gd->device);
gd->device = NULL;
l_free(gd);
}
static struct ofono_gprs_driver driver = {
.name = "mbim",
.probe = mbim_gprs_probe,
.remove = mbim_gprs_remove,
.set_attached = mbim_gprs_set_attached,
.attached_status = mbim_gprs_registration_status,
};
void mbim_gprs_init(void)
{
ofono_gprs_driver_register(&driver);
}
void mbim_gprs_exit(void)
{
ofono_gprs_driver_unregister(&driver);
}

View File

@@ -1,80 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "mbim-desc.h"
/*
* Attempts to find MBIM specific descriptors.
*
* Returns true if the MBIM Function descriptor was found, false otherwise.
*/
bool mbim_find_descriptors(const uint8_t *data, size_t data_len,
const struct mbim_desc **out_desc,
const struct mbim_extended_desc **out_ext_desc)
{
bool r = false;
while (data_len > 3) {
uint8_t len = data[0];
if (data[1] != 0x24)
goto next;
/* MBIM v1.0, Table 4-3 */
switch (data[2]) {
case 0x1b:
if (!out_desc)
break;
if (len != sizeof(struct mbim_desc) || data_len < len)
break;
*out_desc = (const struct mbim_desc *) data;
r = true;
break;
case 0x1c:
if (!out_ext_desc)
break;
if (len != sizeof(struct mbim_extended_desc) ||
data_len < len)
break;
*out_ext_desc =
(const struct mbim_extended_desc *) data;
break;
}
next:
data_len -= len;
data += len;
}
return r;
}

View File

@@ -1,49 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#include <linux/types.h>
/* MBIM v1.0, Section 6.4: MBIM Functional Descriptor */
struct mbim_desc {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
__le16 bcdMBIMVersion;
__le16 wMaxControlMessage;
uint8_t bNumberFilters;
uint8_t bMaxFilterSize;
__le16 wMaxSegmentSize;
uint8_t bmNetworkCapabilities;
} __attribute__ ((packed));
/* MBIM v1.0, Section 6.5: MBIM Extended Functional Descriptor */
struct mbim_extended_desc {
uint8_t bFunctionLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
__le16 bcdMBIMExtendedVersion;
uint8_t bMaxOutstandingCommandMessages;
__le16 wMTU;
} __attribute__ ((packed));
bool mbim_find_descriptors(const uint8_t *data, size_t data_len,
const struct mbim_desc **out_desc,
const struct mbim_extended_desc **out_ext_desc);

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
struct mbim_message;
struct mbim_message_iter;
enum mbim_command_type {
MBIM_COMMAND_TYPE_QUERY = 0,
MBIM_COMMAND_TYPE_SET = 1,
};
struct mbim_message_iter {
const char *sig_start;
uint8_t sig_len;
uint8_t sig_pos;
const struct iovec *iov;
uint32_t n_iov;
uint32_t cur_iov;
size_t cur_iov_offset;
size_t len;
size_t pos;
size_t base_offset;
uint32_t n_elem;
char container_type;
};
struct mbim_message *mbim_message_new(const uint8_t *uuid, uint32_t cid,
enum mbim_command_type type);
struct mbim_message *mbim_message_ref(struct mbim_message *msg);
void mbim_message_unref(struct mbim_message *msg);
uint32_t mbim_message_get_error(struct mbim_message *message);
uint32_t mbim_message_get_cid(struct mbim_message *message);
const uint8_t *mbim_message_get_uuid(struct mbim_message *message);
bool mbim_message_get_arguments(struct mbim_message *message,
const char *signature, ...);
bool mbim_message_get_ipv4_address(struct mbim_message *message,
uint32_t offset,
struct in_addr *addr);
bool mbim_message_get_ipv4_element(struct mbim_message *message,
uint32_t offset,
uint32_t *prefix_len,
struct in_addr *addr);
bool mbim_message_get_ipv6_address(struct mbim_message *essage,
uint32_t offset,
struct in6_addr *addr);
bool mbim_message_get_ipv6_element(struct mbim_message *message,
uint32_t offset,
uint32_t *prefix_len,
struct in6_addr *addr);
bool mbim_message_iter_next_entry(struct mbim_message_iter *iter, ...);
struct mbim_message_builder *mbim_message_builder_new(struct mbim_message *msg);
void mbim_message_builder_free(struct mbim_message_builder *builder);
bool mbim_message_builder_append_basic(struct mbim_message_builder *builder,
char type, const void *value);
bool mbim_message_builder_append_bytes(struct mbim_message_builder *builder,
size_t len, const uint8_t *bytes);
bool mbim_message_builder_enter_struct(struct mbim_message_builder *builder,
const char *signature);
bool mbim_message_builder_leave_struct(struct mbim_message_builder *builder);
bool mbim_message_builder_enter_array(struct mbim_message_builder *builder,
const char *signature);
bool mbim_message_builder_leave_array(struct mbim_message_builder *builder);
bool mbim_message_builder_enter_databuf(struct mbim_message_builder *builder,
const char *signature);
bool mbim_message_builder_leave_databuf(struct mbim_message_builder *builder);
struct mbim_message *mbim_message_builder_finalize(
struct mbim_message_builder *builder);
bool mbim_message_set_arguments(struct mbim_message *message,
const char *signature, ...);

View File

@@ -1,59 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#define align_len(len, boundary) (((len)+(boundary)-1) & ~((boundary)-1))
enum mbim_control_message {
MBIM_OPEN_MSG = 0x1,
MBIM_CLOSE_MSG = 0x2,
MBIM_COMMAND_MSG = 0x3,
MBIM_HOST_ERROR_MSG = 0x4,
MBIM_OPEN_DONE = 0x80000001,
MBIM_CLOSE_DONE = 0x80000002,
MBIM_COMMAND_DONE = 0x80000003,
MBIM_FUNCTION_ERROR_MSG = 0x80000004,
MBIM_INDICATE_STATUS_MSG = 0x80000007,
};
/* MBIM v1.0, Section 9.1 */
struct mbim_message_header {
__le32 type;
__le32 len;
__le32 tid;
} __attribute__ ((packed));
/* MBIM v1.0, Section 9.1 */
struct mbim_fragment_header {
__le32 num_frags;
__le32 cur_frag;
} __attribute__ ((packed));
struct mbim_message *_mbim_message_build(const void *header,
struct iovec *frags,
uint32_t n_frags);
struct mbim_message *_mbim_message_new_command_done(const uint8_t *uuid,
uint32_t cid, uint32_t status);
uint32_t _mbim_information_buffer_offset(uint32_t type);
void _mbim_message_set_tid(struct mbim_message *message, uint32_t tid);
void *_mbim_message_to_bytearray(struct mbim_message *message, size_t *out_len);
void *_mbim_message_get_header(struct mbim_message *message, size_t *out_len);
struct iovec *_mbim_message_get_body(struct mbim_message *message,
size_t *out_n_iov, size_t *out_len);

File diff suppressed because it is too large Load Diff

View File

@@ -1,149 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
struct mbim_device;
struct mbim_message;
#define MBIM_CID_DEVICE_CAPS 1
#define MBIM_CID_SUBSCRIBER_READY_STATUS 2
#define MBIM_CID_RADIO_STATE 3
#define MBIM_CID_PIN 4
#define MBIM_CID_PIN_LIST 5
#define MBIM_CID_HOME_PROVIDER 6
#define MBIM_CID_PREFERRED_PROVIDERS 7
#define MBIM_CID_VISIBLE_PROVIDERS 8
#define MBIM_CID_REGISTER_STATE 9
#define MBIM_CID_PACKET_SERVICE 10
#define MBIM_CID_SIGNAL_STATE 11
#define MBIM_CID_CONNECT 12
#define MBIM_CID_PROVISIONED_CONTEXTS 13
#define MBIM_CID_SERVICE_ACTIVATION 14
#define MBIM_CID_IP_CONFIGURATION 15
#define MBIM_CID_DEVICE_SERVICES 16
#define MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST 19
#define MBIM_CID_PACKET_STATISTICS 20
#define MBIM_CID_NETWORK_IDLE_HINT 21
#define MBIM_CID_EMERGENCY_MODE 22
#define MBIM_CID_IP_PACKET_FILTERS 23
#define MBIM_CID_MULTICARRIER_PROVIDERS 24
#define MBIM_CID_SMS_CONFIGURATION 1
#define MBIM_CID_SMS_READ 2
#define MBIM_CID_SMS_SEND 3
#define MBIM_CID_SMS_DELETE 4
#define MBIM_CID_SMS_MESSAGE_STORE_STATUS 5
#define MBIM_CID_USSD 1
#define MBIM_CID_PHONEBOOK_CONFIGURATION 1
#define MBIM_CID_PHONEBOOK_READ 2
#define MBIM_CID_PHONEBOOK_DELETE 3
#define MBIM_CID_PHONEBOOK_WRITE 4
#define MBIM_CID_STK_PAC 1
#define MBIM_CID_STK_TERMINAL_RESPONSE 2
#define MBIM_CID_STK_ENVELOPE 3
#define MBIM_CID_AKA_AUTH 1
#define MBIM_CID_AKAP_AUTH 2
#define MBIM_CID_SIM_AUTH 3
#define MBIM_CID_DSS_CONNECT 1
/* Table 10-11 */
enum mbim_data_class {
MBIM_DATA_CLASS_NONE = 0x00,
MBIM_DATA_CLASS_GPRS = 0x01,
MBIM_DATA_CLASS_EDGE = 0x02,
MBIM_DATA_CLASS_UMTS = 0x04,
MBIM_DATA_CLASS_HSDPA = 0x08,
MBIM_DATA_CLASS_HSUPA = 0x10,
MBIM_DATA_CLASS_LTE = 0x20,
MBIM_DATA_CLASS_1XRTT = 0x10000,
MBIM_DATA_CLASS_EVDO = 0x20000,
MBIM_DATA_CLASS_EVDO_REVA = 0x40000,
MBIM_DATA_CLASS_1XEVDV = 0x80000,
MBIM_DATA_CLASS_3XRTT = 0x100000,
MBIM_DATA_CLASS_1XEVDO_REVB = 0x200000,
MBIM_DATA_CLASS_UMB = 0x400000,
MBIM_DATA_CLASS_CUSTOM = 0x80000000,
};
typedef void (*mbim_device_debug_func_t) (const char *str, void *user_data);
typedef void (*mbim_device_disconnect_func_t) (void *user_data);
typedef void (*mbim_device_destroy_func_t) (void *user_data);
typedef void (*mbim_device_ready_func_t) (void *user_data);
typedef void (*mbim_device_reply_func_t) (struct mbim_message *message,
void *user_data);
extern const uint8_t mbim_uuid_basic_connect[];
extern const uint8_t mbim_uuid_sms[];
extern const uint8_t mbim_uuid_ussd[];
extern const uint8_t mbim_uuid_phonebook[];
extern const uint8_t mbim_uuid_stk[];
extern const uint8_t mbim_uuid_auth[];
extern const uint8_t mbim_uuid_dss[];
extern const uint8_t mbim_context_type_none[];
extern const uint8_t mbim_context_type_internet[];
extern const uint8_t mbim_context_type_vpn[];
extern const uint8_t mbim_context_type_voice[];
extern const uint8_t mbim_context_type_video_share[];
extern const uint8_t mbim_context_type_purchase[];
extern const uint8_t mbim_context_type_ims[];
extern const uint8_t mbim_context_type_mms[];
extern const uint8_t mbim_context_type_local[];
struct mbim_device *mbim_device_new(int fd, uint32_t max_segment_size);
bool mbim_device_set_close_on_unref(struct mbim_device *device, bool do_close);
struct mbim_device *mbim_device_ref(struct mbim_device *device);
void mbim_device_unref(struct mbim_device *device);
bool mbim_device_shutdown(struct mbim_device *device);
bool mbim_device_set_max_outstanding(struct mbim_device *device, uint32_t max);
bool mbim_device_set_debug(struct mbim_device *device,
mbim_device_debug_func_t func, void *user_data,
mbim_device_destroy_func_t destroy);
bool mbim_device_set_disconnect_handler(struct mbim_device *device,
mbim_device_disconnect_func_t function,
void *user_data,
mbim_device_destroy_func_t destroy);
bool mbim_device_set_ready_handler(struct mbim_device *device,
mbim_device_ready_func_t function,
void *user_data,
mbim_device_destroy_func_t destroy);
uint32_t mbim_device_send(struct mbim_device *device, uint32_t gid,
struct mbim_message *message,
mbim_device_reply_func_t function,
void *user_data,
mbim_device_destroy_func_t destroy);
bool mbim_device_cancel(struct mbim_device *device, uint32_t tid);
bool mbim_device_cancel_group(struct mbim_device *device, uint32_t gid);
uint32_t mbim_device_register(struct mbim_device *device, uint32_t gid,
const uint8_t *uuid, uint32_t cid,
mbim_device_reply_func_t notify,
void *user_data,
mbim_device_destroy_func_t destroy);
bool mbim_device_unregister(struct mbim_device *device, uint32_t id);
bool mbim_device_unregister_group(struct mbim_device *device, uint32_t gid);

View File

@@ -1,53 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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 OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include "mbimmodem.h"
static int mbimmodem_init(void)
{
mbim_devinfo_init();
mbim_sim_init();
mbim_netreg_init();
mbim_sms_exit();
mbim_gprs_init();
mbim_gprs_context_init();
return 0;
}
static void mbimmodem_exit(void)
{
mbim_gprs_context_exit();
mbim_gprs_exit();
mbim_sms_exit();
mbim_netreg_exit();
mbim_sim_exit();
mbim_devinfo_exit();
}
OFONO_PLUGIN_DEFINE(mbimmodem, "MBIM modem driver", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, mbimmodem_init, mbimmodem_exit)

View File

@@ -1,48 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#include "util.h"
enum MBIM_GROUP {
SIM_GROUP = 1,
NETREG_GROUP = 2,
SMS_GROUP = 3,
GPRS_GROUP = 4,
GPRS_CONTEXT_GROUP = 101,
};
extern void mbim_devinfo_init(void);
extern void mbim_devinfo_exit(void);
extern void mbim_sim_init(void);
extern void mbim_sim_exit(void);
extern void mbim_netreg_init(void);
extern void mbim_netreg_exit(void);
extern void mbim_sms_init(void);
extern void mbim_sms_exit(void);
extern void mbim_gprs_init(void);
extern void mbim_gprs_exit(void);
extern void mbim_gprs_context_init(void);
extern void mbim_gprs_context_exit(void);

View File

@@ -1,416 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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 <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/netreg.h>
#include "src/common.h"
#include "drivers/mbimmodem/mbim.h"
#include "drivers/mbimmodem/mbim-message.h"
#include "drivers/mbimmodem/mbimmodem.h"
struct netreg_data {
struct mbim_device *device;
struct l_idle *delayed_register;
};
static inline int register_state_to_status(uint32_t register_state)
{
switch (register_state) {
case 0: /* MBIMRegisterStateUnknown */
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
case 1: /* MBIMRegisterStateDeregistered */
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
case 2: /* MBIMRegisterStateSearching */
return NETWORK_REGISTRATION_STATUS_SEARCHING;
case 3: /* MBIMRegisterStateHome */
return NETWORK_REGISTRATION_STATUS_REGISTERED;
case 4: /* MBIMRegisterStateRoaming */
case 5: /* MBIMRegisterStatePartner */
return NETWORK_REGISTRATION_STATUS_ROAMING;
case 6: /* MBIMRegisterStateDenied */
return NETWORK_REGISTRATION_STATUS_DENIED;
}
return NETWORK_REGISTRATION_STATUS_UNKNOWN;
}
static void mbim_register_state_changed(struct mbim_message *message,
void *user)
{
struct ofono_netreg *netreg = user;
uint32_t nw_error;
uint32_t register_state;
uint32_t register_mode;
uint32_t available_data_classes;
int status;
int tech;
DBG("");
if (!mbim_message_get_arguments(message, "uuuu",
&nw_error, &register_state,
&register_mode,
&available_data_classes))
return;
DBG("NwError: %u, RegisterMode: %u", nw_error, register_mode);
status = register_state_to_status(register_state);
tech = mbim_data_class_to_tech(available_data_classes);
ofono_netreg_status_notify(netreg, status, -1, -1, tech);
}
static void mbim_registration_status_cb(struct mbim_message *message,
void *user)
{
struct cb_data *cbd = user;
ofono_netreg_status_cb_t cb = cbd->cb;
uint32_t dummy;
uint32_t register_state;
uint32_t available_data_classes;
int status;
int tech;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "uuuu",
&dummy, &register_state,
&dummy,
&available_data_classes))
goto error;
status = register_state_to_status(register_state);
tech = mbim_data_class_to_tech(available_data_classes);
CALLBACK_WITH_SUCCESS(cb, status, -1, -1, tech, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
}
static void mbim_registration_status(struct ofono_netreg *netreg,
ofono_netreg_status_cb_t cb,
void *data)
{
struct netreg_data *nd = ofono_netreg_get_data(netreg);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_REGISTER_STATE,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(nd->device, NETREG_GROUP, message,
mbim_registration_status_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
}
static void mbim_current_operator_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_netreg_operator_cb_t cb = cbd->cb;
struct ofono_network_operator op;
uint32_t dummy;
uint32_t register_state;
uint32_t available_data_classes;
L_AUTO_FREE_VAR(char *, provider_id) = NULL;
L_AUTO_FREE_VAR(char *, provider_name) = NULL;
L_AUTO_FREE_VAR(char *, roaming_text) = NULL;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "uuuuusss",
&dummy, &register_state, &dummy,
&available_data_classes, &dummy,
&provider_id, &provider_name,
&roaming_text))
goto error;
if (register_state < 3 || register_state > 5)
goto error;
DBG("provider: %s(%s)", provider_name, provider_id);
/* If MBIMRegisterStateRoaming or MBIMRegisterStatePartner */
if (register_state == 4 || register_state == 5)
DBG("roaming text: %s", roaming_text);
strncpy(op.name, provider_name, OFONO_MAX_OPERATOR_NAME_LENGTH);
op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
strncpy(op.mcc, provider_id, OFONO_MAX_MCC_LENGTH);
op.mcc[OFONO_MAX_MCC_LENGTH] = '\0';
strncpy(op.mnc, provider_id + OFONO_MAX_MCC_LENGTH,
OFONO_MAX_MNC_LENGTH);
op.mnc[OFONO_MAX_MNC_LENGTH] = '\0';
/* Set to current */
op.status = 2;
op.tech = mbim_data_class_to_tech(available_data_classes);
CALLBACK_WITH_SUCCESS(cb, &op, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void mbim_current_operator(struct ofono_netreg *netreg,
ofono_netreg_operator_cb_t cb, void *data)
{
struct netreg_data *nd = ofono_netreg_get_data(netreg);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_REGISTER_STATE,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(nd->device, NETREG_GROUP, message,
mbim_current_operator_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void mbim_register_state_set_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_netreg_register_cb_t cb = cbd->cb;
DBG("");
if (mbim_message_get_error(message) != 0)
CALLBACK_WITH_FAILURE(cb, cbd->data);
else
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void mbim_register_auto(struct ofono_netreg *netreg,
ofono_netreg_register_cb_t cb, void *data)
{
static const uint32_t data_class = MBIM_DATA_CLASS_GPRS |
MBIM_DATA_CLASS_EDGE |
MBIM_DATA_CLASS_UMTS |
MBIM_DATA_CLASS_HSDPA |
MBIM_DATA_CLASS_HSUPA |
MBIM_DATA_CLASS_LTE;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_REGISTER_STATE,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "suu", NULL, 0, data_class);
if (mbim_device_send(nd->device, NETREG_GROUP, message,
mbim_register_state_set_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, data);
}
static inline int convert_signal_strength(uint32_t strength)
{
if (strength == 99)
return -1;
return strength * 100 / 31;
}
static void mbim_signal_state_query_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_netreg_strength_cb_t cb = cbd->cb;
uint32_t strength;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "u", &strength))
goto error;
CALLBACK_WITH_SUCCESS(cb, convert_signal_strength(strength), cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void mbim_signal_strength(struct ofono_netreg *netreg,
ofono_netreg_strength_cb_t cb, void *data)
{
struct netreg_data *nd = ofono_netreg_get_data(netreg);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_SIGNAL_STATE,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(nd->device, NETREG_GROUP, message,
mbim_signal_state_query_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void mbim_signal_state_changed(struct mbim_message *message, void *user)
{
struct ofono_netreg *netreg = user;
uint32_t strength;
uint32_t error_rate;
uint32_t signal_strength_interval;
uint32_t rssi_threshold;
DBG("");
if (!mbim_message_get_arguments(message, "uuuu",
&strength, &error_rate,
&signal_strength_interval,
&rssi_threshold))
return;
DBG("strength: %u, error_rate: %u", strength, error_rate);
DBG("strength interval: %u, rssi_threshold: %u",
signal_strength_interval, rssi_threshold);
ofono_netreg_strength_notify(netreg, convert_signal_strength(strength));
}
static void delayed_register(struct l_idle *idle, void *user_data)
{
struct ofono_netreg *netreg = user_data;
struct netreg_data *nd = ofono_netreg_get_data(netreg);
DBG("");
l_idle_remove(idle);
nd->delayed_register = NULL;
if (!mbim_device_register(nd->device, NETREG_GROUP,
mbim_uuid_basic_connect,
MBIM_CID_SIGNAL_STATE,
mbim_signal_state_changed,
netreg, NULL))
goto error;
if (!mbim_device_register(nd->device, NETREG_GROUP,
mbim_uuid_basic_connect,
MBIM_CID_REGISTER_STATE,
mbim_register_state_changed,
netreg, NULL))
goto error;
ofono_netreg_register(netreg);
return;
error:
ofono_netreg_remove(netreg);
}
static int mbim_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
void *data)
{
struct mbim_device *device = data;
struct netreg_data *nd = l_new(struct netreg_data, 1);
DBG("");
nd->device = mbim_device_ref(device);
nd->delayed_register = l_idle_create(delayed_register, netreg, NULL);
ofono_netreg_set_data(netreg, nd);
return 0;
}
static void mbim_netreg_remove(struct ofono_netreg *netreg)
{
struct netreg_data *nd = ofono_netreg_get_data(netreg);
DBG("");
ofono_netreg_set_data(netreg, NULL);
l_idle_remove(nd->delayed_register);
mbim_device_cancel_group(nd->device, NETREG_GROUP);
mbim_device_unregister_group(nd->device, NETREG_GROUP);
mbim_device_unref(nd->device);
nd->device = NULL;
l_free(nd);
}
static struct ofono_netreg_driver driver = {
.name = "mbim",
.probe = mbim_netreg_probe,
.remove = mbim_netreg_remove,
.registration_status = mbim_registration_status,
.current_operator = mbim_current_operator,
.register_auto = mbim_register_auto,
.strength = mbim_signal_strength,
};
void mbim_netreg_init(void)
{
ofono_netreg_driver_register(&driver);
}
void mbim_netreg_exit(void)
{
ofono_netreg_driver_unregister(&driver);
}

View File

@@ -1,533 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/sim.h>
#include "drivers/mbimmodem/mbim.h"
#include "drivers/mbimmodem/mbim-message.h"
#include "drivers/mbimmodem/mbimmodem.h"
struct sim_data {
struct mbim_device *device;
char *iccid;
char *imsi;
uint32_t last_pin_type;
bool present : 1;
};
static void mbim_sim_state_changed(struct ofono_sim *sim, uint32_t ready_state)
{
struct sim_data *sd = ofono_sim_get_data(sim);
DBG("ready_state: %u", ready_state);
switch (ready_state) {
case 0: /* Not Initialized */
break;
case 1: /* Initialized */
if (!sd->present)
ofono_sim_inserted_notify(sim, true);
sd->present = true;
ofono_sim_initialized_notify(sim);
break;
case 6: /* Device Locked */
if (!sd->present)
ofono_sim_inserted_notify(sim, true);
sd->present = true;
break;
case 2: /* Not inserted */
case 3: /* Bad SIM */
case 4: /* Failure */
case 5: /* Not activated */
if (sd->present)
ofono_sim_inserted_notify(sim, false);
sd->present = false;
break;
default:
break;
};
}
static void mbim_read_imsi(struct ofono_sim *sim,
ofono_sim_imsi_cb_t cb, void *user_data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
DBG("");
CALLBACK_WITH_SUCCESS(cb, sd->imsi, user_data);
}
static enum ofono_sim_password_type mbim_pin_type_to_sim_password(
uint32_t pin_type)
{
switch (pin_type) {
case 0: /* No Pin */
return OFONO_SIM_PASSWORD_NONE;
case 2: /* PIN1 key */
return OFONO_SIM_PASSWORD_SIM_PIN;
case 3: /* PIN2 key */
return OFONO_SIM_PASSWORD_SIM_PIN2;
case 4: /* device to SIM key */
return OFONO_SIM_PASSWORD_PHSIM_PIN;
case 5: /* device to very first SIM key */
return OFONO_SIM_PASSWORD_PHFSIM_PIN;
case 6: /* network personalization key */
return OFONO_SIM_PASSWORD_PHNET_PIN;
case 7: /* network subset personalization key */
return OFONO_SIM_PASSWORD_PHNETSUB_PIN;
case 8: /* service provider (SP) personalization key */
return OFONO_SIM_PASSWORD_PHSP_PIN;
case 9: /* corporate personalization key */
return OFONO_SIM_PASSWORD_PHCORP_PIN;
case 11: /* PUK1 */
return OFONO_SIM_PASSWORD_SIM_PUK;
case 12: /* PUK2 */
return OFONO_SIM_PASSWORD_SIM_PUK2;
case 13: /* device to very first SIM PIN unlock key */
return OFONO_SIM_PASSWORD_PHFSIM_PUK;
case 14: /* network personalization unlock key */
return OFONO_SIM_PASSWORD_PHNET_PUK;
case 15: /* network subset personaliation unlock key */
return OFONO_SIM_PASSWORD_PHNETSUB_PUK;
case 16: /* service provider (SP) personalization unlock key */
return OFONO_SIM_PASSWORD_PHSP_PUK;
case 17: /* corporate personalization unlock key */
return OFONO_SIM_PASSWORD_PHCORP_PUK;
}
return OFONO_SIM_PASSWORD_INVALID;
}
static uint32_t mbim_pin_type_from_sim_password(
enum ofono_sim_password_type type)
{
switch (type) {
case OFONO_SIM_PASSWORD_SIM_PIN:
return 2; /* PIN1 key */
case OFONO_SIM_PASSWORD_SIM_PIN2:
return 3; /* PIN2 key */
case OFONO_SIM_PASSWORD_PHSIM_PIN:
return 4; /* device to SIM key */
case OFONO_SIM_PASSWORD_PHFSIM_PIN:
return 5; /* device to very first SIM key */
case OFONO_SIM_PASSWORD_PHNET_PIN:
return 6; /* network personalization key */
case OFONO_SIM_PASSWORD_PHNETSUB_PIN:
return 7; /* network subset personalization key */
case OFONO_SIM_PASSWORD_PHSP_PIN:
return 8; /* service provider (SP) personalization key */
case OFONO_SIM_PASSWORD_PHCORP_PIN:
return 9; /* corporate personalization key */
case OFONO_SIM_PASSWORD_SIM_PUK:
return 11; /* PUK1 */
case OFONO_SIM_PASSWORD_SIM_PUK2:
return 12; /* PUK2 */
case OFONO_SIM_PASSWORD_PHFSIM_PUK:
return 13; /* device to very first SIM PIN unlock key */
case OFONO_SIM_PASSWORD_PHNET_PUK:
return 14; /* network personalization unlock key */
case OFONO_SIM_PASSWORD_PHNETSUB_PUK:
return 15; /* network subset personaliation unlock key */
case OFONO_SIM_PASSWORD_PHSP_PUK:
return 16; /* service provider (SP) personalization unlock key */
case OFONO_SIM_PASSWORD_PHCORP_PUK:
return 17; /* corporate personalization unlock key */
case OFONO_SIM_PASSWORD_NONE:
case OFONO_SIM_PASSWORD_INVALID:
break;
}
return 0;
}
static void mbim_pin_query_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
struct sim_data *sd = cbd->user;
ofono_sim_passwd_cb_t cb = cbd->cb;
uint32_t pin_type;
uint32_t pin_state;
enum ofono_sim_password_type sim_password;
bool r;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
r = mbim_message_get_arguments(message, "uu",
&pin_type, &pin_state);
if (!r)
goto error;
sim_password = mbim_pin_type_to_sim_password(pin_type);
if (sim_password == OFONO_SIM_PASSWORD_INVALID)
goto error;
if (pin_state == 0)
sim_password = OFONO_SIM_PASSWORD_NONE;
sd->last_pin_type = pin_type;
CALLBACK_WITH_SUCCESS(cb, sim_password, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void mbim_pin_query(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *user_data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
struct mbim_message *message;
DBG("");
cbd->user = sd;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PIN,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(sd->device, SIM_GROUP, message,
mbim_pin_query_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, -1, user_data);
}
static void mbim_pin_retries_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
int retries[OFONO_SIM_PASSWORD_INVALID];
size_t i;
uint32_t pin_type;
uint32_t pin_state;
uint32_t remaining;
enum ofono_sim_password_type sim_password;
bool r;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
r = mbim_message_get_arguments(message, "uuu",
&pin_type, &pin_state, &remaining);
if (!r)
goto error;
sim_password = mbim_pin_type_to_sim_password(pin_type);
if (sim_password == OFONO_SIM_PASSWORD_INVALID)
goto error;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
retries[i] = -1;
if (pin_state == 0 || sim_password == OFONO_SIM_PASSWORD_NONE) {
CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
return;
}
if (remaining == 0xffffffff)
retries[sim_password] = -1;
else
retries[sim_password] = remaining;
CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void mbim_pin_retries_query(struct ofono_sim *sim,
ofono_sim_pin_retries_cb_t cb, void *user_data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, user_data);
struct mbim_message *message;
DBG("");
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PIN,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(sd->device, SIM_GROUP, message,
mbim_pin_retries_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, NULL, user_data);
}
static void mbim_pin_set_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
DBG("");
if (mbim_message_get_error(message) != 0)
CALLBACK_WITH_FAILURE(cb, cbd->data);
else
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void mbim_pin_set(struct ofono_sim *sim, uint32_t pin_type,
uint32_t pin_operation,
const char *old_passwd,
const char *new_passwd,
ofono_sim_lock_unlock_cb_t cb,
void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
DBG("%u %u %s %s", pin_type, pin_operation, old_passwd, new_passwd);
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_PIN,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "uuss", pin_type, pin_operation,
old_passwd, new_passwd);
if (mbim_device_send(sd->device, SIM_GROUP, message,
mbim_pin_set_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, data);
}
static void mbim_pin_enter(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
/* Use MBIMPinOperationEnter (0) and NULL second PIN */
mbim_pin_set(sim, sd->last_pin_type, 0, passwd, NULL, cb, data);
}
static void mbim_puk_enter(struct ofono_sim *sim, const char *puk,
const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct sim_data *sd = ofono_sim_get_data(sim);
/* Use MBIMPinOperationEnter (0) and second PIN */
mbim_pin_set(sim, sd->last_pin_type, 0, puk, passwd, cb, data);
}
static void mbim_pin_enable(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
int enable, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
uint32_t pin_type = mbim_pin_type_from_sim_password(passwd_type);
if (pin_type == 0) {
CALLBACK_WITH_FAILURE(cb, data);
return;
}
/* Use MBIMPinOperationEnable (1) or MBIMPinOperationDisable (2) */
mbim_pin_set(sim, pin_type, enable ? 1 : 2, passwd, NULL, cb, data);
}
static void mbim_pin_change(struct ofono_sim *sim,
enum ofono_sim_password_type passwd_type,
const char *old_passwd, const char *new_passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
uint32_t pin_type = mbim_pin_type_from_sim_password(passwd_type);
if (pin_type == 0) {
CALLBACK_WITH_FAILURE(cb, data);
return;
}
/* Use MBIMPinOperationChange (3) */
mbim_pin_set(sim, pin_type, 3, old_passwd, new_passwd, cb, data);
}
static void mbim_subscriber_ready_status_changed(struct mbim_message *message,
void *user)
{
struct ofono_sim *sim = user;
struct sim_data *sd = ofono_sim_get_data(sim);
uint32_t ready_state;
char *imsi;
char *iccid;
uint32_t ready_info;
DBG("");
if (!mbim_message_get_arguments(message, "ussu",
&ready_state, &imsi,
&iccid, &ready_info))
return;
l_free(sd->iccid);
sd->iccid = iccid;
l_free(sd->imsi);
sd->imsi = imsi;
DBG("%s %s", iccid, imsi);
mbim_sim_state_changed(sim, ready_state);
}
static void mbim_subscriber_ready_status_cb(struct mbim_message *message,
void *user)
{
struct ofono_sim *sim = user;
struct sim_data *sd = ofono_sim_get_data(sim);
uint32_t ready_state;
char *imsi;
char *iccid;
uint32_t ready_info;
bool r;
DBG("");
if (mbim_message_get_error(message) != 0)
goto error;
/* We don't bother parsing MSISDN/MDN array */
r = mbim_message_get_arguments(message, "ussu",
&ready_state, &imsi,
&iccid, &ready_info);
if (!r)
goto error;
sd->iccid = iccid;
sd->imsi = imsi;
if (!mbim_device_register(sd->device, SIM_GROUP,
mbim_uuid_basic_connect,
MBIM_CID_SUBSCRIBER_READY_STATUS,
mbim_subscriber_ready_status_changed,
sim, NULL))
goto error;
ofono_sim_register(sim);
DBG("%s %s", iccid, imsi);
mbim_sim_state_changed(sim, ready_state);
return;
error:
ofono_sim_remove(sim);
}
static int mbim_sim_probe(struct ofono_sim *sim, unsigned int vendor,
void *data)
{
struct mbim_device *device = data;
struct mbim_message *message;
struct sim_data *sd;
message = mbim_message_new(mbim_uuid_basic_connect,
MBIM_CID_SUBSCRIBER_READY_STATUS,
MBIM_COMMAND_TYPE_QUERY);
if (!message)
return -ENOMEM;
mbim_message_set_arguments(message, "");
if (!mbim_device_send(device, SIM_GROUP, message,
mbim_subscriber_ready_status_cb, sim, NULL)) {
mbim_message_unref(message);
return -EIO;
}
sd = l_new(struct sim_data, 1);
sd->device = mbim_device_ref(device);
ofono_sim_set_data(sim, sd);
return 0;
}
static void mbim_sim_remove(struct ofono_sim *sim)
{
struct sim_data *sd = ofono_sim_get_data(sim);
ofono_sim_set_data(sim, NULL);
mbim_device_cancel_group(sd->device, SIM_GROUP);
mbim_device_unregister_group(sd->device, SIM_GROUP);
mbim_device_unref(sd->device);
sd->device = NULL;
l_free(sd->iccid);
l_free(sd->imsi);
l_free(sd);
}
static struct ofono_sim_driver driver = {
.name = "mbim",
.probe = mbim_sim_probe,
.remove = mbim_sim_remove,
.read_imsi = mbim_read_imsi,
.query_passwd_state = mbim_pin_query,
.query_pin_retries = mbim_pin_retries_query,
.send_passwd = mbim_pin_enter,
.reset_passwd = mbim_puk_enter,
.change_passwd = mbim_pin_change,
.lock = mbim_pin_enable,
};
void mbim_sim_init(void)
{
ofono_sim_driver_register(&driver);
}
void mbim_sim_exit(void)
{
ofono_sim_driver_unregister(&driver);
}

View File

@@ -1,516 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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 <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/sms.h>
#include "common.h"
#include "drivers/mbimmodem/mbim.h"
#include "drivers/mbimmodem/mbim-message.h"
#include "drivers/mbimmodem/mbimmodem.h"
struct sms_data {
struct mbim_device *device;
uint32_t configuration_notify_id;
};
static void mbim_sca_set_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_sms_sca_set_cb_t cb = cbd->cb;
DBG("");
if (mbim_message_get_error(message) != 0)
CALLBACK_WITH_FAILURE(cb, cbd->data);
else
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void mbim_sca_set(struct ofono_sms *sms,
const struct ofono_phone_number *sca,
ofono_sms_sca_set_cb_t cb, void *data)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
const char *numberstr = phone_number_to_string(sca);
message = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_CONFIGURATION,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "us", 0, numberstr);
if (mbim_device_send(sd->device, SMS_GROUP, message,
mbim_sca_set_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, data);
}
static void mbim_sca_query_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
ofono_sms_sca_query_cb_t cb = cbd->cb;
struct ofono_phone_number sca;
uint32_t dummy;
L_AUTO_FREE_VAR(char *, number) = NULL;
const char *p;
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "uuuus",
&dummy, &dummy, &dummy, &dummy,
&number))
goto error;
if (number[0] == '+') {
p = number + 1;
sca.type = 145;
} else {
p = number;
sca.type = 129;
}
strncpy(sca.number, p, OFONO_MAX_PHONE_NUMBER_LENGTH);
sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
}
static void mbim_sca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
void *data)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
message = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_CONFIGURATION,
MBIM_COMMAND_TYPE_QUERY);
mbim_message_set_arguments(message, "");
if (mbim_device_send(sd->device, SMS_GROUP, message,
mbim_sca_query_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static void mbim_delete_cb(struct mbim_message *message, void *user)
{
DBG("%u", mbim_message_get_error(message));
}
static void mbim_sms_send_cb(struct mbim_message *message, void *user)
{
struct cb_data *cbd = user;
struct sms_data *sd = cbd->user;
ofono_sms_submit_cb_t cb = cbd->cb;
uint32_t mr;
struct mbim_message *delete;
DBG("%u", mbim_message_get_error(message));
if (mbim_message_get_error(message) != 0)
goto error;
if (!mbim_message_get_arguments(message, "u", &mr))
goto error;
/* Just in case, send an SMS DELETE command for Sent messages */
delete = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_DELETE,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(delete, "uu", 4, 0);
if (!mbim_device_send(sd->device, SMS_GROUP, delete,
mbim_delete_cb, NULL, NULL))
mbim_message_unref(delete);
CALLBACK_WITH_SUCCESS(cb, mr, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
}
static void mbim_submit(struct ofono_sms *sms, const unsigned char *pdu,
int pdu_len, int tpdu_len, int mms,
ofono_sms_submit_cb_t cb, void *data)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct cb_data *cbd = cb_data_new(cb, data);
struct mbim_message *message;
DBG("pdu_len: %d tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
cbd->user = sd;
message = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_SEND,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(message, "ud", 0, "ay", pdu_len, pdu);
if (mbim_device_send(sd->device, SMS_GROUP, message,
mbim_sms_send_cb, cbd, l_free) > 0)
return;
l_free(cbd);
mbim_message_unref(message);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void mbim_sms_send_delete(struct sms_data *sd, uint32_t index)
{
struct mbim_message *delete;
DBG("%u", index);
delete = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_DELETE,
MBIM_COMMAND_TYPE_SET);
mbim_message_set_arguments(delete, "uu", 1, index);
if (!mbim_device_send(sd->device, SMS_GROUP, delete,
mbim_delete_cb, NULL, NULL))
mbim_message_unref(delete);
}
static void mbim_parse_sms_read_info(struct mbim_message *message,
struct ofono_sms *sms)
{
struct sms_data *sd = ofono_sms_get_data(sms);
uint32_t format;
uint32_t n_sms;
struct mbim_message_iter array;
struct mbim_message_iter bytes;
uint32_t index;
uint32_t status;
uint32_t pdu_len;
if (!mbim_message_get_arguments(message, "ua(uuay)",
&format, &n_sms, &array))
return;
if (format != 0)
return;
while (mbim_message_iter_next_entry(&array, &index, &status,
&pdu_len, &bytes)) {
int i = 0;
/* Ignore Draft (2) and Sent (3) messages */
if (status == 0 || status == 1) {
uint8_t pdu[176];
uint32_t tpdu_len;
while (mbim_message_iter_next_entry(&bytes, pdu + i))
i++;
tpdu_len = pdu_len - pdu[0] - 1;
ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len);
}
mbim_sms_send_delete(sd, index);
}
}
static void mbim_sms_read_notify(struct mbim_message *message, void *user)
{
struct ofono_sms *sms = user;
DBG("");
mbim_parse_sms_read_info(message, sms);
}
static void mbim_sms_read_new_query_cb(struct mbim_message *message, void *user)
{
struct ofono_sms *sms = user;
DBG("");
mbim_parse_sms_read_info(message, sms);
}
static void mbim_sms_message_store_status_changed(struct mbim_message *message,
void *user)
{
struct ofono_sms *sms = user;
struct sms_data *sd = ofono_sms_get_data(sms);
uint32_t flag;
uint32_t index;
struct mbim_message *read_query;
DBG("");
if (!mbim_message_get_arguments(message, "uu", &flag, &index))
return;
DBG("%u %u", flag, index);
/* MBIM_SMS_FLAG_NEW_MESSAGE not set */
if ((flag & 2) == 0)
return;
read_query = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_READ,
MBIM_COMMAND_TYPE_QUERY);
if (!read_query)
return;
/* Query using MBIMSmsFormatPdu(0) and MBIMSmsFlagNew (2) */
mbim_message_set_arguments(read_query, "uuu", 0, 2, 0);
if (!mbim_device_send(sd->device, SMS_GROUP, read_query,
mbim_sms_read_new_query_cb, sms, NULL))
mbim_message_unref(read_query);
}
static void mbim_sms_read_all_query_cb(struct mbim_message *message, void *user)
{
struct ofono_sms *sms = user;
struct sms_data *sd = ofono_sms_get_data(sms);
DBG("");
mbim_parse_sms_read_info(message, sms);
mbim_device_register(sd->device, SMS_GROUP, mbim_uuid_sms,
MBIM_CID_SMS_MESSAGE_STORE_STATUS,
mbim_sms_message_store_status_changed,
sms, NULL);
}
static bool mbim_sms_finish_init(struct ofono_sms *sms)
{
struct sms_data *sd = ofono_sms_get_data(sms);
struct mbim_message *message;
/*
* Class 0 SMS comes via SMS_READ notification, so register for these
* here. After that we send an SMS_READ request to retrieve any new
* SMS messages. In the callback we will register to
* MESSAGE_STORE_STATUS to receive notification that new SMS messages
* have arrived
*/
if (!mbim_device_register(sd->device, SMS_GROUP,
mbim_uuid_sms,
MBIM_CID_SMS_READ,
mbim_sms_read_notify, sms, NULL))
return false;
message = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_READ,
MBIM_COMMAND_TYPE_QUERY);
if (!message)
return false;
/* Query using MBIMSmsFormatPdu(0) and MBIMSmsFlagAll (0) */
mbim_message_set_arguments(message, "uuu", 0, 0, 0);
if (!mbim_device_send(sd->device, SMS_GROUP, message,
mbim_sms_read_all_query_cb, sms, NULL)) {
mbim_message_unref(message);
return false;
}
return true;
}
static void mbim_sms_configuration_changed(struct mbim_message *message,
void *user)
{
struct ofono_sms *sms = user;
struct sms_data *sd = ofono_sms_get_data(sms);
uint32_t storage_state;
DBG("");
if (!mbim_message_get_arguments(message, "u", &storage_state))
goto error;
if (storage_state != 1)
return;
mbim_device_unregister(sd->device, sd->configuration_notify_id);
sd->configuration_notify_id = 0;
if (!mbim_sms_finish_init(sms))
goto error;
ofono_sms_register(sms);
return;
error:
ofono_sms_remove(sms);
}
static void mbim_sms_configuration_query_cb(struct mbim_message *message,
void *user)
{
struct ofono_sms *sms = user;
struct sms_data *sd = ofono_sms_get_data(sms);
uint32_t error;
uint32_t storage_state;
uint32_t format;
uint32_t max_messages;
DBG("");
error = mbim_message_get_error(message);
/*
* SUBSCRIBER_READY_STATUS tells us that a SIM is in ReadyState,
* unfortunately that seems to be not enough to know that the SMS
* state is initialized. Handle this here, if we get an error 14
* 'MBIM_STATUS_NOT_INITIALIZED', then listen for the
* SMS_CONFIGURATION notification. Why some devices return an error
* here instead of responding with a 0 storage state is a mystery
*/
switch (error) {
case 14: /* Seems SIM ReadyState is sometimes not enough */
goto setup_notification;
case 0:
break;
default:
goto error;
}
/* We don't bother parsing CdmaShortMessageSize or ScAddress array */
if (!mbim_message_get_arguments(message, "uuu",
&storage_state, &format, &max_messages))
goto error;
DBG("storage_state: %u, format: %u, max_messages: %u",
storage_state, format, max_messages);
if (format != 0) {
DBG("Unsupported SMS Format, expect 0 (PDU)");
goto error;
}
if (storage_state == 1) {
if (!mbim_sms_finish_init(sms))
goto error;
ofono_sms_register(sms);
return;
}
setup_notification:
/* Wait for storage_state to go to Initialized before registering */
sd->configuration_notify_id = mbim_device_register(sd->device,
SMS_GROUP,
mbim_uuid_sms,
MBIM_CID_SMS_CONFIGURATION,
mbim_sms_configuration_changed,
sms, NULL);
if (sd->configuration_notify_id > 0)
return;
error:
ofono_sms_remove(sms);
}
static int mbim_sms_probe(struct ofono_sms *sms, unsigned int vendor,
void *data)
{
struct mbim_device *device = data;
struct sms_data *sd;
struct mbim_message *message;
DBG("");
message = mbim_message_new(mbim_uuid_sms,
MBIM_CID_SMS_CONFIGURATION,
MBIM_COMMAND_TYPE_QUERY);
if (!message)
return -ENOMEM;
mbim_message_set_arguments(message, "");
if (!mbim_device_send(device, SMS_GROUP, message,
mbim_sms_configuration_query_cb, sms, NULL)) {
mbim_message_unref(message);
return -EIO;
}
sd = l_new(struct sms_data, 1);
sd->device = mbim_device_ref(device);
ofono_sms_set_data(sms, sd);
return 0;
}
static void mbim_sms_remove(struct ofono_sms *sms)
{
struct sms_data *sd = ofono_sms_get_data(sms);
DBG("");
ofono_sms_set_data(sms, NULL);
mbim_device_cancel_group(sd->device, SMS_GROUP);
mbim_device_unregister_group(sd->device, SMS_GROUP);
mbim_device_unref(sd->device);
sd->device = NULL;
l_free(sd);
}
static struct ofono_sms_driver driver = {
.name = "mbim",
.probe = mbim_sms_probe,
.remove = mbim_sms_remove,
.sca_query = mbim_sca_query,
.sca_set = mbim_sca_set,
.submit = mbim_submit,
};
void mbim_sms_init(void)
{
ofono_sms_driver_register(&driver);
}
void mbim_sms_exit(void)
{
ofono_sms_driver_unregister(&driver);
}

View File

@@ -1,54 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "src/common.h"
#include "mbim.h"
#include "util.h"
int mbim_data_class_to_tech(uint32_t n)
{
if (n & MBIM_DATA_CLASS_LTE)
return ACCESS_TECHNOLOGY_EUTRAN;
if (n & (MBIM_DATA_CLASS_HSUPA | MBIM_DATA_CLASS_HSDPA))
return ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
if (n & MBIM_DATA_CLASS_HSUPA)
return ACCESS_TECHNOLOGY_UTRAN_HSUPA;
if (n & MBIM_DATA_CLASS_HSDPA)
return ACCESS_TECHNOLOGY_UTRAN_HSDPA;
if (n & MBIM_DATA_CLASS_UMTS)
return ACCESS_TECHNOLOGY_UTRAN;
if (n & MBIM_DATA_CLASS_EDGE)
return ACCESS_TECHNOLOGY_GSM_EGPRS;
if (n & MBIM_DATA_CLASS_GPRS)
return ACCESS_TECHNOLOGY_GSM;
return -1;
}

View File

@@ -1,59 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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
*
*/
#include <ell/ell.h>
struct cb_data {
void *cb;
void *data;
void *user;
};
static inline struct cb_data *cb_data_new(void *cb, void *data)
{
struct cb_data *ret;
ret = l_new(struct cb_data, 1);
ret->cb = cb;
ret->data = data;
ret->user = NULL;
return ret;
}
#define CALLBACK_WITH_FAILURE(cb, args...) \
do { \
struct ofono_error cb_e; \
cb_e.type = OFONO_ERROR_TYPE_FAILURE; \
cb_e.error = 0; \
\
cb(&cb_e, ##args); \
} while (0) \
#define CALLBACK_WITH_SUCCESS(f, args...) \
do { \
struct ofono_error e; \
e.type = OFONO_ERROR_TYPE_NO_ERROR; \
e.error = 0; \
f(&e, ##args); \
} while (0)
int mbim_data_class_to_tech(uint32_t n);

View File

@@ -29,16 +29,12 @@
#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)
@@ -68,124 +64,8 @@ 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;
@@ -194,20 +74,17 @@ 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. We just need to query the
* parameters in effect on the default bearer and
* let the ofono core know about the activated
* context.
* network is joined.
*/
get_lte_attach_params(gprs);
/* FIXME: query default profile number and APN
* instead of assuming profile 1 and ""
*/
ofono_gprs_cid_activated(gprs, 1 , "automatic");
}
} else {
data->last_auto_context_id = 0;
}
return status;
}
@@ -321,7 +198,7 @@ static void qmi_attached_status(struct ofono_gprs *gprs,
g_free(cbd);
}
static void create_wds_cb(struct qmi_service *service, void *user_data)
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);
@@ -329,12 +206,12 @@ static void create_wds_cb(struct qmi_service *service, void *user_data)
DBG("");
if (!service) {
ofono_error("Failed to request WDS service");
ofono_error("Failed to request NAS service");
ofono_gprs_remove(gprs);
return;
}
data->wds = qmi_service_ref(service);
data->nas = qmi_service_ref(service);
/*
* First get the SS info - the modem may already be connected,
@@ -351,25 +228,6 @@ static void create_wds_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)
{
@@ -382,8 +240,6 @@ 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);
@@ -398,9 +254,6 @@ 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);

View File

@@ -1,264 +0,0 @@
/*
*
* 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);
}

View File

@@ -332,7 +332,6 @@ static void register_net_cb(struct qmi_result *result, void *user_data)
struct cb_data *cbd = user_data;
ofono_netreg_register_cb_t cb = cbd->cb;
uint16_t error;
int cme_error;
DBG("");
@@ -342,8 +341,7 @@ static void register_net_cb(struct qmi_result *result, void *user_data)
goto done;
}
cme_error = qmi_error_to_ofono_cme(error);
CALLBACK_WITH_CME_ERROR(cb, cme_error, cbd->data);
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}

View File

@@ -476,17 +476,6 @@ static const char *__error_to_string(uint16_t error)
return NULL;
}
int qmi_error_to_ofono_cme(int qmi_error) {
switch (qmi_error) {
case 0x0019:
return 4; /* Not Supported */
case 0x0052:
return 32; /* Access Denied */
default:
return -1;
}
}
static void __debug_msg(const char dir, const void *buf, size_t len,
qmi_debug_func_t function, void *user_data)
{
@@ -1084,7 +1073,6 @@ struct discover_data {
qmi_discover_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
uint8_t tid;
guint timeout;
};
@@ -1145,13 +1133,6 @@ static void discover_callback(uint16_t message, uint16_t length,
uint8_t type = service_list->services[i].type;
const char *name = __service_type_to_string(type);
if (name)
__debug_device(device, "found service [%s %d.%d]",
name, major, minor);
else
__debug_device(device, "found service [%d %d.%d]",
type, major, minor);
if (type == QMI_SERVICE_CONTROL) {
device->control_major = major;
device->control_minor = minor;
@@ -1164,6 +1145,13 @@ static void discover_callback(uint16_t message, uint16_t length,
list[count].name = name;
count++;
if (name)
__debug_device(device, "found service [%s %d.%d]",
name, major, minor);
else
__debug_device(device, "found service [%d %d.%d]",
type, major, minor);
}
ptr = tlv_get(buffer, length, 0x10, &len);
@@ -1172,6 +1160,13 @@ static void discover_callback(uint16_t message, uint16_t length,
device->version_str = strndup(ptr + 1, *((uint8_t *) ptr));
service_list = ptr + *((uint8_t *) ptr) + 1;
for (i = 0; i < service_list->count; i++) {
if (service_list->services[i].type == QMI_SERVICE_CONTROL)
continue;
}
done:
device->version_list = list;
device->version_count = count;
@@ -1186,38 +1181,14 @@ static gboolean discover_reply(gpointer user_data)
{
struct discover_data *data = user_data;
struct qmi_device *device = data->device;
unsigned int tid = data->tid;
GList *list;
struct qmi_request *req = NULL;
data->timeout = 0;
/* remove request from queues */
if (tid != 0) {
list = g_queue_find_custom(device->req_queue,
GUINT_TO_POINTER(tid), __request_compare);
if (list) {
req = list->data;
g_queue_delete_link(device->req_queue, list);
} else {
list = g_queue_find_custom(device->control_queue,
GUINT_TO_POINTER(tid), __request_compare);
if (list) {
req = list->data;
g_queue_delete_link(device->control_queue,
list);
}
}
}
if (data->func)
data->func(device->version_count,
device->version_list, data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
__request_free(req, NULL);
return FALSE;
}
@@ -1263,7 +1234,6 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
data->tid = hdr->transaction;
__request_submit(device, req, hdr->transaction);
@@ -1353,65 +1323,6 @@ bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
return true;
}
struct sync_data {
qmi_sync_func_t func;
void *user_data;
};
static void qmi_device_sync_callback(uint16_t message, uint16_t length,
const void *buffer, void *user_data)
{
struct sync_data *data = user_data;
if (data->func)
data->func(data->user_data);
g_free(data);
}
/* sync will release all previous clients */
bool qmi_device_sync(struct qmi_device *device,
qmi_sync_func_t func, void *user_data)
{
struct qmi_request *req;
struct qmi_control_hdr *hdr;
struct sync_data *func_data;
if (!device)
return false;
__debug_device(device, "Sending sync to reset QMI");
func_data = g_new0(struct sync_data, 1);
func_data->func = func;
func_data->user_data = user_data;
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_SYNC, QMI_CONTROL_HDR_SIZE,
NULL, 0,
qmi_device_sync_callback, func_data, (void **) &hdr);
if (device->next_control_tid < 1)
device->next_control_tid = 1;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
__request_submit(device, req, hdr->transaction);
return true;
}
/* if the device support the QMI call SYNC over the CTL interface */
bool qmi_device_is_sync_supported(struct qmi_device *device)
{
if (device == NULL)
return false;
return (device->control_major > 1 ||
(device->control_major == 1 && device->control_minor >= 5));
}
static bool get_device_file_name(struct qmi_device *device,
char *file_name, int size)
{

View File

@@ -76,7 +76,7 @@ typedef void (*qmi_destroy_func_t)(void *user_data);
struct qmi_device;
typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
typedef void (*qmi_sync_func_t)(void *user_data);
typedef void (*qmi_shutdown_func_t)(void *user_data);
typedef void (*qmi_discover_func_t)(uint8_t count,
const struct qmi_version *list, void *user_data);
@@ -96,10 +96,6 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
void *user_data, qmi_destroy_func_t destroy);
bool qmi_device_sync(struct qmi_device *device,
qmi_sync_func_t func, void *user_data);
bool qmi_device_is_sync_supported(struct qmi_device *device);
enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
struct qmi_device *device);
bool qmi_device_set_expected_data_format(struct qmi_device *device,
@@ -144,8 +140,6 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
uint64_t *value);
void qmi_result_print_tlvs(struct qmi_result *result);
int qmi_error_to_ofono_cme(int qmi_error);
struct qmi_service;
typedef void (*qmi_result_func_t)(struct qmi_result *result, void *user_data);

View File

@@ -39,7 +39,6 @@ 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();
@@ -52,7 +51,6 @@ 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();

View File

@@ -48,9 +48,6 @@ 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);

View File

@@ -277,9 +277,6 @@ 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);

View File

@@ -334,38 +334,9 @@ error:
g_free(cbd);
}
static void raw_read_cb(struct qmi_result *result, void *user_data)
{
struct ofono_sms *sms = user_data;
const struct qmi_wms_raw_message* msg;
uint16_t len;
uint16_t error;
if (qmi_result_set_error(result, &error)) {
DBG("Raw read error: %d (%s)", error,
qmi_result_get_error(result));
return;
}
/* Raw message data */
msg = qmi_result_get(result, 0x01, &len);
if (msg) {
uint16_t plen;
uint16_t tpdu_len;
plen = GUINT16_FROM_LE(msg->msg_length);
tpdu_len = plen - msg->msg_data[0] - 1;
ofono_sms_deliver_notify(sms, msg->msg_data, plen, tpdu_len);
} else {
DBG("No message data available at requested position");
}
}
static void event_notify(struct qmi_result *result, void *user_data)
{
struct ofono_sms *sms = user_data;
struct sms_data *data = ofono_sms_get_data(sms);
const struct qmi_wms_result_new_msg_notify *notify;
const struct qmi_wms_result_message *message;
uint16_t len;
@@ -389,34 +360,6 @@ static void event_notify(struct qmi_result *result, void *user_data)
DBG("msg format %d PDU length %d", message->msg_format, plen);
ofono_sms_deliver_notify(sms, message->msg_data, plen, plen);
} else {
/* The Quectel EC21, at least, does not provide the
* message data in the event notification, so a 'raw read'
* needs to be issued in order to query the message itself
*/
struct qmi_param *param;
param = qmi_param_new();
if (!param)
return;
/* Message memory storage ID */
qmi_param_append(param, 0x01, sizeof(*notify), notify);
/* The 'message mode' parameter is documented as optional,
* but the Quectel EC21 errors out with error 17 (missing
* argument) if it is not provided... we default to 3GPP
* here because that's what works for me and it's not clear
* how to actually query what this should be otherwise...
*/
/* Message mode */
qmi_param_append_uint8(param, 0x10,
QMI_WMS_MESSAGE_MODE_GSMWCDMA);
if (qmi_service_send(data->wms, QMI_WMS_RAW_READ, param,
raw_read_cb, sms, NULL) > 0)
return;
qmi_param_free(param);
}
}

View File

@@ -3,7 +3,6 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
*
* 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,103 +23,20 @@
#include <config.h>
#endif
#define _GNU_SOURCE
#include <string.h>
#include <glib.h>
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/ussd.h>
#include <smsutil.h>
#include "qmi.h"
#include "qmimodem.h"
#include "voice.h"
struct ussd_data {
struct qmi_service *voice;
uint16_t major;
uint16_t minor;
};
static int validate_ussd_data(const struct qmi_ussd_data *data, uint16_t size)
{
if (data == NULL)
return 1;
if (size < sizeof(*data))
return 1;
if (size < sizeof(*data) + data->length)
return 1;
if (data->dcs < QMI_USSD_DCS_ASCII || data->dcs > QMI_USSD_DCS_UCS2)
return 1;
return 0;
}
static int convert_qmi_dcs_gsm_dcs(int qmi_dcs, int *gsm_dcs)
{
switch (qmi_dcs) {
case QMI_USSD_DCS_ASCII:
*gsm_dcs = USSD_DCS_8BIT;
break;
default:
return 1;
}
return 0;
}
static void async_orig_ind(struct qmi_result *result, void *user_data)
{
struct ofono_ussd *ussd = user_data;
const struct qmi_ussd_data *qmi_ussd;
uint16_t error = 0;
uint16_t len;
int gsm_dcs;
DBG("");
qmi_result_get_uint16(result, QMI_VOICE_PARAM_ASYNC_USSD_ERROR, &error);
switch (error) {
case 0:
/* no error */
break;
case 92:
qmi_result_get_uint16(result,
QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE,
&error);
DBG("Failure Cause: 0x%04x", error);
goto error;
default:
DBG("USSD Error 0x%04x", error);
goto error;
}
qmi_ussd = qmi_result_get(result, QMI_VOICE_PARAM_ASYNC_USSD_DATA,
&len);
if (qmi_ussd == NULL)
return;
if (validate_ussd_data(qmi_ussd, len))
goto error;
if (convert_qmi_dcs_gsm_dcs(qmi_ussd->dcs, &gsm_dcs))
goto error;
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOTIFY, gsm_dcs,
qmi_ussd->data, qmi_ussd->length);
return;
error:
ofono_ussd_notify(ussd, OFONO_USSD_STATUS_TERMINATED, 0, NULL, 0);
}
static void create_voice_cb(struct qmi_service *service, void *user_data)
{
struct ofono_ussd *ussd = user_data;
@@ -128,7 +44,7 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
DBG("");
if (service == NULL) {
if (!service) {
ofono_error("Failed to request Voice service");
ofono_ussd_remove(ussd);
return;
@@ -142,9 +58,6 @@ static void create_voice_cb(struct qmi_service *service, void *user_data)
data->voice = qmi_service_ref(service);
qmi_service_register(data->voice, QMI_VOICE_ASYNC_ORIG_USSD,
async_orig_ind, ussd, NULL);
ofono_ussd_register(ussd);
}
@@ -164,6 +77,7 @@ static int qmi_ussd_probe(struct ofono_ussd *ussd,
create_voice_cb, ussd, NULL);
return 0;
}
static void qmi_ussd_remove(struct ofono_ussd *ussd)
@@ -179,103 +93,10 @@ static void qmi_ussd_remove(struct ofono_ussd *ussd)
g_free(data);
}
static void qmi_ussd_cancel(struct ofono_ussd *ussd,
ofono_ussd_cb_t cb, void *user_data)
{
struct ussd_data *ud = ofono_ussd_get_data(ussd);
DBG("");
if (qmi_service_send(ud->voice, QMI_VOICE_CANCEL_USSD, NULL,
NULL, NULL, NULL) > 0)
CALLBACK_WITH_SUCCESS(cb, user_data);
else
CALLBACK_WITH_FAILURE(cb, user_data);
}
/*
* The cb is called when the request (on modem layer) reports success or
* failure. It doesn't contain a network result. We get the network answer
* via VOICE_IND.
*/
static void qmi_ussd_request_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_ussd_cb_t cb = cbd->cb;
DBG("");
qmi_result_print_tlvs(result);
if (qmi_result_set_error(result, NULL)) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
}
static void qmi_ussd_request(struct ofono_ussd *ussd, int dcs,
const unsigned char *pdu, int len,
ofono_ussd_cb_t cb, void *data)
{
struct ussd_data *ud = ofono_ussd_get_data(ussd);
struct cb_data *cbd = cb_data_new(cb, data);
struct qmi_ussd_data *qmi_ussd;
struct qmi_param *param;
char *utf8 = NULL;
long utf8_len = 0;
DBG("");
switch (dcs) {
case 0xf: /* 7bit GSM unspecific */
utf8 = ussd_decode(dcs, len, pdu);
if (!utf8)
goto error;
utf8_len = strlen(utf8);
break;
default:
DBG("Unsupported USSD Data Coding Scheme 0x%x", dcs);
goto error;
}
/*
* So far only DCS_ASCII works.
* DCS_8BIT and DCS_UCS2 is broken, because the modem firmware
* (least on a EC20) encodes those in-correctly onto the air interface,
* resulting in wrong decoded USSD data.
*/
qmi_ussd = alloca(sizeof(struct qmi_ussd_data) + utf8_len);
qmi_ussd->dcs = QMI_USSD_DCS_ASCII;
qmi_ussd->length = len;
memcpy(qmi_ussd->data, utf8, utf8_len);
param = qmi_param_new();
if (param == NULL)
goto error;
qmi_param_append(param, QMI_VOICE_PARAM_USS_DATA,
sizeof(struct qmi_ussd_data) + utf8_len, qmi_ussd);
if (qmi_service_send(ud->voice, QMI_VOICE_ASYNC_ORIG_USSD, param,
qmi_ussd_request_cb, cbd, g_free) > 0)
return;
qmi_param_free(param);
error:
g_free(utf8);
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static struct ofono_ussd_driver driver = {
.name = "qmimodem",
.probe = qmi_ussd_probe,
.remove = qmi_ussd_remove,
.request = qmi_ussd_request,
.cancel = qmi_ussd_cancel
};
void qmi_ussd_init(void)

View File

@@ -39,15 +39,6 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
return ret;
}
#define CALLBACK_WITH_CME_ERROR(cb, err, args...) \
do { \
struct ofono_error cb_e; \
cb_e.type = OFONO_ERROR_TYPE_CME; \
cb_e.error = err; \
\
cb(&cb_e, ##args); \
} while (0) \
#define CALLBACK_WITH_FAILURE(cb, args...) \
do { \
struct ofono_error cb_e; \

View File

@@ -1,62 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
*
* 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.
*
*/
#define QMI_VOICE_PARAM_USS_DATA 0x01
#define QMI_VOICE_PARAM_ASYNC_USSD_ERROR 0x10
#define QMI_VOICE_PARAM_ASYNC_USSD_FAILURE_CASE 0x11
#define QMI_VOICE_PARAM_ASYNC_USSD_DATA 0x12
#define QMI_VOICE_PARAM_USSD_IND_USER_ACTION 0x01
#define QMI_VOICE_PARAM_USSD_IND_DATA 0x10
#define QMI_VOICE_PARAM_USSD_IND_UCS2 0x11
/* according to GSM TS 23.038 section 5
* coding group 1111, No message class, 8 bit data
*/
#define USSD_DCS_8BIT 0xf4
/* coding group 01xx, Class 0, UCS2 (16 bit) */
#define USSD_DCS_UCS2 0x48
/* default alphabet Language unspecific */
#define USSD_DCS_UNSPECIFIC 0x0f
/* based on qmi ussd definition */
enum qmi_ussd_dcs {
QMI_USSD_DCS_ASCII = 0x1,
QMI_USSD_DCS_8BIT,
QMI_USSD_DCS_UCS2,
};
enum qmi_ussd_user_required {
QMI_USSD_NO_USER_ACTION_REQUIRED = 0x1,
QMI_USSD_USER_ACTION_REQUIRED,
};
/* QMI service voice. Using an enum to prevent doublicated entries */
enum voice_commands {
QMI_VOICE_CANCEL_USSD = 0x3c,
QMI_VOICE_USSD_RELEASE_IND = 0x3d,
QMI_VOICE_USSD_IND = 0x3e,
QMI_VOICE_SUPS_IND = 0x42,
QMI_VOICE_ASYNC_ORIG_USSD = 0x43,
};
struct qmi_ussd_data {
uint8_t dcs;
uint8_t length;
uint8_t data[0];
} __attribute__((__packed__));

View File

@@ -25,8 +25,6 @@
#define QMI_WMS_RAW_SEND 32 /* Send a raw message */
#define QMI_WMS_RAW_READ 34 /* Read raw message from storage*/
#define QMI_WMS_GET_MSG_LIST 49 /* Get list of messages from the device */
#define QMI_WMS_SET_ROUTES 50 /* Set routes for message memory storage */
#define QMI_WMS_GET_ROUTES 51 /* Get routes for message memory storage */
@@ -68,13 +66,6 @@ struct qmi_wms_param_message {
#define QMI_WMS_MESSAGE_MODE_GSMWCDMA 1
struct qmi_wms_raw_message {
uint8_t msg_tag;
uint8_t msg_format;
uint16_t msg_length;
uint8_t msg_data[0];
} __attribute__((__packed__));
/* Get routes for message memory storage */
#define QMI_WMS_RESULT_ROUTE_LIST 0x01
#define QMI_WMS_PARAM_ROUTE_LIST 0x01

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2018 Jolla Ltd.
* Copyright (C) 2015-2017 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,7 +14,6 @@
*/
#include "ril_plugin.h"
#include "ril_sim_card.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -27,11 +26,11 @@
* ril.h does not state that string count must be given, but that is
* still expected by the modem
*/
#define RIL_QUERY_STRING_COUNT 4
#define RIL_SET_STRING_COUNT 5
#define RIL_SET_PW_STRING_COUNT 3
struct ril_call_barring {
struct ril_sim_card *card;
GRilIoQueue *q;
guint timer_id;
};
@@ -107,7 +106,7 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
{
struct ril_call_barring *bd = ofono_call_barring_get_data(b);
char cls_textual[RIL_MAX_SERVICE_LENGTH];
GRilIoRequest *req;
GRilIoRequest *req = grilio_request_new();
DBG("lock: %s, services to query: %d", lock, cls);
@@ -124,9 +123,15 @@ static void ril_call_barring_query(struct ofono_call_barring *b,
/*
* See 3GPP 27.007 7.4 for parameter descriptions.
* According to ril.h password should be empty string "" when not
* needed, but in reality we only need to give string length as 0
*/
req = grilio_request_array_utf8_new(4, lock, "", cls_textual,
ril_sim_card_app_aid(bd->card));
grilio_request_append_int32(req, RIL_QUERY_STRING_COUNT);
grilio_request_append_utf8(req, lock); /* Facility code */
grilio_request_append_int32(req, 0); /* Password length */
grilio_request_append_utf8(req, cls_textual);
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_QUERY_FACILITY_LOCK,
ril_call_barring_query_cb, cb, data);
@@ -177,7 +182,7 @@ static void ril_call_barring_set(struct ofono_call_barring *b,
RIL_FACILITY_UNLOCK);
grilio_request_append_utf8(req, passwd);
grilio_request_append_utf8(req, cls_textual);
grilio_request_append_utf8(req, ril_sim_card_app_aid(bd->card));
grilio_request_append_utf8(req, NULL); /* AID (not yet supported) */
ril_call_barring_submit_request(bd, req,
RIL_REQUEST_SET_FACILITY_LOCK,
@@ -238,7 +243,6 @@ static int ril_call_barring_probe(struct ofono_call_barring *b,
struct ril_call_barring *bd = g_new0(struct ril_call_barring, 1);
DBG("");
bd->card = ril_sim_card_ref(modem->sim_card);
bd->q = grilio_queue_new(ril_modem_io(modem));
bd->timer_id = g_idle_add(ril_call_barring_register, b);
ofono_call_barring_set_data(b, bd);
@@ -256,7 +260,6 @@ static void ril_call_barring_remove(struct ofono_call_barring *b)
g_source_remove(bd->timer_id);
}
ril_sim_card_unref(bd->card);
grilio_queue_cancel_all(bd->q, FALSE);
grilio_queue_unref(bd->q);
g_free(bd);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2015-2017 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,7 +24,6 @@ struct ril_cbs {
GRilIoChannel *io;
GRilIoQueue *q;
char *log_prefix;
guint register_id;
gulong event_id;
};
@@ -52,12 +51,6 @@ 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)
@@ -68,9 +61,6 @@ 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);
@@ -107,9 +97,6 @@ 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);
@@ -157,41 +144,27 @@ 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);
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);
}
}
DBG_(cd, "%u bytes", len);
ofono_cbs_notify(cd->cbs, data, len);
}
static gboolean ril_cbs_register(void *user_data)
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_cbs *cd = user_data;
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;
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);
}
}
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
@@ -199,6 +172,7 @@ 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]) ?
@@ -208,7 +182,20 @@ 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);
cd->register_id = g_idle_add(ril_cbs_register, cd);
/*
* 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);
return 0;
}
@@ -217,9 +204,6 @@ 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);

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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,10 +23,10 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#define DEFAULT_UPDATE_RATE_MS (10000) /* 10 sec */
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
#define MAX_RETRIES (5)
typedef GObjectClass RilCellInfoClass;
@@ -37,12 +36,13 @@ struct ril_cell_info {
GObject object;
struct sailfish_cell_info info;
GRilIoChannel *io;
MceDisplay *display;
struct ril_radio *radio;
struct ril_sim_card *sim_card;
gulong display_state_event_id;
gulong radio_state_event_id;
gulong sim_status_event_id;
gboolean sim_card_ready;
int update_rate_ms;
char *log_prefix;
gulong event_id;
guint query_id;
@@ -75,20 +75,6 @@ static void ril_cell_free1(gpointer cell)
ril_cell_free(cell);
}
static const char *ril_cell_info_int_format(int value, const char *format)
{
if (value == SAILFISH_CELL_INVALID_VALUE) {
return "";
} else {
static GUtilIdlePool *ril_cell_info_pool = NULL;
GUtilIdlePool *pool = gutil_idle_pool_get(&ril_cell_info_pool);
char *str = g_strdup_printf(format, value);
gutil_idle_pool_add(pool, str, g_free);
return str;
}
}
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
while (l1 && l2) {
@@ -137,17 +123,11 @@ static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
DBG("[gsm] reg=%d%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(gsm->mcc, ",mcc=%d"),
ril_cell_info_int_format(gsm->mnc, ",mnc=%d"),
ril_cell_info_int_format(gsm->lac, ",lac=%d"),
ril_cell_info_int_format(gsm->cid, ",cid=%d"),
ril_cell_info_int_format(gsm->arfcn, ",arfcn=%d"),
ril_cell_info_int_format(gsm->bsic, ",bsic=%d"),
ril_cell_info_int_format(gsm->signalStrength,
",strength=%d"),
ril_cell_info_int_format(gsm->bitErrorRate, ",err=%d"),
ril_cell_info_int_format(gsm->timingAdvance, ",t=%d"));
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
"bsic=%d,strength=%d,err=%d,t=%d", registered,
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
gsm->timingAdvance);
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = registered;
return cell;
@@ -175,16 +155,10 @@ static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
DBG("[wcdma] reg=%d%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(wcdma->mcc, ",mcc=%d"),
ril_cell_info_int_format(wcdma->mnc, ",mnc=%d"),
ril_cell_info_int_format(wcdma->lac, ",lac=%d"),
ril_cell_info_int_format(wcdma->cid, ",cid=%d"),
ril_cell_info_int_format(wcdma->psc, ",psc=%d"),
ril_cell_info_int_format(wcdma->signalStrength,
",strength=%d"),
ril_cell_info_int_format(wcdma->bitErrorRate,
",err=%d"));
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
"strength=%d,err=%d", registered, wcdma->mcc,
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
wcdma->signalStrength, wcdma->bitErrorRate);
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = registered;
return cell;
@@ -216,19 +190,11 @@ static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
grilio_parser_get_int32(rilp, &lte->rssnr) &&
grilio_parser_get_int32(rilp, &lte->cqi) &&
grilio_parser_get_int32(rilp, &lte->timingAdvance)) {
DBG("[lte] reg=%d%s%s%s%s%s%s%s%s%s%s%s", registered,
ril_cell_info_int_format(lte->mcc, ",mcc=%d"),
ril_cell_info_int_format(lte->mnc, ",mnc=%d"),
ril_cell_info_int_format(lte->ci, ",ci=%d"),
ril_cell_info_int_format(lte->pci, ",pci=%d"),
ril_cell_info_int_format(lte->tac, ",tac=%d"),
ril_cell_info_int_format(lte->signalStrength,
",strength=%d"),
ril_cell_info_int_format(lte->rsrp, ",rsrp=%d"),
ril_cell_info_int_format(lte->rsrq, ",rsrq=%d"),
ril_cell_info_int_format(lte->rssnr, ",rssnr=%d"),
ril_cell_info_int_format(lte->cqi, ",cqi=%d"),
ril_cell_info_int_format(lte->timingAdvance, ",t=%d"));
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = registered;
return cell;
@@ -345,24 +311,11 @@ 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)
{
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
}
}
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,
@@ -370,13 +323,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
grilio_request_unref(req);
}
static void ril_cell_info_set_rate(struct ril_cell_info *self)
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
{
GRilIoRequest *req = grilio_request_array_int32_new(1,
(self->update_rate_ms >= 0) ? self->update_rate_ms : INT_MAX);
GRilIoRequest *req = grilio_request_sized_new(8);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, ms);
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,
@@ -384,6 +337,20 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self)
grilio_request_unref(req);
}
static void ril_cell_info_update_rate(struct ril_cell_info *self)
{
if (self->sim_card_ready) {
ril_cell_info_set_rate(self,
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
}
}
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
{
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
}
static void ril_cell_info_refresh(struct ril_cell_info *self)
{
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
@@ -409,15 +376,12 @@ static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
self->sim_card_ready = ril_sim_card_ready(sim);
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
ril_cell_info_update_rate(self);
}
/* sailfish_cell_info interface callbacks */
struct ril_cell_info_closure {
GCClosure cclosure;
struct ril_cell_info_signal_data {
sailfish_cell_info_cb_t cb;
void *arg;
};
@@ -439,9 +403,17 @@ static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
}
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
struct ril_cell_info_closure *closure)
void *user_data)
{
closure->cb(&self->info, closure->arg);
struct ril_cell_info_signal_data *data = user_data;
data->cb(&self->info, data->arg);
}
static void ril_cell_info_cells_disconnect_notify(gpointer data,
GClosure *closure)
{
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
}
static gulong ril_cell_info_add_cells_changed_handler_proc
@@ -449,18 +421,16 @@ static gulong ril_cell_info_add_cells_changed_handler_proc
sailfish_cell_info_cb_t cb, void *arg)
{
if (cb) {
struct ril_cell_info_closure *closure =
(struct ril_cell_info_closure *) g_closure_new_simple
(sizeof(struct ril_cell_info_closure), NULL);
GCClosure* cc = &closure->cclosure;
struct ril_cell_info_signal_data *data =
g_slice_new(struct ril_cell_info_signal_data);
cc->closure.data = closure;
cc->callback = G_CALLBACK(ril_cell_info_cells_changed_cb);
closure->cb = cb;
closure->arg = arg;
return g_signal_connect_closure_by_id(ril_cell_info_cast(info),
ril_cell_info_signals[SIGNAL_CELLS_CHANGED], 0,
&cc->closure, FALSE);
data->cb = cb;
data->arg = arg;
return g_signal_connect_data(ril_cell_info_cast(info),
SIGNAL_CELLS_CHANGED_NAME,
G_CALLBACK(ril_cell_info_cells_changed_cb),
data, ril_cell_info_cells_disconnect_notify,
G_CONNECT_AFTER);
} else {
return 0;
}
@@ -474,36 +444,22 @@ static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
}
}
static void ril_cell_info_set_update_interval_proc
(struct sailfish_cell_info *info, int ms)
{
struct ril_cell_info *self = ril_cell_info_cast(info);
if (self->update_rate_ms != ms) {
self->update_rate_ms = ms;
DBG_(self, "%d ms", ms);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
}
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card)
const char *log_prefix, MceDisplay *display,
struct ril_radio *radio, struct ril_sim_card *sim_card)
{
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
ril_cell_info_ref_proc,
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_remove_handler_proc
};
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
self->info.proc = &ril_cell_info_proc;
self->io = grilio_channel_ref(io);
self->display = mce_display_ref(display);
self->radio = ril_radio_ref(radio);
self->sim_card = ril_sim_card_ref(sim_card);
self->log_prefix = (log_prefix && log_prefix[0]) ?
@@ -511,6 +467,9 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
DBG_(self, "");
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
self->display_state_event_id =
mce_display_add_state_changed_handler(display,
ril_cell_info_display_state_cb, self);
self->radio_state_event_id =
ril_radio_add_state_changed_handler(radio,
ril_cell_info_radio_state_cb, self);
@@ -519,15 +478,12 @@ 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);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
ril_cell_info_update_rate(self);
return &self->info;
}
static void ril_cell_info_init(struct ril_cell_info *self)
{
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
}
static void ril_cell_info_dispose(GObject *object)
@@ -544,6 +500,8 @@ static void ril_cell_info_dispose(GObject *object)
FALSE);
self->set_rate_id = 0;
}
gutil_disconnect_handlers(self->display,
&self->display_state_event_id, 1);
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
ril_sim_card_remove_handlers(self->sim_card,
&self->sim_status_event_id, 1);
@@ -557,6 +515,7 @@ static void ril_cell_info_finalize(GObject *object)
DBG_(self, "");
g_free(self->log_prefix);
grilio_channel_unref(self->io);
mce_display_unref(self->display);
ril_radio_unref(self->radio);
ril_sim_card_unref(self->sim_card);
g_slist_free_full(self->info.cells, ril_cell_free1);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2019 Jolla Ltd.
* Copyright (C) 2016-2017 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
@@ -17,12 +17,12 @@
#define RIL_CELL_INFO_H
#include "ril_types.h"
#include <mce_display.h>
#include <sailfish_cell_info.h>
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card);
const char *log_prefix, MceDisplay *display,
struct ril_radio *radio, struct ril_sim_card *sim_card);
#endif /* RIL_CELL_INFO_H */

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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,7 +19,6 @@
#include <gutil_intarray.h>
#include <gutil_ints.h>
#include <gutil_misc.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -186,72 +184,6 @@ 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)
{
@@ -274,7 +206,7 @@ GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
while (*ptr) {
int val;
if (gutil_parse_int(*ptr++, 0, &val)) {
if (ril_parse_int(*ptr++, 0, &val)) {
gutil_int_array_append(array, val);
}
}
@@ -304,6 +236,337 @@ 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

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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
@@ -23,6 +22,8 @@
#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,
@@ -35,12 +36,7 @@ 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, ...)
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;
const char *name, int value, ...);
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key);
char *ril_config_ints_to_string(GUtilInts *ints, char separator);

View File

@@ -1,622 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* 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_connman.h"
#include <ofono/log.h>
#include <gdbus.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
#include <glib-object.h>
#define CONNMAN_BUS DBUS_BUS_SYSTEM
#define CONNMAN_SERVICE "net.connman"
#define CONNMAN_PATH "/"
#define CONNMAN_GET_PROPERTIES "GetProperties"
#define CONNMAN_GET_TECHNOLOGIES "GetTechnologies"
#define CONNMAN_PROPERTY_CHANGED "PropertyChanged"
#define CONNMAN_TECH_CONNECTED "Connected"
#define CONNMAN_TECH_TETHERING "Tethering"
#define CONNMAN_INTERFACE_(name) "net.connman." name
#define CONNMAN_MANAGER_INTERFACE CONNMAN_INTERFACE_("Manager")
#define CONNMAN_TECH_INTERFACE CONNMAN_INTERFACE_("Technology")
#define CONNMAN_TECH_PATH_(name) "/net/connman/technology/" name
#define CONNMAN_TECH_PATH_WIFI CONNMAN_TECH_PATH_("wifi")
#define CONNMAN_TECH_CONNECTED_BIT (0x01)
#define CONNMAN_TECH_TETHERING_BIT (0x02)
#define CONNMAN_TECH_ALL_PROPERTY_BITS (\
CONNMAN_TECH_CONNECTED_BIT | \
CONNMAN_TECH_TETHERING_BIT)
typedef GObjectClass ConnManObjectClass;
typedef struct connman_tech ConnManTech;
typedef struct connman_object {
GObject object;
struct ril_connman pub;
guint32 pending_signals;
DBusConnection *connection;
DBusPendingCall *call;
guint service_watch;
guint signal_watch;
GHashTable *techs;
ConnManTech *wifi;
} ConnManObject;
G_DEFINE_TYPE(ConnManObject, connman_object, G_TYPE_OBJECT)
#define CONNMAN_OBJECT_TYPE (connman_object_get_type())
#define CONNMAN_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
CONNMAN_OBJECT_TYPE, ConnManObject))
struct connman_tech {
ConnManObject *obj;
const char *path;
gboolean connected;
gboolean tethering;
};
typedef struct connman_closure {
GCClosure cclosure;
ril_connman_property_cb_t callback;
gpointer user_data;
} ConnManClosure;
#define connman_closure_new() ((ConnManClosure *) \
g_closure_new_simple(sizeof(ConnManClosure), NULL))
#define SIGNAL_PROPERTY_CHANGED_NAME "ril-connman-property-changed"
#define SIGNAL_PROPERTY_DETAIL "%x"
#define SIGNAL_PROPERTY_DETAIL_MAX_LEN (8)
#define SIGNAL_BIT(property) (1 << (property - 1))
#define SIGNAL_BIT_(name) SIGNAL_BIT(RIL_CONNMAN_PROPERTY_##name)
enum connman_object_signal {
SIGNAL_PROPERTY_CHANGED,
SIGNAL_COUNT
};
static guint connman_object_signals[SIGNAL_COUNT];
static GQuark connman_object_property_quarks[RIL_CONNMAN_PROPERTY_COUNT - 1];
static inline ConnManObject *connman_object_cast(struct ril_connman *connman)
{
return G_LIKELY(connman) ?
CONNMAN_OBJECT(G_CAST(connman, ConnManObject, pub)) :
NULL;
}
static inline const char *connman_iter_get_string(DBusMessageIter *it)
{
const char *str = NULL;
dbus_message_iter_get_basic(it, &str);
return str;
}
static GQuark connman_object_property_quark(enum ril_connman_property p)
{
/* For ANY property this function is expected to return zero */
if (p > RIL_CONNMAN_PROPERTY_ANY && p < RIL_CONNMAN_PROPERTY_COUNT) {
const int i = p - 1;
if (G_UNLIKELY(!connman_object_property_quarks[i])) {
char buf[SIGNAL_PROPERTY_DETAIL_MAX_LEN + 1];
snprintf(buf, sizeof(buf), SIGNAL_PROPERTY_DETAIL, p);
buf[sizeof(buf) - 1] = 0;
connman_object_property_quarks[i] =
g_quark_from_string(buf);
}
return connman_object_property_quarks[i];
}
return 0;
}
static void connman_object_property_changed(ConnManObject *self,
enum ril_connman_property property, ConnManClosure *closure)
{
closure->callback(&self->pub, property, closure->user_data);
}
static void connman_object_emit_property_change(ConnManObject *self,
enum ril_connman_property p)
{
self->pending_signals &= ~SIGNAL_BIT(p);
g_signal_emit(self, connman_object_signals[SIGNAL_PROPERTY_CHANGED],
connman_object_property_quark(p), p);
}
static void connman_object_emit_pending_signals(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
gboolean valid_changed, present_changed;
enum ril_connman_property p;
/* Handlers could drop their references to us */
g_object_ref(self);
/*
* PRESENT and VALID are the last signals to be emitted if the object
* BECOMES present and/or valid.
*/
if ((self->pending_signals & SIGNAL_BIT_(VALID)) &&
connman->valid) {
self->pending_signals &= ~SIGNAL_BIT_(VALID);
valid_changed = TRUE;
} else {
valid_changed = FALSE;
}
if ((self->pending_signals & SIGNAL_BIT_(PRESENT)) &&
connman->present) {
self->pending_signals &= ~SIGNAL_BIT_(PRESENT);
present_changed = TRUE;
} else {
present_changed = FALSE;
}
/*
* Emit the signals. Not that in case if valid has become FALSE,
* then VALID is emitted first, otherwise it's emitted last.
* Same thing with PRESENT.
*/
for (p = RIL_CONNMAN_PROPERTY_ANY + 1;
p < RIL_CONNMAN_PROPERTY_COUNT && self->pending_signals;
p++) {
if (self->pending_signals & SIGNAL_BIT(p)) {
connman_object_emit_property_change(self, p);
}
}
/* Then emit PRESENT and VALID if necessary */
if (present_changed) {
connman_object_emit_property_change(self,
RIL_CONNMAN_PROPERTY_PRESENT);
}
if (valid_changed) {
connman_object_emit_property_change(self,
RIL_CONNMAN_PROPERTY_VALID);
}
/* And release the temporary reference */
g_object_unref(self);
}
static void connman_cancel_call(ConnManObject *self)
{
if (self->call) {
dbus_pending_call_cancel(self->call);
dbus_pending_call_unref(self->call);
self->call = NULL;
}
}
static ConnManTech *connman_tech_new(ConnManObject *self, const char *path)
{
ConnManTech *tech = g_new0(ConnManTech, 1);
char *key = g_strdup(path);
tech->obj = self;
tech->path = key;
g_hash_table_replace(self->techs, key, tech);
return tech;
}
static void connman_invalidate(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
if (connman->valid) {
connman->valid = FALSE;
self->pending_signals |= SIGNAL_BIT_(VALID);
}
}
static void connman_update_valid(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
const gboolean valid = (connman->present && !self->call);
if (connman->valid != valid) {
connman->valid = valid;
self->pending_signals |= SIGNAL_BIT_(VALID);
}
}
static gboolean connman_update_tethering(ConnManObject *self)
{
struct ril_connman *connman = &self->pub;
gboolean tethering = FALSE;
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, self->techs);
while (g_hash_table_iter_next(&it, NULL, &value)) {
const ConnManTech *tech = value;
if (tech->tethering) {
tethering = TRUE;
break;
}
}
if (connman->tethering != tethering) {
connman->tethering = tethering;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
return TRUE;
} else {
return FALSE;
}
}
static void connman_set_tech_tethering(ConnManTech *tech, gboolean tethering)
{
if (tech->tethering != tethering) {
ConnManObject *self = tech->obj;
tech->tethering = tethering;
DBG(CONNMAN_TECH_TETHERING " %s for %s",
tethering ? "on" : "off", tech->path);
if (tethering) {
struct ril_connman *connman = &self->pub;
if (G_LIKELY(!connman->tethering)) {
/* Definitely tethering now */
connman->tethering = TRUE;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
DBG("Tethering on");
}
} else if (connman_update_tethering(self)) {
/* Not tethering anymore */
DBG("Tethering off");
}
}
}
static void connman_set_tech_connected(ConnManTech *tech, gboolean connected)
{
if (tech->connected != connected) {
ConnManObject *self = tech->obj;
tech->connected = connected;
DBG(CONNMAN_TECH_CONNECTED " %s for %s",
connected ? "on" : "off", tech->path);
if (tech == self->wifi) {
struct ril_connman *connman = &self->pub;
connman->wifi_connected = connected;
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
DBG("WiFi %sconnected", connected ? "" : "dis");
}
}
}
static int connman_tech_set_property(ConnManTech *tech, DBusMessageIter *it)
{
DBusMessageIter var;
DBusBasicValue value;
const char *key = connman_iter_get_string(it);
dbus_message_iter_next(it);
dbus_message_iter_recurse(it, &var);
dbus_message_iter_get_basic(&var, &value);
if (!g_ascii_strcasecmp(key, CONNMAN_TECH_CONNECTED)) {
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
connman_set_tech_connected(tech, value.bool_val);
return CONNMAN_TECH_CONNECTED_BIT;
}
} else if (!g_ascii_strcasecmp(key, CONNMAN_TECH_TETHERING)) {
if (dbus_message_iter_get_arg_type(&var) == DBUS_TYPE_BOOLEAN) {
connman_set_tech_tethering(tech, value.bool_val);
return CONNMAN_TECH_TETHERING_BIT;
}
}
return 0;
}
static void connman_tech_set_properties(ConnManTech *tech, DBusMessageIter *it)
{
DBusMessageIter dict;
int handled = 0;
dbus_message_iter_recurse(it, &dict);
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry;
dbus_message_iter_recurse(&dict, &entry);
handled |= connman_tech_set_property(tech, &entry);
if (handled == CONNMAN_TECH_ALL_PROPERTY_BITS) {
/* Ignore the rest */
break;
}
dbus_message_iter_next(&dict);
}
}
static gboolean connman_tech_property_changed(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
const char *path = dbus_message_get_path(msg);
ConnManObject *self = CONNMAN_OBJECT(user_data);
ConnManTech *tech = g_hash_table_lookup(self->techs, path);
DBusMessageIter it;
if (tech && dbus_message_has_signature(msg, "sv") &&
dbus_message_iter_init(msg, &it)) {
const char* name = connman_iter_get_string(&it);
if (!connman_tech_set_property(tech, &it)) {
DBG("%s changed for %s", name, path);
}
connman_object_emit_pending_signals(self);
}
return TRUE;
}
static void connman_set_techs(ConnManObject *self, DBusMessageIter *it)
{
DBusMessageIter list;
dbus_message_iter_recurse(it, &list);
while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
DBusMessageIter entry;
const char *path;
ConnManTech *tech;
dbus_message_iter_recurse(&list, &entry);
path = connman_iter_get_string(&entry);
tech = connman_tech_new(self, path);
DBG("%s", path);
if (!g_strcmp0(path, CONNMAN_TECH_PATH_WIFI)) {
/* WiFi is a special case */
self->wifi = tech;
}
dbus_message_iter_next(&entry);
connman_tech_set_properties(tech, &entry);
dbus_message_iter_next(&list);
}
}
static void connman_techs_reply(DBusPendingCall *call, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusError error;
DBusMessageIter array;
dbus_error_init(&error);
if (dbus_set_error_from_message(&error, reply)) {
DBG("Failed to get technologies: %s", error.message);
dbus_error_free(&error);
} else if (dbus_message_has_signature(reply, "a(oa{sv})") &&
dbus_message_iter_init(reply, &array)) {
connman_set_techs(self, &array);
}
dbus_message_unref(reply);
dbus_pending_call_unref(self->call);
self->call = NULL;
connman_update_valid(self);
connman_object_emit_pending_signals(self);
}
static void connman_get_techs(ConnManObject *self)
{
DBusMessage *msg = dbus_message_new_method_call(CONNMAN_SERVICE,
CONNMAN_PATH, CONNMAN_MANAGER_INTERFACE,
CONNMAN_GET_TECHNOLOGIES);
connman_cancel_call(self);
if (g_dbus_send_message_with_reply(self->connection, msg,
&self->call, DBUS_TIMEOUT_INFINITE)) {
/* Not valid while any request is pending */
connman_invalidate(self);
dbus_pending_call_set_notify(self->call, connman_techs_reply,
self, NULL);
}
dbus_message_unref(msg);
}
static void connman_appeared(DBusConnection *conn, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
struct ril_connman *connman = &self->pub;
if (!connman->present) {
DBG("connman is there");
connman->present = TRUE;
self->pending_signals |= SIGNAL_BIT_(PRESENT);
connman_get_techs(self);
connman_object_emit_pending_signals(self);
}
}
static void connman_vanished(DBusConnection *conn, void *user_data)
{
ConnManObject *self = CONNMAN_OBJECT(user_data);
struct ril_connman *connman = &self->pub;
if (connman->present) {
DBG("connman has disappeared");
g_hash_table_remove_all(self->techs);
self->wifi = NULL;
connman->present = FALSE;
self->pending_signals |= SIGNAL_BIT_(PRESENT);
if (connman->wifi_connected) {
connman->wifi_connected = FALSE;
self->pending_signals |= SIGNAL_BIT_(WIFI_CONNECTED);
}
if (connman->tethering) {
connman->tethering = FALSE;
self->pending_signals |= SIGNAL_BIT_(TETHERING);
}
connman_object_emit_pending_signals(self);
}
}
static void connman_init(ConnManObject *self, DBusConnection *connection)
{
self->connection = dbus_connection_ref(connection);
self->service_watch = g_dbus_add_service_watch(self->connection,
CONNMAN_SERVICE, connman_appeared, connman_vanished,
self, NULL);
self->signal_watch = g_dbus_add_signal_watch(self->connection,
CONNMAN_SERVICE, NULL, CONNMAN_TECH_INTERFACE,
CONNMAN_PROPERTY_CHANGED, connman_tech_property_changed,
self, NULL);
}
struct ril_connman *ril_connman_new()
{
static ConnManObject *instance = NULL;
if (instance) {
g_object_ref(instance);
return &instance->pub;
} else {
DBusError error;
DBusConnection *connection;
dbus_error_init(&error);
connection = dbus_bus_get(CONNMAN_BUS, NULL);
if (connection) {
instance = g_object_new(CONNMAN_OBJECT_TYPE, NULL);
connman_init(instance, connection);
dbus_connection_unref(connection);
g_object_add_weak_pointer(G_OBJECT(instance),
(gpointer*)(&instance));
return &instance->pub;
} else {
ofono_error("Unable to attach to connman bus: %s",
error.message);
dbus_error_free(&error);
return NULL;
}
}
}
struct ril_connman *ril_connman_ref(struct ril_connman *connman)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_object_ref(self);
return connman;
} else {
return NULL;
}
}
void ril_connman_unref(struct ril_connman *connman)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_object_unref(self);
}
}
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg)
{
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self) && G_LIKELY(cb)) {
/*
* We can't directly connect the provided callback because
* it expects the first parameter to point to public part
* of the object but glib will call it with ConnManObject
* as the first parameter. connman_object_property_changed()
* will do the conversion.
*/
ConnManClosure *closure = connman_closure_new();
GCClosure *cc = &closure->cclosure;
cc->closure.data = closure;
cc->callback = G_CALLBACK(connman_object_property_changed);
closure->callback = cb;
closure->user_data = arg;
return g_signal_connect_closure_by_id(self,
connman_object_signals[SIGNAL_PROPERTY_CHANGED],
connman_object_property_quark(p), &cc->closure, FALSE);
}
return 0;
}
void ril_connman_remove_handler(struct ril_connman *connman, gulong id)
{
if (G_LIKELY(id)) {
ConnManObject *self = connman_object_cast(connman);
if (G_LIKELY(self)) {
g_signal_handler_disconnect(self, id);
}
}
}
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
int n)
{
gutil_disconnect_handlers(connman_object_cast(connman), ids, n);
}
static void connman_object_init(ConnManObject *self)
{
self->techs = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
}
static void connman_object_finalize(GObject *object)
{
ConnManObject *self = CONNMAN_OBJECT(object);
connman_cancel_call(self);
g_hash_table_destroy(self->techs);
g_dbus_remove_watch(self->connection, self->service_watch);
g_dbus_remove_watch(self->connection, self->signal_watch);
dbus_connection_unref(self->connection);
G_OBJECT_CLASS(connman_object_parent_class)->finalize(object);
}
static void connman_object_class_init(ConnManObjectClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = connman_object_finalize;
connman_object_signals[SIGNAL_PROPERTY_CHANGED] =
g_signal_new(SIGNAL_PROPERTY_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,61 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_CONNMAN_H
#define RIL_CONNMAN_H
#include <gutil_misc.h>
struct ril_connman {
gboolean valid; /* TRUE if other fields are valid */
gboolean present; /* ConnMan is present on D-Bus */
gboolean tethering; /* At least one technology is tethering */
gboolean wifi_connected; /* WiFi network is connected */
};
enum ril_connman_property {
RIL_CONNMAN_PROPERTY_ANY,
RIL_CONNMAN_PROPERTY_VALID,
RIL_CONNMAN_PROPERTY_PRESENT,
RIL_CONNMAN_PROPERTY_TETHERING,
RIL_CONNMAN_PROPERTY_WIFI_CONNECTED,
RIL_CONNMAN_PROPERTY_COUNT
};
typedef void (*ril_connman_property_cb_t)(struct ril_connman *connman,
enum ril_connman_property property, void *arg);
struct ril_connman *ril_connman_new(void);
struct ril_connman *ril_connman_ref(struct ril_connman *connman);
void ril_connman_unref(struct ril_connman *connman);
gulong ril_connman_add_property_changed_handler(struct ril_connman *connman,
enum ril_connman_property p, ril_connman_property_cb_t cb, void *arg);
void ril_connman_remove_handler(struct ril_connman *connman, gulong id);
void ril_connman_remove_handlers(struct ril_connman *connman, gulong *ids,
int n);
#define ril_connman_remove_all_handlers(connman, ids) \
ril_connman_remove_handlers(connman, ids, G_N_ELEMENTS(ids))
#endif /* RIL_CONNMAN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,6 +1,10 @@
/*
* RIL constants adopted from AOSP's header:
*
* /hardware/ril/reference_ril/ril.h
*
* Copyright (C) 2013 Canonical Ltd.
* Copyright (C) 2013-2020 Jolla Ltd.
* Copyright (C) 2013-2017 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
@@ -15,10 +19,81 @@
#ifndef __RIL_CONSTANTS_H
#define __RIL_CONSTANTS_H 1
#include <ofono/ril-constants.h>
#define RIL_MAX_UUID_LENGTH 64
/* Error Codes */
enum ril_status {
RIL_E_SUCCESS = 0,
RIL_E_RADIO_NOT_AVAILABLE = 1,
RIL_E_GENERIC_FAILURE = 2,
RIL_E_PASSWORD_INCORRECT = 3,
RIL_E_SIM_PIN2 = 4,
RIL_E_SIM_PUK2 = 5,
RIL_E_REQUEST_NOT_SUPPORTED = 6,
RIL_E_CANCELLED = 7,
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
RIL_E_SMS_SEND_FAIL_RETRY = 10,
RIL_E_SIM_ABSENT = 11,
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
RIL_E_MODE_NOT_SUPPORTED = 13,
RIL_E_FDN_CHECK_FAILURE = 14,
RIL_E_ILLEGAL_SIM_OR_ME = 15,
RIL_E_MISSING_RESOURCE = 16,
RIL_E_NO_SUCH_ELEMENT = 17,
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
RIL_E_DIAL_MODIFIED_TO_SS = 19,
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
RIL_E_USSD_MODIFIED_TO_SS = 22,
RIL_E_USSD_MODIFIED_TO_USSD = 23,
RIL_E_SS_MODIFIED_TO_DIAL = 24,
RIL_E_SS_MODIFIED_TO_USSD = 25,
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
RIL_E_SS_MODIFIED_TO_SS = 27,
RIL_E_LCE_NOT_SUPPORTED = 36,
RIL_E_NO_MEMORY = 37,
RIL_E_INTERNAL_ERR = 38,
RIL_E_SYSTEM_ERR = 39,
RIL_E_MODEM_ERR = 40,
RIL_E_INVALID_STATE = 41,
RIL_E_NO_RESOURCES = 42,
RIL_E_SIM_ERR = 43,
RIL_E_INVALID_ARGUMENTS = 44,
RIL_E_INVALID_SIM_STATE = 45,
RIL_E_INVALID_MODEM_STATE = 46,
RIL_E_INVALID_CALL_ID = 47,
RIL_E_NO_SMS_TO_ACK = 48,
RIL_E_NETWORK_ERR = 49,
RIL_E_REQUEST_RATE_LIMITED = 50,
RIL_E_SIM_BUSY = 51,
RIL_E_SIM_FULL = 52,
RIL_E_NETWORK_REJECT = 53,
RIL_E_OPERATION_NOT_ALLOWED = 54,
RIL_E_EMPTY_RECORD = 55,
RIL_E_INVALID_SMS_FORMAT = 56,
RIL_E_ENCODING_ERR = 57,
RIL_E_INVALID_SMSC_ADDRESS = 58,
RIL_E_NO_SUCH_ENTRY = 59,
RIL_E_NETWORK_NOT_READY = 60,
RIL_E_NOT_PROVISIONED = 61,
RIL_E_NO_SUBSCRIPTION = 62,
RIL_E_NO_NETWORK_FOUND = 63,
RIL_E_DEVICE_IN_USE = 64,
RIL_E_ABORTED = 65,
RIL_E_INVALID_RESPONSE = 66
};
/* call states */
enum ril_call_state {
RIL_CALL_ACTIVE = 0,
RIL_CALL_HOLDING = 1,
RIL_CALL_DIALING = 2,
RIL_CALL_ALERTING = 3,
RIL_CALL_INCOMING = 4,
RIL_CALL_WAITING = 5
};
/* Radio state */
enum ril_radio_state {
RADIO_STATE_OFF = 0,
@@ -192,64 +267,30 @@ enum ril_call_fail_cause {
};
enum ril_data_call_fail_cause {
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_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,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
PDP_FAIL_NONE = 0,
PDP_FAIL_OPERATOR_BARRED = 0x08,
PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
PDP_FAIL_MISSING_UKNOWN_APN = 0x1B,
PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
PDP_FAIL_USER_AUTHENTICATION = 0x1D,
PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
PDP_FAIL_NSAPI_IN_USE = 0x23,
PDP_FAIL_REGULAR_DEACTIVATION = 0x24,
PDP_FAIL_ONLY_IPV4_ALLOWED = 0x32,
PDP_FAIL_ONLY_IPV6_ALLOWED = 0x33,
PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
PDP_FAIL_PROTOCOL_ERRORS = 0x6F,
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1,
PDP_FAIL_DATA_REGISTRATION_FAIL = -2,
PDP_FAIL_SIGNAL_LOST = -3,
PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,
PDP_FAIL_RADIO_POWER_OFF = -5,
PDP_FAIL_TETHERED_CALL_ACTIVE = -6,
PDP_FAIL_ERROR_UNSPECIFIED = 0xffff
};
/* RIL_REQUEST_DEACTIVATE_DATA_CALL parameter */
@@ -267,12 +308,6 @@ enum ril_data_profile {
RIL_DATA_PROFILE_INVALID = 0xFFFFFFFF
};
enum ril_profile_type {
RIL_PROFILE_COMMON = 0,
RIL_PROFILE_3GPP = 1,
RIL_PROFILE_3GPP2 = 2
};
enum ril_auth {
RIL_AUTH_NONE = 0,
RIL_AUTH_PAP = 1,
@@ -360,13 +395,191 @@ enum ril_cell_info_type {
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
};
enum ril_restricted_state {
RIL_RESTRICTED_STATE_NONE = 0x00,
RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
RIL_RESTRICTED_STATE_CS_NORMAL = 0x02,
RIL_RESTRICTED_STATE_CS_ALL = 0x04,
RIL_RESTRICTED_STATE_PS_ALL = 0x10
};
/* RIL Request Messages, ofono -> rild */
#define RIL_REQUEST_GET_SIM_STATUS 1
#define RIL_REQUEST_ENTER_SIM_PIN 2
#define RIL_REQUEST_ENTER_SIM_PUK 3
#define RIL_REQUEST_ENTER_SIM_PIN2 4
#define RIL_REQUEST_ENTER_SIM_PUK2 5
#define RIL_REQUEST_CHANGE_SIM_PIN 6
#define RIL_REQUEST_CHANGE_SIM_PIN2 7
#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
#define RIL_REQUEST_GET_CURRENT_CALLS 9
#define RIL_REQUEST_DIAL 10
#define RIL_REQUEST_GET_IMSI 11
#define RIL_REQUEST_HANGUP 12
#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
#define RIL_REQUEST_CONFERENCE 16
#define RIL_REQUEST_UDUB 17
#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
#define RIL_REQUEST_SIGNAL_STRENGTH 19
#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
#define RIL_REQUEST_OPERATOR 22
#define RIL_REQUEST_RADIO_POWER 23
#define RIL_REQUEST_DTMF 24
#define RIL_REQUEST_SEND_SMS 25
#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
#define RIL_REQUEST_SETUP_DATA_CALL 27
#define RIL_REQUEST_SIM_IO 28
#define RIL_REQUEST_SEND_USSD 29
#define RIL_REQUEST_CANCEL_USSD 30
#define RIL_REQUEST_GET_CLIR 31
#define RIL_REQUEST_SET_CLIR 32
#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
#define RIL_REQUEST_SET_CALL_FORWARD 34
#define RIL_REQUEST_QUERY_CALL_WAITING 35
#define RIL_REQUEST_SET_CALL_WAITING 36
#define RIL_REQUEST_SMS_ACKNOWLEDGE 37
#define RIL_REQUEST_GET_IMEI 38
#define RIL_REQUEST_GET_IMEISV 39
#define RIL_REQUEST_ANSWER 40
#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
#define RIL_REQUEST_SET_FACILITY_LOCK 43
#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
#define RIL_REQUEST_DTMF_START 49
#define RIL_REQUEST_DTMF_STOP 50
#define RIL_REQUEST_BASEBAND_VERSION 51
#define RIL_REQUEST_SEPARATE_CONNECTION 52
#define RIL_REQUEST_SET_MUTE 53
#define RIL_REQUEST_GET_MUTE 54
#define RIL_REQUEST_QUERY_CLIP 55
#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
#define RIL_REQUEST_DATA_CALL_LIST 57
#define RIL_REQUEST_RESET_RADIO 58
#define RIL_REQUEST_OEM_HOOK_RAW 59
#define RIL_REQUEST_OEM_HOOK_STRINGS 60
#define RIL_REQUEST_SCREEN_STATE 61
#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
#define RIL_REQUEST_SET_BAND_MODE 65
#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
#define RIL_REQUEST_STK_GET_PROFILE 67
#define RIL_REQUEST_STK_SET_PROFILE 68
#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
#define RIL_REQUEST_SET_LOCATION_UPDATES 76
#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
#define RIL_REQUEST_SET_TTY_MODE 80
#define RIL_REQUEST_QUERY_TTY_MODE 81
#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
#define RIL_REQUEST_CDMA_FLASH 84
#define RIL_REQUEST_CDMA_BURST_DTMF 85
#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
#define RIL_REQUEST_CDMA_SEND_SMS 87
#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
#define RIL_REQUEST_DEVICE_IDENTITY 98
#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
#define RIL_REQUEST_GET_SMSC_ADDRESS 100
#define RIL_REQUEST_SET_SMSC_ADDRESS 101
#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
#define RIL_REQUEST_ISIM_AUTHENTICATION 105
#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
#define RIL_REQUEST_VOICE_RADIO_TECH 108
#define RIL_REQUEST_GET_CELL_INFO_LIST 109
#define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110
#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
#define RIL_REQUEST_IMS_REGISTRATION_STATE 112
#define RIL_REQUEST_IMS_SEND_SMS 113
#define RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 114
#define RIL_REQUEST_SIM_OPEN_CHANNEL 115
#define RIL_REQUEST_SIM_CLOSE_CHANNEL 116
#define RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 117
#define RIL_REQUEST_NV_READ_ITEM 118
#define RIL_REQUEST_NV_WRITE_ITEM 119
#define RIL_REQUEST_NV_WRITE_CDMA_PRL 120
#define RIL_REQUEST_NV_RESET_CONFIG 121
/* SET_UICC_SUBSCRIPTION was 115 in v9 and 122 in v10 and later */
#define RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION 115
#define RIL_REQUEST_SET_UICC_SUBSCRIPTION 122
#define RIL_REQUEST_ALLOW_DATA 123
#define RIL_REQUEST_GET_HARDWARE_CONFIG 124
#define RIL_REQUEST_SIM_AUTHENTICATION 125
#define RIL_REQUEST_GET_DC_RT_INFO 126
#define RIL_REQUEST_SET_DC_RT_INFO_RATE 127
#define RIL_REQUEST_SET_DATA_PROFILE 128
#define RIL_REQUEST_SHUTDOWN 129
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
/* RIL Unsolicited Messages, rild -> ofono */
#define RIL_UNSOL_RESPONSE_BASE 1000
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
#define RIL_UNSOL_ON_USSD 1006
#define RIL_UNSOL_ON_USSD_REQUEST 1007
#define RIL_UNSOL_NITZ_TIME_RECEIVED 1008
#define RIL_UNSOL_SIGNAL_STRENGTH 1009
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
#define RIL_UNSOL_STK_SESSION_END 1012
#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
#define RIL_UNSOL_STK_CALL_SETUP 1015
#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
#define RIL_UNSOL_SIM_REFRESH 1017
#define RIL_UNSOL_CALL_RING 1018
#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
#define RIL_UNSOL_CDMA_CALL_WAITING 1025
#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
#define RIL_UNSOL_CDMA_INFO_REC 1027
#define RIL_UNSOL_OEM_HOOK_RAW 1028
#define RIL_UNSOL_RINGBACK_TONE 1029
#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
#define RIL_UNSOL_RIL_CONNECTED 1034
#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
#define RIL_UNSOL_CELL_INFO_LIST 1036
#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037
#define RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED 1038
#define RIL_UNSOL_SRVCC_STATE_NOTIFY 1039
#define RIL_UNSOL_HARDWARE_CONFIG_CHANGED 1040
#define RIL_UNSOL_DC_RT_INFO_CHANGED 1041
#define RIL_UNSOL_RADIO_CAPABILITY 1042
#define RIL_UNSOL_ON_SS 1043
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
/* A special request, ofono -> rild */
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
/* Suplementary services Service class*/
#define SERVICE_CLASS_NONE 0
@@ -375,19 +588,6 @@ 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 */
/*

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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,8 +13,6 @@
* GNU General Public License for more details.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_data.h"
#include "ril_radio.h"
#include "ril_network.h"
@@ -31,10 +28,11 @@
#include <grilio_parser.h>
#include <grilio_request.h>
#include "common.h" /* ACCESS_TECHNOLOGY_EUTRAN */
#define DATA_PROFILE_DEFAULT_STR "0"
/* Yes, it does sometimes take minutes in roaming */
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
#define PROTO_IP_STR "IP"
#define PROTO_IPV6_STR "IPV6"
#define PROTO_IPV4V6_STR "IPV4V6"
enum ril_data_priv_flags {
RIL_DATA_FLAG_NONE = 0x00,
@@ -78,13 +76,6 @@ enum ril_data_priv_flags {
typedef GObjectClass RilDataClass;
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
};
enum ril_data_settings_event_id {
SETTINGS_EVENT_IMSI_CHANGED,
SETTINGS_EVENT_PREF_MODE,
@@ -103,24 +94,18 @@ struct ril_data_priv {
struct ril_radio *radio;
struct ril_network *network;
struct ril_data_manager *dm;
struct ril_vendor *vendor;
enum ril_data_priv_flags flags;
enum ril_restricted_state restricted_state;
struct ril_vendor_hook *vendor_hook;
struct ril_data_request *req_queue;
struct ril_data_request *pending_req;
struct ril_data_options options;
gboolean use_data_profiles;
guint mms_data_profile_id;
guint slot;
char *log_prefix;
guint query_id;
gulong io_event_id[IO_EVENT_COUNT];
gulong io_event_id;
gulong settings_event_id[SETTINGS_EVENT_COUNT];
GHashTable* grab;
gboolean downgraded_tech; /* Status 55 workaround */
};
enum ril_data_signal {
@@ -171,7 +156,6 @@ struct ril_data_request {
struct ril_data_request_setup {
struct ril_data_request req;
guint profile_id;
char *apn;
char *username;
char *password;
@@ -191,9 +175,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)
{
@@ -292,6 +276,34 @@ static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
}
}
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
return PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return PROTO_IP_STR;
default:
return NULL;
}
}
int ril_data_protocol_to_ofono(const gchar *str)
{
if (str) {
if (!strcmp(str, PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(str, PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(str, PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
int version, GRilIoParser *rilp)
{
@@ -311,7 +323,7 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
prot = ril_protocol_to_ofono(prot_str);
prot = ril_data_protocol_to_ofono(prot_str);
if (prot < 0 && status == PDP_FAIL_NONE) {
ofono_error("Invalid protocol: %s", prot_str);
}
@@ -336,12 +348,12 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
return TRUE;
}
static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
int version, GRilIoParser *parser)
{
GRilIoParser copy = *parser;
struct ril_data_call *call = ril_data_call_new();
gboolean parsed = ril_vendor_data_call_parse(vendor, call,
gboolean parsed = ril_vendor_hook_data_call_parse(hook, call,
version, parser);
if (!parsed) {
@@ -357,7 +369,7 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
call->status, call->retry_time,
call->cid, call->active,
ril_protocol_from_ofono(call->prot),
ril_data_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu,
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
@@ -372,7 +384,7 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
}
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, struct ril_vendor *vendor,
guint len, struct ril_vendor_hook *hook,
enum ril_data_call_format format)
{
guint32 version, n, i;
@@ -393,7 +405,7 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call = ril_data_call_parse(vendor,
struct ril_data_call *call = ril_data_call_parse(hook,
list->version, &rilp);
if (call) {
@@ -441,7 +453,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 == l2->version && l1->num == l2->num) {
if (l1->version == l1->version && l1->num == l2->num) {
GSList *p1 = l1->calls;
GSList *p2 = l2->calls;
@@ -525,10 +537,6 @@ struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
static void ril_data_set_calls(struct ril_data *self,
struct ril_data_call_list *list)
{
struct ril_data_priv *priv = self->priv;
GHashTableIter it;
gpointer key;
if (!ril_data_call_list_equal(self->data_calls, list)) {
DBG("data calls changed");
ril_data_call_list_free(self->data_calls);
@@ -537,63 +545,6 @@ static void ril_data_set_calls(struct ril_data *self,
} else {
ril_data_call_list_free(list);
}
/* Clean up the grab table */
g_hash_table_iter_init(&it, priv->grab);
while (g_hash_table_iter_next(&it, &key, NULL)) {
const int cid = GPOINTER_TO_INT(key);
if (!ril_data_call_find(self->data_calls, cid)) {
g_hash_table_iter_remove(&it);
}
}
if (self->data_calls) {
GSList *l;
/* Disconnect stray calls (one at a time) */
for (l = self->data_calls->calls; l; l = l->next) {
struct ril_data_call *dc = l->data;
key = GINT_TO_POINTER(dc->cid);
if (!g_hash_table_contains(priv->grab, key)) {
DBG_(self, "stray call %u", dc->cid);
ril_data_call_deact_cid(self, dc->cid);
break;
}
}
}
}
static void ril_data_check_allowed(struct ril_data *self, gboolean was_allowed)
{
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_restricted_state_changed_cb(GRilIoChannel *io, guint event,
const void *data, guint len, void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
GRilIoParser rilp;
guint32 count, state;
GASSERT(event == RIL_UNSOL_RESTRICTED_STATE_CHANGED);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &count) && count == 1 &&
grilio_parser_get_uint32(&rilp, &state) &&
grilio_parser_at_end(&rilp)) {
struct ril_data_priv *priv = self->priv;
if (priv->restricted_state != state) {
const gboolean was_allowed = ril_data_allowed(self);
DBG_(self, "restricted state 0x%02x", state);
priv->restricted_state = state;
ril_data_check_allowed(self, was_allowed);
}
}
}
static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
@@ -611,7 +562,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->vendor, priv->options.data_call_format));
priv->vendor_hook, priv->options.data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -628,7 +579,7 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->vendor, priv->options.data_call_format));
priv->vendor_hook, priv->options.data_call_format));
} else {
/* RADIO_NOT_AVAILABLE == no calls */
ril_data_set_calls(self, NULL);
@@ -822,31 +773,6 @@ 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)
{
@@ -858,8 +784,8 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
struct ril_data_call *call = NULL;
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len, priv->vendor,
priv->options.data_call_format);
list = ril_data_call_list_parse(data, len,
priv->vendor_hook, priv->options.data_call_format);
}
if (list) {
@@ -871,49 +797,33 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
}
}
if (call) {
switch (call->status) {
if (call && call->status == PDP_FAIL_ERROR_UNSPECIFIED &&
setup->retry_count < priv->options.data_call_retry_limit) {
/*
* According to the comment from ril.h we should silently
* retry. First time we retry immediately and if that doesn't
* retry. First time we retry immediately and if that doedsn't
* work, then after certain delay.
*/
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;
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);
}
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);
@@ -937,7 +847,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
struct ril_data_request_setup *setup =
G_CAST(req, struct ril_data_request_setup, req);
struct ril_data_priv *priv = req->data->priv;
const char *proto_str = ril_protocol_from_ofono(setup->proto);
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
GRilIoRequest *ioreq;
int tech, auth = RIL_AUTH_NONE;
@@ -963,12 +873,25 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
}
if (setup->username && setup->username[0]) {
auth = ril_auth_method_from_ofono(setup->auth_method);
switch (setup->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
}
}
/* Give vendor code a chance to build a vendor specific packet */
ioreq = ril_vendor_data_call_req(priv->vendor, tech,
setup->profile_id, setup->apn, setup->username,
ioreq = ril_vendor_hook_data_call_req(priv->vendor_hook, tech,
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
setup->password, auth, proto_str);
if (!ioreq) {
@@ -976,7 +899,7 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
ioreq = grilio_request_new();
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
grilio_request_append_format(ioreq, "%d", tech);
grilio_request_append_format(ioreq, "%d", setup->profile_id);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
grilio_request_append_utf8(ioreq, setup->username);
grilio_request_append_utf8(ioreq, setup->password);
@@ -985,7 +908,6 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
}
GASSERT(!req->pending_id);
grilio_request_set_timeout(ioreq, SETUP_DATA_CALL_TIMEOUT);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
RIL_REQUEST_SETUP_DATA_CALL, ril_data_call_setup_cb,
NULL, setup);
@@ -1006,18 +928,12 @@ static void ril_data_call_setup_free(struct ril_data_request *req)
static struct ril_data_request *ril_data_call_setup_new(struct ril_data *data,
const struct ofono_gprs_primary_context *ctx,
enum ofono_gprs_context_type context_type,
ril_data_call_setup_cb_t cb, void *arg)
{
struct ril_data_priv *priv = data->priv;
struct ril_data_request_setup *setup =
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->apn = g_strdup(ctx->apn);
setup->username = g_strdup(ctx->username);
setup->password = g_strdup(ctx->password);
@@ -1128,11 +1044,6 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
return req;
}
static void ril_data_call_deact_cid(struct ril_data *data, int cid)
{
ril_data_request_queue(ril_data_call_deact_new(data, cid, NULL, NULL));
}
/*==========================================================================*
* ril_data_allow_request
*==========================================================================*/
@@ -1159,7 +1070,9 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
DBG_(data, "data off");
}
ril_data_check_allowed(data, was_allowed);
if (ril_data_allowed(data) != was_allowed) {
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
}
}
ril_data_request_finish(req);
@@ -1199,11 +1112,6 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
/*==========================================================================*
* ril_data
*==========================================================================*/
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
{
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
OFONO_RADIO_ACCESS_MODE_ANY;
}
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
ril_data_cb_t cb, void *arg)
@@ -1232,17 +1140,6 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
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;
@@ -1257,7 +1154,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config,
struct ril_vendor *vendor)
struct ril_vendor_hook *vendor_hook)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
@@ -1284,27 +1181,16 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
priv->log_prefix = (name && name[0]) ?
g_strconcat(name, " ", NULL) : g_strdup("");
priv->use_data_profiles = config->use_data_profiles;
priv->mms_data_profile_id = config->mms_data_profile_id;
priv->slot = config->slot;
priv->q = grilio_queue_new(io);
priv->io = grilio_channel_ref(io);
priv->dm = ril_data_manager_ref(dm);
priv->radio = ril_radio_ref(radio);
priv->network = ril_network_ref(network);
priv->vendor = ril_vendor_ref(vendor);
priv->io_event_id[IO_EVENT_DATA_CALL_LIST_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
ril_data_call_list_changed_cb,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
priv->io_event_id[IO_EVENT_RESTRICTED_STATE_CHANGED] =
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,
@@ -1378,8 +1264,6 @@ void ril_data_unref(struct ril_data *self)
gboolean ril_data_allowed(struct ril_data *self)
{
return G_LIKELY(self) &&
(self->priv->restricted_state &
RIL_RESTRICTED_STATE_PS_ALL) == 0 &&
(self->priv->flags &
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON)) ==
(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
@@ -1394,7 +1278,9 @@ static void ril_data_deactivate_all(struct ril_data *self)
struct ril_data_call *call = l->data;
if (call->status == PDP_FAIL_NONE) {
DBG_(self, "deactivating call %u", call->cid);
ril_data_call_deact_cid(self, call->cid);
ril_data_request_queue(
ril_data_call_deact_new(self,
call->cid, NULL, NULL));
}
}
}
@@ -1431,20 +1317,6 @@ 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;
@@ -1476,7 +1348,9 @@ static void ril_data_disallow(struct ril_data *self)
ril_data_power_update(self);
}
ril_data_check_allowed(self, was_allowed);
if (ril_data_allowed(self) != was_allowed) {
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
}
}
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
@@ -1556,11 +1430,10 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
struct ril_data_request *ril_data_call_setup(struct ril_data *self,
const struct ofono_gprs_primary_context *ctx,
enum ofono_gprs_context_type context_type,
ril_data_call_setup_cb_t cb, void *arg)
{
struct ril_data_request *req =
ril_data_call_setup_new(self, ctx, context_type, cb, arg);
ril_data_call_setup_new(self, ctx, cb, arg);
ril_data_request_queue(req);
return req;
@@ -1576,39 +1449,12 @@ struct ril_data_request *ril_data_call_deactivate(struct ril_data *self,
return req;
}
gboolean ril_data_call_grab(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie && ril_data_call_find(self->data_calls, cid)) {
struct ril_data_priv *priv = self->priv;
gpointer key = GINT_TO_POINTER(cid);
void *prev = g_hash_table_lookup(priv->grab, key);
if (!prev) {
g_hash_table_insert(priv->grab, key, cookie);
return TRUE;
} else {
return (prev == cookie);
}
}
return FALSE;
}
void ril_data_call_release(struct ril_data *self, int cid, void *cookie)
{
if (self && cookie) {
struct ril_data_priv *priv = self->priv;
g_hash_table_remove(priv->grab, GUINT_TO_POINTER(cid));
}
}
static void ril_data_init(struct ril_data *self)
{
struct ril_data_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
RIL_DATA_TYPE, struct ril_data_priv);
self->priv = priv;
priv->grab = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static void ril_data_dispose(GObject *object)
@@ -1616,14 +1462,26 @@ 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_handlers(priv->io, &priv->io_event_id, 1);
grilio_queue_cancel_all(priv->q, FALSE);
priv->query_id = 0;
ril_data_cancel_all_requests(self);
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;
}
dm->data_list = g_slist_remove(dm->data_list, self);
ril_data_manager_check_data(dm);
g_hash_table_destroy(priv->grab);
G_OBJECT_CLASS(ril_data_parent_class)->dispose(object);
}
@@ -1631,11 +1489,6 @@ 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);
@@ -1645,7 +1498,7 @@ static void ril_data_finalize(GObject *object)
ril_network_unref(priv->network);
ril_data_manager_unref(priv->dm);
ril_data_call_list_free(self->data_calls);
ril_vendor_unref(priv->vendor);
ril_vendor_hook_unref(priv->vendor_hook);
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
}
@@ -1719,41 +1572,35 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
{
GSList *l;
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;
if (ril_data_manager_handover(self)) {
struct ril_network *lte_network = NULL;
int non_gsm_count = 0;
/* Find a SIM for internet access */
/*
* Count number of SIMs for which non-GSM mode is selected
*/
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;
/* 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 (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
non_gsm_count++;
if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
!lte_network) {
lte_network = network;
}
}
}
/*
* If there's no SIM selected for internet access
* then use a slot with highest capabilities for LTE.
* then choose the first slot for LTE.
*/
if (!lte_network) {
lte_network = best_network;
struct ril_data *data = self->data_list->data;
lte_network = data->priv->network;
}
for (l= self->data_list; l; l = l->next) {
@@ -1762,7 +1609,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
ril_network_set_max_pref_mode(network,
(network == lte_network) ?
ril_data_max_mode(data) :
OFONO_RADIO_ACCESS_MODE_ANY :
OFONO_RADIO_ACCESS_MODE_GSM,
FALSE);
}
@@ -1772,7 +1619,7 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
ril_network_set_max_pref_mode(data->priv->network,
ril_data_max_mode(data), FALSE);
OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
}
}
}
@@ -1801,7 +1648,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
if (ril_data_manager_handover(self)) {
ril_network_set_max_pref_mode(priv->network,
ril_data_max_mode(data), TRUE);
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
}
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
@@ -1814,7 +1661,7 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
}
}
void ril_data_manager_check_data(struct ril_data_manager *self)
static void ril_data_manager_check_data(struct ril_data_manager *self)
{
/*
* Don't do anything if there any requests pending.

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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
@@ -55,8 +54,7 @@ struct ril_data {
};
enum ril_data_manager_flags {
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01,
RIL_DATA_MANAGER_FORCE_GSM_ON_OTHER_SLOTS = 0x02
RIL_DATA_MANAGER_3GLTE_HANDOVER = 0x01
};
enum ril_data_allow_data_opt {
@@ -79,11 +77,16 @@ 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);
@@ -97,7 +100,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config,
struct ril_vendor *vendor);
struct ril_vendor_hook *vendor_hook);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);
@@ -114,21 +117,20 @@ void ril_data_allow(struct ril_data *data, enum ril_data_role role);
struct ril_data_request;
struct ril_data_request *ril_data_call_setup(struct ril_data *data,
const struct ofono_gprs_primary_context *ctx,
enum ofono_gprs_context_type context_type,
ril_data_call_setup_cb_t cb, void *arg);
struct ril_data_request *ril_data_call_deactivate(struct ril_data *data,
int cid, ril_data_call_deactivate_cb_t cb, void *arg);
void ril_data_request_detach(struct ril_data_request *req);
void ril_data_request_cancel(struct ril_data_request *req);
gboolean ril_data_call_grab(struct ril_data *data, int cid, void *cookie);
void ril_data_call_release(struct ril_data *data, int cid, void *cookie);
void ril_data_call_free(struct ril_data_call *call);
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
int ril_data_protocol_to_ofono(const gchar *str);
/* Constructors of various kinds of RIL requests */
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);

View File

@@ -1,44 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* 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"
struct ril_devmon_io *ril_devmon_start_io(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info)
{
return devmon ? devmon->start_io(devmon, channel, cell_info) : NULL;
}
void ril_devmon_io_free(struct ril_devmon_io *devmon_io)
{
if (devmon_io) {
devmon_io->free(devmon_io);
}
}
void ril_devmon_free(struct ril_devmon *devmon)
{
if (devmon) {
devmon->free(devmon);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,80 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_DEVMON_H
#define RIL_DEVMON_H
#include "ril_cell_info.h"
/*
* Separate instance of ril_devmon is created for each modem.
* Device monitor is started after RIL has been connected.
*/
struct ril_devmon_io {
void (*free)(struct ril_devmon_io *devmon_io);
};
struct ril_devmon {
void (*free)(struct ril_devmon *devmon);
struct ril_devmon_io *(*start_io)(struct ril_devmon *devmon,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
};
/*
* 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(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(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(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,
GRilIoChannel *channel, struct sailfish_cell_info *cell_info);
void ril_devmon_io_free(struct ril_devmon_io *devmon_io);
void ril_devmon_free(struct ril_devmon *devmon);
#endif /* RIL_CONNMAN_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,92 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* 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 <grilio_channel.h>
typedef struct ril_devmon_ds {
struct ril_devmon pub;
struct ril_devmon *ss;
struct ril_devmon *ds;
} DevMon;
static inline DevMon *ril_devmon_auto_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
static struct ril_devmon_io *ril_devmon_auto_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *self = ril_devmon_auto_cast(devmon);
if (!self->ss) {
/* We have already chosen SEND_DEVICE_STATE method */
return ril_devmon_start_io(self->ds, io, cell_info);
} else if (!self->ds) {
/* We have already chosen SCREEN_STATE method */
return ril_devmon_start_io(self->ss, io, cell_info);
} else if (io->ril_version > 14 /* Covers binder implementation */) {
/* Choose SEND_DEVICE_STATE method */
DBG("%s: Will use SEND_DEVICE_STATE method", io->name);
ril_devmon_free(self->ss);
self->ss = NULL;
return ril_devmon_start_io(self->ds, io, cell_info);
} else {
/* Choose legacy SCREEN_STATE method */
DBG("%s: Will use SCREEN_STATE method", io->name);
ril_devmon_free(self->ds);
self->ds = NULL;
return ril_devmon_start_io(self->ss, io, cell_info);
}
}
static void ril_devmon_auto_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_auto_cast(devmon);
ril_devmon_free(self->ss);
ril_devmon_free(self->ds);
g_free(self);
}
struct ril_devmon *ril_devmon_auto_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
/*
* Allocate both implementations at startup. We need to do that
* early so that connections to D-Bus daemon and services are
* established before we drop privileges. This isn't much of
* an overhead because those implementation don't do much until
* we actually start the I/O (at which point we drop one of those).
*/
self->pub.free = ril_devmon_auto_free;
self->pub.start_io = ril_devmon_auto_start_io;
self->ss = ril_devmon_ss_new(config);
self->ds = ril_devmon_ds_new(config);
return &self->pub;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,104 +0,0 @@
/*
* 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:
*/

View File

@@ -1,355 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* 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 "ril_connman.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>
enum device_state_type {
/* Mirrors RIL_DeviceStateType from ril.h */
POWER_SAVE_MODE,
CHARGING_STATE,
LOW_DATA_EXPECTED
};
enum ril_devmon_ds_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ds_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ds_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
enum ril_devmon_ds_connman_event {
CONNMAN_EVENT_VALID,
CONNMAN_EVENT_TETHERING,
CONNMAN_EVENT_COUNT
};
typedef struct ril_devmon_ds {
struct ril_devmon pub;
struct ril_connman *connman;
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 {
struct ril_devmon_io pub;
struct ril_connman *connman;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
guint low_data_req_id;
guint charging_req_id;
gboolean low_data;
gboolean charging;
gboolean low_data_supported;
gboolean charging_supported;
gulong connman_event_id[CONNMAN_EVENT_COUNT];
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)
static inline DevMon *ril_devmon_ds_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
static inline DevMonIo *ril_devmon_ds_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ds_tethering_on(struct ril_connman *connman)
{
return connman->valid && connman->tethering;
}
static inline gboolean ril_devmon_ds_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ds_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static inline gboolean ril_devmon_ds_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static guint ril_devmon_ds_io_send_device_state(DevMonIo *self,
enum device_state_type type, gboolean state,
GRilIoChannelResponseFunc callback)
{
GRilIoRequest *req = grilio_request_array_int32_new(2, type, state);
const guint id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SEND_DEVICE_STATE, callback, NULL, self);
grilio_request_unref(req);
return id;
}
static void ril_devmon_ds_io_low_data_state_sent(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DevMonIo *self = user_data;
self->low_data_req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
DBG_(self, "LOW_DATA_EXPECTED state is not supported");
self->low_data_supported = FALSE;
}
}
static void ril_devmon_ds_io_charging_state_sent(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
DevMonIo *self = user_data;
self->charging_req_id = 0;
if (status == RIL_E_REQUEST_NOT_SUPPORTED) {
DBG_(self, "CHARGING state is not supported");
self->charging_supported = FALSE;
}
}
static void ril_devmon_ds_io_update_charging(DevMonIo *self)
{
const gboolean charging = ril_devmon_ds_charging(self->charger);
if (self->charging != charging) {
self->charging = charging;
DBG_(self, "Charging %s", charging ? "on" : "off");
if (self->charging_supported) {
grilio_channel_cancel_request(self->io,
self->charging_req_id, FALSE);
self->charging_req_id =
ril_devmon_ds_io_send_device_state(self,
CHARGING_STATE, charging,
ril_devmon_ds_io_charging_state_sent);
}
}
}
static void ril_devmon_ds_io_update_low_data(DevMonIo *self)
{
const gboolean low_data =
!ril_devmon_ds_tethering_on(self->connman) &&
!ril_devmon_ds_charging(self->charger) &&
!ril_devmon_ds_display_on(self->display);
if (self->low_data != low_data) {
self->low_data = low_data;
DBG_(self, "Low data is%s expected", low_data ? "" : " not");
if (self->low_data_supported) {
grilio_channel_cancel_request(self->io,
self->low_data_req_id, FALSE);
self->low_data_req_id =
ril_devmon_ds_io_send_device_state(self,
LOW_DATA_EXPECTED, low_data,
ril_devmon_ds_io_low_data_state_sent);
}
}
}
static void ril_devmon_ds_io_set_cell_info_update_interval(DevMonIo *self)
{
sailfish_cell_info_set_update_interval(self->cell_info,
(ril_devmon_ds_display_on(self->display) &&
(ril_devmon_ds_charging(self->charger) ||
ril_devmon_ds_battery_ok(self->battery))) ?
self->cell_info_interval_short_ms :
self->cell_info_interval_long_ms);
}
static void ril_devmon_ds_io_connman_cb(struct ril_connman *connman,
enum ril_connman_property property, void *user_data)
{
ril_devmon_ds_io_update_low_data((DevMonIo *)user_data);
}
static void ril_devmon_ds_io_battery_cb(MceBattery *battery, void *user_data)
{
ril_devmon_ds_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ds_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
ril_devmon_ds_io_update_low_data(self);
ril_devmon_ds_io_set_cell_info_update_interval(self);
}
static void ril_devmon_ds_io_charger_cb(MceCharger *charger, void *user_data)
{
DevMonIo *self = user_data;
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);
}
static void ril_devmon_ds_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ds_io_cast(devmon_io);
ril_connman_remove_all_handlers(self->connman, self->connman_event_id);
ril_connman_unref(self->connman);
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->low_data_req_id, FALSE);
grilio_channel_cancel_request(self->io, self->charging_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_ds_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ds = ril_devmon_ds_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ds_io_free;
self->low_data_supported = TRUE;
self->charging_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->connman = ril_connman_ref(ds->connman);
self->connman_event_id[CONNMAN_EVENT_VALID] =
ril_connman_add_property_changed_handler(self->connman,
RIL_CONNMAN_PROPERTY_VALID,
ril_devmon_ds_io_connman_cb, self);
self->connman_event_id[CONNMAN_EVENT_TETHERING] =
ril_connman_add_property_changed_handler(self->connman,
RIL_CONNMAN_PROPERTY_TETHERING,
ril_devmon_ds_io_connman_cb, self);
self->battery = mce_battery_ref(ds->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ds_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ds_io_battery_cb, self);
self->charger = mce_charger_ref(ds->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ds_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ds_io_charger_cb, self);
self->display = mce_display_ref(ds->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ds_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
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);
return &self->pub;
}
static void ril_devmon_ds_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ds_cast(devmon);
ril_connman_unref(self->connman);
mce_battery_unref(self->battery);
mce_charger_unref(self->charger);
mce_display_unref(self->display);
g_free(self);
}
struct ril_devmon *ril_devmon_ds_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ds_free;
self->pub.start_io = ril_devmon_ds_start_io;
self->connman = ril_connman_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;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,261 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 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
* 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>
enum ril_devmon_ss_battery_event {
BATTERY_EVENT_VALID,
BATTERY_EVENT_STATUS,
BATTERY_EVENT_COUNT
};
enum ril_devmon_ss_charger_event {
CHARGER_EVENT_VALID,
CHARGER_EVENT_STATE,
CHARGER_EVENT_COUNT
};
enum ril_devmon_ss_display_event {
DISPLAY_EVENT_VALID,
DISPLAY_EVENT_STATE,
DISPLAY_EVENT_COUNT
};
typedef struct ril_devmon_ss {
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_ss_io {
struct ril_devmon_io pub;
struct sailfish_cell_info *cell_info;
MceBattery *battery;
MceCharger *charger;
MceDisplay *display;
GRilIoChannel *io;
gboolean display_on;
gboolean screen_state_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;
inline static DevMon *ril_devmon_ss_cast(struct ril_devmon *pub)
{
return G_CAST(pub, DevMon, pub);
}
inline static DevMonIo *ril_devmon_ss_io_cast(struct ril_devmon_io *pub)
{
return G_CAST(pub, DevMonIo, pub);
}
static inline gboolean ril_devmon_ss_battery_ok(MceBattery *battery)
{
return battery->valid && battery->status >= MCE_BATTERY_OK;
}
static inline gboolean ril_devmon_ss_charging(MceCharger *charger)
{
return charger->valid && charger->state == MCE_CHARGER_ON;
}
static gboolean ril_devmon_ss_display_on(MceDisplay *display)
{
return display->valid && display->state != MCE_DISPLAY_STATE_OFF;
}
static void ril_devmon_ss_io_state_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("RIL_REQUEST_SCREEN_STATE is not supported");
self->screen_state_supported = FALSE;
}
}
static void ril_devmon_ss_io_send_screen_state(DevMonIo *self)
{
/*
* RIL_REQUEST_SCREEN_STATE (deprecated on 2017-01-10)
*
* ((int *)data)[0] is == 1 for "Screen On"
* ((int *)data)[0] is == 0 for "Screen Off"
*/
if (self->screen_state_supported) {
GRilIoRequest *req = grilio_request_array_int32_new(1,
self->display_on);
grilio_channel_cancel_request(self->io, self->req_id, FALSE);
self->req_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SCREEN_STATE, ril_devmon_ss_io_state_sent,
NULL, self);
grilio_request_unref(req);
}
}
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))) ?
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)
{
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ss_io_charger_cb(MceCharger *charger, void *user_data)
{
ril_devmon_ss_io_set_cell_info_update_interval(user_data);
}
static void ril_devmon_ss_io_display_cb(MceDisplay *display, void *user_data)
{
DevMonIo *self = user_data;
const gboolean display_on = ril_devmon_ss_display_on(display);
if (self->display_on != display_on) {
self->display_on = display_on;
ril_devmon_ss_io_send_screen_state(self);
ril_devmon_ss_io_set_cell_info_update_interval(self);
}
}
static void ril_devmon_ss_io_free(struct ril_devmon_io *devmon_io)
{
DevMonIo *self = ril_devmon_ss_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_ss_start_io(struct ril_devmon *devmon,
GRilIoChannel *io, struct sailfish_cell_info *cell_info)
{
DevMon *ss = ril_devmon_ss_cast(devmon);
DevMonIo *self = g_new0(DevMonIo, 1);
self->pub.free = ril_devmon_ss_io_free;
self->screen_state_supported = TRUE;
self->io = grilio_channel_ref(io);
self->cell_info = sailfish_cell_info_ref(cell_info);
self->battery = mce_battery_ref(ss->battery);
self->battery_event_id[BATTERY_EVENT_VALID] =
mce_battery_add_valid_changed_handler(self->battery,
ril_devmon_ss_io_battery_cb, self);
self->battery_event_id[BATTERY_EVENT_STATUS] =
mce_battery_add_status_changed_handler(self->battery,
ril_devmon_ss_io_battery_cb, self);
self->charger = mce_charger_ref(ss->charger);
self->charger_event_id[CHARGER_EVENT_VALID] =
mce_charger_add_valid_changed_handler(self->charger,
ril_devmon_ss_io_charger_cb, self);
self->charger_event_id[CHARGER_EVENT_STATE] =
mce_charger_add_state_changed_handler(self->charger,
ril_devmon_ss_io_charger_cb, self);
self->display = mce_display_ref(ss->display);
self->display_on = ril_devmon_ss_display_on(self->display);
self->display_event_id[DISPLAY_EVENT_VALID] =
mce_display_add_valid_changed_handler(self->display,
ril_devmon_ss_io_display_cb, self);
self->display_event_id[DISPLAY_EVENT_STATE] =
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;
}
static void ril_devmon_ss_free(struct ril_devmon *devmon)
{
DevMon *self = ril_devmon_ss_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_ss_new(const struct ril_slot_config *config)
{
DevMon *self = g_new0(DevMon, 1);
self->pub.free = ril_devmon_ss_free;
self->pub.start_io = ril_devmon_ss_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:
*/

View File

@@ -1,267 +0,0 @@
/*
* 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:
*/

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,8 +13,6 @@
* GNU General Public License for more details.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_ecclist.h"
#include "ril_log.h"
@@ -50,53 +47,6 @@ 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;
@@ -108,9 +58,16 @@ 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 = ril_ecclist_parse(content);
} else {
list = g_strsplit(content, ",", 0);
for (ptr = list; *ptr; ptr++) {
*ptr = g_strstrip(*ptr);
}
gutil_strv_sort(list, TRUE);
} else if (error) {
DBG("%s: %s", priv->path, GERRMSG(error));
g_error_free(error);
}
@@ -132,8 +89,7 @@ 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);
}
@@ -165,9 +121,10 @@ 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);
DBG("%swatching %s", priv->file_watch ? "" : "not ",
priv->path);
ril_ecclist_update(self);
if (priv->file_watch) {
DBG("watching %s", priv->path);
ril_ecclist_update(self);
}
}
if (mask & IN_IGNORED) {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2015-2018 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
@@ -88,7 +88,6 @@ static int ril_gprs_context_address_family(const char *addr)
static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
{
if (gcd->active_call) {
ril_data_call_release(gcd->data, gcd->active_call->cid, gcd);
ril_data_call_free(gcd->active_call);
gcd->active_call = NULL;
}
@@ -112,7 +111,6 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
}
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
ril_data_call_grab(gcd->data, call->cid, gcd);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -468,7 +466,6 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
gcd->activate.cb = cb;
gcd->activate.data = data;
gcd->activate.req = ril_data_call_setup(gcd->data, ctx,
__ofono_gprs_context_get_assigned_type(gc),
ril_gprs_context_activate_primary_cb, gcd);
}
@@ -483,23 +480,24 @@ static void ril_gprs_context_deactivate_primary_cb(struct ril_data *data,
* invoked and gcd->deactivate.req will be NULL.
*/
if (gcd->deactivate.req) {
struct ofono_error error;
ofono_gprs_context_cb_t cb = gcd->deactivate.cb;
gpointer cb_data = gcd->deactivate.data;
if (ril_status == RIL_E_SUCCESS) {
GASSERT(gcd->active_call);
ril_error_init_ok(&error);
ofono_info("Deactivated data call");
} else {
ril_error_init_failure(&error);
ofono_error("Deactivate failure: %s",
ril_error_to_string(ril_status));
}
memset(&gcd->deactivate, 0, sizeof(gcd->deactivate));
if (cb) {
struct ofono_error error;
ril_gprs_context_free_active_call(gcd);
cb(ril_error_ok(&error), cb_data);
cb(&error, cb_data);
return;
}
}
@@ -513,7 +511,7 @@ static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
GASSERT(gcd->active_ctx_cid == id);
GASSERT(gcd->active_call && gcd->active_ctx_cid == id);
ofono_info("Deactivating context: %u", id);
if (gcd->active_call && gcd->active_ctx_cid == id) {

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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,15 +19,15 @@
#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"
#include "ofono.h"
#include <ofono/watch.h>
#include "sailfish_watch.h"
#define MAX_PDP_CONTEXTS (2)
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
enum ril_modem_power_state {
@@ -44,15 +43,7 @@ enum ril_modem_online_state {
GOING_OFFLINE
};
enum ril_modem_watch_event {
WATCH_IMSI,
WATCH_ICCID,
WATCH_SIM_STATE,
WATCH_EVENT_COUNT
};
struct ril_modem_online_request {
const char *name;
ofono_modem_online_cb_t cb;
struct ril_modem_data *md;
void *data;
@@ -61,16 +52,13 @@ struct ril_modem_online_request {
struct ril_modem_data {
struct ril_modem modem;
struct ofono_watch *watch;
struct sailfish_watch *watch;
GRilIoQueue *q;
char *log_prefix;
char *imeisv;
char *imei;
char *ecclist_file;
gulong watch_event_id[WATCH_EVENT_COUNT];
char* last_known_iccid;
char* reset_iccid;
gulong imsi_event_id;
guint online_check_id;
enum ril_modem_power_state power_state;
@@ -134,20 +122,6 @@ void ril_modem_delete(struct ril_modem *md)
}
}
static void ril_modem_online_request_done(struct ril_modem_online_request *req)
{
if (req->cb) {
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *data = req->data;
req->cb = NULL;
req->data = NULL;
DBG_(req->md, "%s", req->name);
cb(ril_error_ok(&error), data);
}
}
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
{
if (req->timeout_id) {
@@ -155,20 +129,28 @@ static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
req->timeout_id = 0;
}
ril_modem_online_request_done(req);
if (req->cb) {
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *data = req->data;
req->cb = NULL;
req->data = NULL;
cb(ril_error_ok(&error), data);
}
}
static void ril_modem_update_online_state(struct ril_modem_data *md)
{
switch (md->modem.radio->state) {
case RADIO_STATE_ON:
DBG_(md, "online");
DBG("online");
ril_modem_online_request_ok(&md->set_online);
break;
case RADIO_STATE_OFF:
case RADIO_STATE_UNAVAILABLE:
DBG_(md, "offline");
DBG("offline");
ril_modem_online_request_ok(&md->set_offline);
break;
@@ -188,11 +170,17 @@ static void ril_modem_update_online_state(struct ril_modem_data *md)
static gboolean ril_modem_online_request_timeout(gpointer data)
{
struct ril_modem_online_request *req = data;
struct ofono_error error;
ofono_modem_online_cb_t cb = req->cb;
void *cb_data = req->data;
GASSERT(req->timeout_id);
GASSERT(cb);
req->timeout_id = 0;
DBG_(req->md, "%s", req->name);
ril_modem_online_request_done(req);
req->cb = NULL;
req->data = NULL;
cb(ril_error_failure(&error), cb_data);
ril_modem_update_online_state(req->md);
return G_SOURCE_REMOVE;
@@ -218,21 +206,22 @@ 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;
struct ofono_radio_settings *rs = ril_modem_radio_settings(m);
if (md->watch->imsi) {
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
/* radio-settings.c assumes that IMSI is available */
if (!rs) {
if (!ril_modem_radio_settings(m)) {
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 */
DBG_(md, "radio settings interface is already gone");
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");
}
}
}
@@ -241,10 +230,11 @@ 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);
}
static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
{
struct ril_modem_data *md = data;
@@ -252,32 +242,6 @@ static void ril_modem_imsi_cb(struct ofono_watch *watch, void *data)
ril_modem_update_radio_settings(md);
}
static void ril_modem_iccid_cb(struct ofono_watch *watch, void *data)
{
struct ril_modem_data *md = data;
GASSERT(md->watch == watch);
if (watch->iccid) {
g_free(md->last_known_iccid);
md->last_known_iccid = g_strdup(watch->iccid);
DBG_(md, "%s", md->last_known_iccid);
}
}
static void ril_modem_sim_state_cb(struct ofono_watch *watch, void *data)
{
struct ril_modem_data *md = data;
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
GASSERT(md->watch == watch);
if (state == OFONO_SIM_STATE_RESETTING) {
g_free(md->reset_iccid);
md->reset_iccid = md->last_known_iccid;
md->last_known_iccid = NULL;
DBG_(md, "%s is resetting", md->reset_iccid);
}
}
static void ril_modem_pre_sim(struct ofono_modem *modem)
{
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
@@ -304,22 +268,15 @@ 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) {
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
};
int i;
/* Create a context for each type */
for (i = 0; i < G_N_ELEMENTS(ap_types); i++) {
for (i = 0; i < MAX_PDP_CONTEXTS; 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);
}
}
@@ -327,16 +284,8 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
ofono_phonebook_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
ofono_message_waiting_register(ofono_message_waiting_create(modem));
if (md->modem.config.enable_stk) {
if (!md->reset_iccid ||
g_strcmp0(md->reset_iccid, md->watch->iccid)) {
/* This SIM was never reset */
ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
} else {
ofono_warn("Disabling STK after SIM reset");
}
}
if (md->modem.config.enable_cbs) {
ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
}
@@ -421,14 +370,12 @@ 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);
ofono_watch_remove_all_handlers(md->watch, md->watch_event_id);
ofono_watch_unref(md->watch);
sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
sailfish_watch_unref(md->watch);
if (md->online_check_id) {
g_source_remove(md->online_check_id);
@@ -442,7 +389,6 @@ 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);
@@ -450,8 +396,6 @@ static void ril_modem_remove(struct ofono_modem *ofono)
grilio_channel_unref(modem->io);
grilio_queue_cancel_all(md->q, FALSE);
grilio_queue_unref(md->q);
g_free(md->last_known_iccid);
g_free(md->reset_iccid);
g_free(md->ecclist_file);
g_free(md->log_prefix);
g_free(md->imeisv);
@@ -464,7 +408,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_vendor *vendor,
struct ril_sim_settings *settings,
struct sailfish_cell_info *cell_info)
{
/* Skip the slash from the path, it looks like "/ril_0" */
@@ -491,7 +435,6 @@ 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);
@@ -500,30 +443,19 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
modem->data = ril_data_ref(data);
modem->io = grilio_channel_ref(io);
md->q = grilio_queue_new(io);
md->watch = ofono_watch_new(path);
md->last_known_iccid = g_strdup(md->watch->iccid);
md->watch = sailfish_watch_new(path);
md->watch_event_id[WATCH_IMSI] =
ofono_watch_add_imsi_changed_handler(md->watch,
md->imsi_event_id =
sailfish_watch_add_imsi_changed_handler(md->watch,
ril_modem_imsi_cb, md);
md->watch_event_id[WATCH_ICCID] =
ofono_watch_add_iccid_changed_handler(md->watch,
ril_modem_iccid_cb, md);
md->watch_event_id[WATCH_SIM_STATE] =
ofono_watch_add_sim_state_changed_handler(md->watch,
ril_modem_sim_state_cb, md);
md->set_online.name = "online";
md->set_online.md = md;
md->set_offline.name = "offline";
md->set_offline.md = md;
ofono_modem_set_data(ofono, md);
err = ofono_modem_register(ofono);
if (!err) {
ril_radio_power_cycle(modem->radio);
GASSERT(io->connected);
if (config->radio_power_cycle) {
ril_radio_power_cycle(modem->radio);
}
/*
* ofono_modem_reset sets Powered to TRUE without

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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
@@ -17,17 +16,11 @@
#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"
#include <ofono/watch.h>
#define REGISTRATION_MAX_RETRIES (2)
enum ril_netreg_events {
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
NETREG_RIL_EVENT_SIGNAL_STRENGTH,
@@ -43,21 +36,14 @@ 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 {
@@ -75,8 +61,6 @@ struct ril_netreg_cbd {
#define ril_netreg_cbd_free g_free
#define DBG_(nd,fmt,args...) DBG("%s" fmt, (nd)->log_prefix, ##args)
static inline struct ril_netreg *ril_netreg_get_data(struct ofono_netreg *ofono)
{
return ofono ? ofono_netreg_get_data(ofono) : NULL;
@@ -125,7 +109,7 @@ static gboolean ril_netreg_status_notify_cb(gpointer user_data)
struct ril_netreg *nd = user_data;
const struct ril_registration_state *reg = &nd->network->voice;
DBG_(nd, "");
DBG("%s", nd->log_prefix);
GASSERT(nd->notify_id);
nd->notify_id = 0;
ofono_netreg_status_notify(nd->netreg,
@@ -140,9 +124,9 @@ static void ril_netreg_status_notify(struct ril_network *net, void *user_data)
/* Coalesce multiple notifications into one */
if (nd->notify_id) {
DBG_(nd, "notification aready queued");
DBG("%snotification aready queued", nd->log_prefix);
} else {
DBG_(nd, "queuing notification");
DBG("%squeuing notification", nd->log_prefix);
nd->notify_id = g_idle_add(ril_netreg_status_notify_cb, nd);
}
}
@@ -154,7 +138,7 @@ static void ril_netreg_registration_status(struct ofono_netreg *netreg,
const struct ril_registration_state *reg = &nd->network->voice;
struct ofono_error error;
DBG_(nd, "");
DBG("%s", nd->log_prefix);
cb(ril_error_ok(&error),
ril_netreg_check_status(nd, reg->status),
reg->lac, reg->ci, reg->access_tech, data);
@@ -167,7 +151,7 @@ static gboolean ril_netreg_current_operator_cb(void *user_data)
ofono_netreg_operator_cb_t cb = cbd->cb.operator;
struct ofono_error error;
DBG_(nd, "");
DBG("%s", nd->log_prefix);
GASSERT(nd->current_operator_id);
nd->current_operator_id = 0;
@@ -197,74 +181,11 @@ 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;
@@ -306,23 +227,21 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
}
/* Set the proper status */
if (!status) {
op->status = OPERATOR_STATUS_UNKNOWN;
} else if (!strcmp(status, "available")) {
op->status = OPERATOR_STATUS_AVAILABLE;
if (!strcmp(status, "available")) {
list[i].status = OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) {
op->status = OPERATOR_STATUS_CURRENT;
list[i].status = OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) {
op->status = OPERATOR_STATUS_FORBIDDEN;
list[i].status = OPERATOR_STATUS_FORBIDDEN;
} else {
op->status = OPERATOR_STATUS_UNKNOWN;
list[i].status = OPERATOR_STATUS_UNKNOWN;
}
op->tech = -1;
ok = ril_parse_mcc_mnc(numeric, op);
if (ok) {
if (op->tech < 0) {
op->tech = nd->network->voice.access_tech;
op->tech = cbd->nd->network->voice.access_tech;
}
DBG("[operator=%s, %s, %s, status: %s]", op->name,
op->mcc, op->mnc, status);
@@ -337,7 +256,6 @@ 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);
@@ -372,57 +290,16 @@ 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();
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
ril_netreg_query_register_auto_cb, ril_netreg_cbd_free,
ofono_info("nw select automatic");
grilio_queue_send_request_full(nd->q, NULL,
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_register_manual(struct ofono_netreg *netreg,
@@ -431,12 +308,9 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
GRilIoRequest *req = grilio_request_new();
const char *suffix = nd->network_selection_manual_0 ? "+0" : "";
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, nd->network_selection_timeout);
grilio_request_set_retry(req, 0, REGISTRATION_MAX_RETRIES);
ofono_info("nw select manual: %s%s", mcc, mnc);
grilio_request_append_format(req, "%s%s+0", mcc, mnc);
grilio_queue_send_request_full(nd->q, req,
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
ril_netreg_register_cb, ril_netreg_cbd_free,
@@ -444,92 +318,75 @@ static void ril_netreg_register_manual(struct ofono_netreg *netreg,
grilio_request_unref(req);
}
static int ril_netreg_qdbm_to_percentage(struct ril_netreg *nd, int qdbm)
{
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 (qdbm <= min_qdbm) ? 1 :
(qdbm >= max_qdbm) ? 100 :
(100 * (qdbm - min_qdbm) / (max_qdbm - min_qdbm));
}
static int ril_netreg_get_signal_strength(struct ril_netreg *nd,
const void *data, guint len)
static int ril_netreg_get_signal_strength(const void *data, guint len)
{
GRilIoParser rilp;
struct ril_vendor_signal_strength signal;
int gw_signal = 0, cdma_dbm = 0, evdo_dbm = 0, lte_signal = 0;
int rsrp = 0;
grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
if (!ril_vendor_signal_strength_parse(nd->vendor, &signal, &rilp)) {
gint32 rsrp = 0, tdscdma_dbm = 0;
/* RIL_SignalStrength_v6 */
/* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &gw_signal);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
/* Apply default parsing algorithm */
grilio_parser_init(&rilp, data, len);
signal.gsm = INT_MAX;
signal.lte = INT_MAX;
signal.qdbm = 0;
/* CDMA_SignalStrength */
grilio_parser_get_int32(&rilp, &cdma_dbm);
grilio_parser_get_int32(&rilp, NULL); /* ecio */
/* GW_SignalStrength */
grilio_parser_get_int32(&rilp, &signal.gsm);
grilio_parser_get_int32(&rilp, NULL); /* bitErrorRate */
/* EVDO_SignalStrength */
grilio_parser_get_int32(&rilp, &evdo_dbm);
grilio_parser_get_int32(&rilp, NULL); /* ecio */
grilio_parser_get_int32(&rilp, NULL); /* signalNoiseRatio */
/* CDMA_SignalStrength */
grilio_parser_get_int32(&rilp, NULL); /* dbm */
grilio_parser_get_int32(&rilp, NULL); /* ecio */
/* LTE_SignalStrength */
grilio_parser_get_int32(&rilp, &lte_signal);
grilio_parser_get_int32(&rilp, &rsrp);
/* The rest is ignored */
/* 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);
/* 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", gw_signal,
cdma_dbm, evdo_dbm, lte_signal);
} else {
DBG("gw: %d, cdma: %d, evdo: %d, lte: %d rsrp: %d", gw_signal,
cdma_dbm, evdo_dbm, lte_signal, rsrp);
}
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 (signal.gsm >= 1 && signal.gsm <= 31) {
if (gw_signal >= 1 && gw_signal <= 31) {
/* Valid values are (0-31, 99) as defined in TS 27.007 */
return (signal.gsm * 100) / 31;
return (gw_signal * 100) / 31;
}
/* Valid values are (0-31, 99) as defined in TS 27.007 */
if (signal.lte >= 0 && signal.lte <= 31) {
return (signal.lte * 100) / 31;
if (lte_signal >= 0 && lte_signal <= 31) {
return (lte_signal * 100) / 31;
}
if (signal.qdbm < 0) {
return ril_netreg_qdbm_to_percentage(nd, signal.qdbm);
} else if (signal.gsm == 0) {
return 0;
} else {
return -1;
/* RSRP range: 44 to 140 dBm as defined in 3GPP TS 36.133 */
if (lte_signal == 99 && rsrp >= 44 && rsrp <= 140) {
return 140 - rsrp;
}
/* If we've got zero strength and no valid RSRP, then so be it */
if (gw_signal == 0) {
return 0;
}
/* 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,
@@ -539,11 +396,9 @@ 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(nd, data, len);
DBG_(nd, "%d", strength);
if (strength >= 0) {
ofono_netreg_strength_notify(nd->netreg, strength);
}
strength = ril_netreg_get_signal_strength(data, len);
DBG("%d", strength);
ofono_netreg_strength_notify(nd->netreg, strength);
}
static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
@@ -554,8 +409,8 @@ static void ril_netreg_strength_cb(GRilIoChannel *io, int status,
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
cb(ril_error_ok(&error), ril_netreg_get_signal_strength
(cbd->nd, data, len), cbd->data);
int strength = ril_netreg_get_signal_strength(data, len);
cb(ril_error_ok(&error), strength, cbd->data);
} else {
ofono_error("Failed to retrive the signal strength: %s",
ril_error_to_string(status));
@@ -590,7 +445,7 @@ static void ril_netreg_nitz_notify(GRilIoChannel *io, guint ril_event,
grilio_parser_init(&rilp, data, len);
nitz = grilio_parser_get_utf8(&rilp);
DBG_(nd, "%s", nitz);
DBG("%s", nitz);
/*
* Format: yy/mm/dd,hh:mm:ss(+/-)tz[,ds]
@@ -657,23 +512,14 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
{
struct ril_modem *modem = data;
struct ril_netreg *nd = g_new0(struct ril_netreg, 1);
const struct ril_slot_config *config = &modem->config;
guint slot = ril_modem_slot(modem);
nd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
DBG_(nd, "%p", netreg);
DBG("[%u] %p", slot, netreg);
nd->log_prefix = g_strdup_printf("%s_%u ", RILMODEM_DRIVER, slot);
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);
@@ -683,8 +529,9 @@ static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
static void ril_netreg_remove(struct ofono_netreg *netreg)
{
struct ril_netreg *nd = ril_netreg_get_data(netreg);
unsigned int i;
DBG_(nd, "%p", netreg);
DBG("%p", netreg);
grilio_queue_cancel_all(nd->q, FALSE);
ofono_netreg_set_data(netreg, NULL);
@@ -700,12 +547,14 @@ 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);
for (i=0; i<G_N_ELEMENTS(nd->network_event_id); i++) {
ril_network_remove_handler(nd->network, nd->network_event_id[i]);
}
ril_network_unref(nd->network);
ril_vendor_unref(nd->vendor);
grilio_channel_remove_all_handlers(nd->io, nd->ril_event_id);
grilio_channel_remove_handlers(nd->io, nd->ril_event_id,
G_N_ELEMENTS(nd->ril_event_id));
grilio_channel_unref(nd->io);
grilio_queue_unref(nd->q);
g_free(nd->log_prefix);

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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,7 +21,6 @@
#include <glib-object.h>
struct ofono_network_operator;
struct ril_radio_caps;
struct ril_registration_state {
int status; /* enum network_registration_status */
@@ -44,24 +42,20 @@ 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,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card,
struct ril_sim_settings *settings,
const struct ril_slot_config *ril_slot_config,
struct ril_vendor *vendor);
struct ril_sim_settings *settings);
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);
enum ofono_radio_access_mode ril_network_max_supported_mode
(struct ril_network *self);
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
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);
@@ -71,6 +65,8 @@ 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);

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2017 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
@@ -33,11 +32,6 @@ 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)
{
@@ -46,13 +40,20 @@ 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);
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
&data, len);
for (i = 0; i < len; i++) {
guchar byte = bytes[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
&byte);
}
dbus_message_iter_close_container(&it, &array);
} else if (ril_status == GRILIO_STATUS_TIMEOUT) {
DBG("Timed out");
@@ -62,7 +63,7 @@ static void ril_oem_raw_send_cb(GRilIoChannel *io, int ril_status,
reply = __ofono_error_failed(msg);
}
g_dbus_send_message(ofono_dbus_get_connection(), reply);
__ofono_dbus_pending_reply(&msg, reply);
}
static DBusMessage *ril_oem_raw_send(DBusConnection *conn, DBusMessage *msg,
@@ -71,12 +72,6 @@ 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) {
@@ -99,7 +94,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,
ril_oem_raw_send_done, dbus_message_ref(msg));
NULL, dbus_message_ref(msg));
grilio_request_unref(req);
return NULL;
} else {

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2015-2017 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
@@ -53,7 +52,6 @@ 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;
@@ -72,7 +70,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_vendor *vendor,
struct ril_sim_settings *settings,
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);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2015-2017 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,8 +13,6 @@
* GNU General Public License for more details.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_radio.h"
#include "ril_util.h"
#include "ril_log.h"
@@ -73,16 +71,14 @@ G_DEFINE_TYPE(RilRadio, ril_radio, G_TYPE_OBJECT)
#define RIL_RADIO_TYPE (ril_radio_get_type())
#define RIL_RADIO(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj,RIL_RADIO_TYPE,RilRadio))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on);
static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
return (self->online || g_hash_table_size(priv->req_table) > 0) &&
!priv->power_cycle;
return self->online && !priv->power_cycle &&
g_hash_table_size(priv->req_table) > 0;
}
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
@@ -106,7 +102,7 @@ static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
DBG_(self, "");
DBG("%s", priv->log_prefix);
GASSERT(priv->retry_id);
priv->retry_id = 0;
ril_radio_submit_power_request(self,
@@ -120,7 +116,7 @@ static void ril_radio_cancel_retry(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (priv->retry_id) {
DBG_(self, "retry cancelled");
DBG("%sretry cancelled", priv->log_prefix);
g_source_remove(priv->retry_id);
priv->retry_id = 0;
}
@@ -133,8 +129,8 @@ static void ril_radio_check_state(struct ril_radio *self)
if (!priv->pending_id) {
gboolean should_be_on = ril_radio_power_should_be_on(self);
if (ril_radio_state_on(priv->last_known_state) ==
should_be_on) {
if (ril_radio_state_on(self->priv->last_known_state) ==
should_be_on) {
/* All is good, cancel pending retry if there is one */
ril_radio_cancel_retry(self);
} else if (priv->state_changed_while_request_pending) {
@@ -142,7 +138,7 @@ static void ril_radio_check_state(struct ril_radio *self)
ril_radio_submit_power_request(self, should_be_on);
} else if (!priv->retry_id) {
/* There has been no reaction so far, wait a bit */
DBG_(self, "retry scheduled");
DBG("%sretry scheduled", priv->log_prefix);
priv->retry_id = g_timeout_add_seconds(POWER_RETRY_SECS,
ril_radio_power_request_retry_cb, self);
}
@@ -151,38 +147,33 @@ static void ril_radio_check_state(struct ril_radio *self)
/* Don't update public state while something is pending */
if (!priv->pending_id && !priv->retry_id &&
self->state != priv->last_known_state) {
DBG_(self, "%s -> %s", ril_radio_state_to_string(self->state),
DBG("%s%s -> %s", priv->log_prefix,
ril_radio_state_to_string(self->state),
ril_radio_state_to_string(priv->last_known_state));
self->state = priv->last_known_state;
ril_radio_emit_signal(self, SIGNAL_STATE_CHANGED);
}
}
static void ril_radio_power_request_done(struct ril_radio *self)
{
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
}
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
const void *data, guint len, void *user_data)
{
struct ril_radio *self = RIL_RADIO(user_data);
struct ril_radio_priv *priv = self->priv;
GASSERT(priv->pending_id);
priv->pending_id = 0;
if (ril_status != RIL_E_SUCCESS) {
ofono_error("Power request failed: %s",
ril_error_to_string(ril_status));
}
ril_radio_power_request_done(self);
if (priv->next_state_valid) {
ril_radio_submit_power_request(self, priv->next_state);
} else {
ril_radio_check_state(self);
}
}
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
@@ -223,37 +214,20 @@ static void ril_radio_power_request(struct ril_radio *self, gboolean on,
/* Wait for the pending request to complete */
priv->next_state_valid = TRUE;
priv->next_state = on;
DBG_(self, "%s (queued)", on_off);
DBG("%s%s (queued)", priv->log_prefix, on_off);
} else {
DBG_(self, "%s (ignored)", on_off);
DBG("%s%s (ignored)", priv->log_prefix, on_off);
}
} else {
if (ril_radio_state_on(priv->last_known_state) == on) {
DBG_(self, "%s (already)", on_off);
ril_radio_check_state(self);
} else {
DBG_(self, "%s", on_off);
ril_radio_submit_power_request(self, on);
}
DBG("%s%s", priv->log_prefix, on_off);
ril_radio_submit_power_request(self, on);
}
}
void ril_radio_confirm_power_on(struct ril_radio *self)
{
if (G_LIKELY(self) && ril_radio_power_should_be_on(self)) {
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);
}
ril_radio_power_request(self, TRUE, TRUE);
}
}
@@ -263,12 +237,12 @@ void ril_radio_power_cycle(struct ril_radio *self)
struct ril_radio_priv *priv = self->priv;
if (ril_radio_state_off(priv->last_known_state)) {
DBG_(self, "power is already off");
DBG("%spower is already off", priv->log_prefix);
GASSERT(!priv->power_cycle);
} else if (priv->power_cycle) {
DBG_(self, "already in progress");
DBG("%salready in progress", priv->log_prefix);
} else {
DBG_(self, "initiated");
DBG("%sinitiated", priv->log_prefix);
priv->power_cycle = TRUE;
if (!priv->pending_id) {
ril_radio_submit_power_request(self, FALSE);
@@ -285,7 +259,7 @@ void ril_radio_power_on(struct ril_radio *self, gpointer tag)
if (!g_hash_table_contains(priv->req_table, tag)) {
gboolean was_on = ril_radio_power_should_be_on(self);
DBG_(self, "%p", tag);
DBG("%s%p", priv->log_prefix, tag);
g_hash_table_insert(priv->req_table, tag, tag);
if (!was_on && ril_radio_power_should_be_on(self)) {
ril_radio_power_request(self, TRUE, FALSE);
@@ -300,7 +274,7 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
struct ril_radio_priv *priv = self->priv;
if (g_hash_table_remove(priv->req_table, tag)) {
DBG_(self, "%p", tag);
DBG("%s%p", priv->log_prefix, tag);
if (!ril_radio_power_should_be_on(self)) {
/* The last one turns the lights off */
ril_radio_power_request(self, FALSE, FALSE);
@@ -372,41 +346,20 @@ static void ril_radio_state_changed(GRilIoChannel *io, guint code,
if (radio_state != RADIO_STATE_UNAVAILABLE) {
struct ril_radio_priv *priv = self->priv;
DBG_(self, "%s", ril_radio_state_to_string(radio_state));
DBG("%s%s", priv->log_prefix,
ril_radio_state_to_string(radio_state));
GASSERT(!priv->pending_id || !priv->retry_id);
if (priv->power_cycle && ril_radio_state_off(radio_state)) {
DBG_(self, "switched off for power cycle");
DBG("%sswitched off for power cycle", priv->log_prefix);
priv->power_cycle = FALSE;
}
priv->last_known_state = radio_state;
if (priv->pending_id) {
if (ril_radio_state_on(radio_state) ==
ril_radio_power_should_be_on(self)) {
DBG_(self, "dropping pending request");
/*
* All right, the modem has switched to the
* desired state, drop the request.
*/
grilio_queue_cancel_request(priv->q,
priv->pending_id, FALSE);
/*
* This will zero pending_id and call
* ril_radio_check_state() if necesary:
*/
ril_radio_power_request_done(self);
/* We are done */
return;
} else {
/* Something weird is going on */
priv->state_changed_while_request_pending++;
}
priv->state_changed_while_request_pending++;
}
priv->last_known_state = radio_state;
ril_radio_check_state(self);
}
}
@@ -421,15 +374,10 @@ struct ril_radio *ril_radio_new(GRilIoChannel *io)
priv->log_prefix =
(io && io->name && io->name[0] && strcmp(io->name, "RIL")) ?
g_strconcat(io->name, " ", NULL) : g_strdup("");
DBG_(self, "");
DBG("%s", priv->log_prefix);
priv->state_event_id = grilio_channel_add_unsol_event_handler(priv->io,
ril_radio_state_changed,
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, self);
/*
* Some RILs like to receive power off request at startup even if
* radio is already off. Make those happy.
*/
ril_radio_submit_power_request(self, FALSE);
return self;
}
@@ -483,7 +431,7 @@ static void ril_radio_finalize(GObject *object)
struct ril_radio *self = RIL_RADIO(object);
struct ril_radio_priv *priv = self->priv;
DBG_(self, "");
DBG("%s", priv->log_prefix);
g_free(priv->log_prefix);
grilio_channel_unref(priv->io);
grilio_queue_unref(priv->q);

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2017-2020 Jolla Ltd.
* Copyright (C) 2017 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,16 +19,12 @@
#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);
@@ -43,47 +39,21 @@ 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_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
gulong ril_radio_caps_manager_add_aborted_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);
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))
gulong id);
/* 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_sim_settings *settings,
struct ril_sim_card *sim, struct ril_network *net,
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 */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2015-2018 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,8 +18,7 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/watch.h>
#include "sailfish_watch.h"
#include "simutil.h"
#include "util.h"
#include "ofono.h"
@@ -93,7 +92,7 @@ struct ril_sim {
const char *log_prefix;
char *allocated_log_prefix;
struct ofono_watch *watch;
struct sailfish_watch *watch;
gulong sim_state_watch_id;
/* query_passwd_state context */
@@ -109,9 +108,8 @@ struct ril_sim_io_response {
guint data_len;
};
struct ril_sim_cbd_io {
struct ril_sim_cbd {
struct ril_sim *sd;
struct ril_sim_card *card;
union _ofono_sim_cb {
ofono_sim_file_info_cb_t file_info;
ofono_sim_read_cb_t read;
@@ -181,43 +179,24 @@ static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
#define ril_sim_cbd_free g_free
static inline struct ril_sim *ril_sim_get_data(struct ofono_sim *sim)
{
return ofono_sim_get_data(sim);
}
static struct ril_sim_cbd_io *ril_sim_cbd_io_new(struct ril_sim *sd, void *cb,
static struct ril_sim_cbd *ril_sim_cbd_new(struct ril_sim *sd, void *cb,
void *data)
{
struct ril_sim_cbd_io *cbd = g_new0(struct ril_sim_cbd_io, 1);
struct ril_sim_cbd *cbd = g_new0(struct ril_sim_cbd, 1);
cbd->sd = sd;
cbd->cb.ptr = cb;
cbd->data = data;
cbd->card = ril_sim_card_ref(sd->card);
return cbd;
}
static void ril_sim_cbd_io_free(void *data)
{
struct ril_sim_cbd_io *cbd = data;
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
ril_sim_card_unref(cbd->card);
g_free(cbd);
}
static void ril_sim_cbd_io_start(struct ril_sim_cbd_io *cbd, GRilIoRequest* req,
guint code, GRilIoChannelResponseFunc cb)
{
struct ril_sim *sd = cbd->sd;
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code,
cb, ril_sim_cbd_io_free, cbd);
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
}
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
void *user_data)
{
@@ -276,6 +255,11 @@ static void ril_sim_pin_req_done(gpointer ptr)
}
}
static const char *ril_sim_app_id(struct ril_sim *sd)
{
return sd->card->app ? sd->card->app->aid : NULL;
}
int ril_sim_app_type(struct ofono_sim *sim)
{
struct ril_sim *sd = ril_sim_get_data(sim);
@@ -445,13 +429,14 @@ static void ril_sim_io_response_free(struct ril_sim_io_response *res)
static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
struct ril_sim_cbd *cbd = user_data;
ofono_sim_file_info_cb_t cb = cbd->cb.file_info;
struct ril_sim *sd = cbd->sd;
struct ril_sim_io_response *res = NULL;
struct ofono_error error;
DBG_(sd, "");
ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
ril_error_init_failure(&error);
res = ril_sim_parse_io_response(data, len);
@@ -495,13 +480,12 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
guint p1, guint p2, guint p3, const char *hex_data,
const guchar *path, guint path_len,
GRilIoChannelResponseFunc cb, struct ril_sim_cbd_io *cbd)
GRilIoChannelResponseFunc cb, struct ril_sim_cbd *cbd)
{
GRilIoRequest *req = grilio_request_new();
DBG_(sd, "cmd=0x%.2X,efid=0x%.4X,%d,%d,%d,%s,pin2=(null),aid=%s",
cmd, fileid, p1, p2, p3, hex_data,
ril_sim_card_app_aid(sd->card));
cmd, fileid, p1, p2, p3, hex_data, ril_sim_app_id(sd));
grilio_request_append_int32(req, cmd);
grilio_request_append_int32(req, fileid);
@@ -511,11 +495,13 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
grilio_request_append_int32(req, p3); /* P3 */
grilio_request_append_utf8(req, hex_data); /* data; only for writes */
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
grilio_request_append_utf8(req, ril_sim_card_app_aid(sd->card));
grilio_request_append_utf8(req, ril_sim_app_id(sd));
grilio_request_set_blocking(req, TRUE);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_IO, cb);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -525,19 +511,19 @@ static void ril_sim_ofono_read_file_info(struct ofono_sim *sim, int fileid,
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_request_io(sd, CMD_GET_RESPONSE, fileid, 0, 0, 15, NULL,
path, len, ril_sim_file_info_cb,
ril_sim_cbd_io_new(sd, cb, data));
path, len, ril_sim_file_info_cb, ril_sim_cbd_new(sd, cb, data));
}
static void ril_sim_read_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
struct ril_sim_cbd *cbd = user_data;
ofono_sim_read_cb_t cb = cbd->cb.read;
struct ril_sim_io_response *res;
struct ofono_error err;
DBG_(cbd->sd, "");
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
@@ -556,7 +542,7 @@ static void ril_sim_read(struct ofono_sim *sim, guint cmd, int fileid,
{
struct ril_sim *sd = ril_sim_get_data(sim);
ril_sim_request_io(sd, cmd, fileid, p1, p2, p3, NULL, path, path_len,
ril_sim_read_cb, ril_sim_cbd_io_new(sd, cb, data));
ril_sim_read_cb, ril_sim_cbd_new(sd, cb, data));
}
static void ril_sim_ofono_read_file_transparent(struct ofono_sim *sim,
@@ -586,12 +572,13 @@ static void ril_sim_ofono_read_file_cyclic(struct ofono_sim *sim, int fileid,
static void ril_sim_write_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
struct ril_sim_cbd *cbd = user_data;
ofono_sim_write_cb_t cb = cbd->cb.write;
struct ril_sim_io_response *res;
struct ofono_error err;
DBG_(cbd->sd, "");
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
@@ -612,7 +599,7 @@ static void ril_sim_write(struct ofono_sim *sim, guint cmd, int fileid,
struct ril_sim *sd = ril_sim_get_data(sim);
char *hex_data = encode_hex(value, length, 0);
ril_sim_request_io(sd, cmd, fileid, p1, p2, length, hex_data, path,
path_len, ril_sim_write_cb, ril_sim_cbd_io_new(sd, cb, data));
path_len, ril_sim_write_cb, ril_sim_cbd_new(sd, cb, data));
g_free(hex_data);
}
@@ -649,10 +636,12 @@ static void ril_sim_write_file_cyclic(struct ofono_sim *sim, int fileid,
static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
struct ril_sim_cbd *cbd = user_data;
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
struct ofono_error error;
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
if (status == RIL_E_SUCCESS) {
gchar *imsi;
GRilIoParser rilp;
@@ -677,8 +666,8 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_card_app_aid(sd->card);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
const char *app_id = ril_sim_app_id(sd);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
DBG_(sd, "%s", app_id);
@@ -690,8 +679,10 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
*/
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_request_set_blocking(req, TRUE);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_GET_IMSI,
ril_sim_get_imsi_cb);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -873,7 +864,7 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
}
}
static void ril_sim_state_changed_cb(struct ofono_watch *watch, void *data)
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
{
struct ril_sim *sd = data;
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
@@ -899,22 +890,25 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
const char *pin)
{
/*
* If there's no AID then so be it... Some
* adaptations (namely, MTK) don't provide it
* but don't seem to require it either.
*/
GRilIoRequest *req = grilio_request_array_utf8_new(2, pin,
ril_sim_card_app_aid(sd->card));
if (sd->card->app) {
/*
* If there's no AID then so be it... Some
* adaptations (namely, MTK) don't provide it
* but don't seem to require it either.
*/
GRilIoRequest *req = grilio_request_array_utf8_new(2,
pin, sd->card->app->aid);
grilio_request_set_blocking(req, TRUE);
return req;
grilio_request_set_blocking(req, TRUE);
return req;
}
return NULL;
}
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
const char *puk, const char *pin)
{
const char *app_id = ril_sim_card_app_aid(sd->card);
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
GRilIoRequest *req = grilio_request_array_utf8_new(3,
puk, pin, app_id);
@@ -1133,7 +1127,6 @@ static void ril_sim_pin_change_state_status_cb(struct ril_sim_card *sc,
cbd->cb(ril_error_ok(&error), cbd->data);
}
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,10 +1165,7 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
ril_sim_check_perm_lock(sd);
cbd->ril_status = ril_status;
/* 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 ||
if (cbd->card_status_id && (!cbd->state_event_count ||
ril_sim_app_in_transient_state(sd))) {
GASSERT(!g_list_find(sd->pin_cbd_list, cbd));
@@ -1210,9 +1200,6 @@ 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);
}
}
@@ -1223,7 +1210,7 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
if (req) {
DBG_(sd, "%s,aid=%s", passwd, ril_sim_card_app_aid(sd->card));
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
@@ -1250,7 +1237,10 @@ static guint ril_perso_change_state(struct ofono_sim *sim,
case OFONO_SIM_PASSWORD_PHNET_PIN:
if (!enable) {
code = RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
req = grilio_request_array_utf8_new(1, passwd);
req = grilio_request_sized_new(12);
grilio_request_append_int32(req,
RIL_PERSOSUBSTATE_SIM_NETWORK);
grilio_request_append_utf8(req, passwd);
} else {
DBG_(sd, "Not supported, enable=%d", enable);
}
@@ -1299,7 +1289,7 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_card_app_aid(sd->card);
const char *app_id = ril_sim_app_id(sd);
const char *type_str = ril_sim_facility_code(passwd_type);
struct ofono_error error;
guint id = 0;
@@ -1337,7 +1327,7 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
if (req) {
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
ril_sim_card_app_aid(sd->card));
ril_sim_app_id(sd));
grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
@@ -1357,7 +1347,7 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *app_id = ril_sim_card_app_aid(sd->card);
const char *app_id = ril_sim_app_id(sd);
GRilIoRequest *req = grilio_request_array_utf8_new(3,
old_passwd, new_passwd, app_id);
@@ -1375,9 +1365,11 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
struct ril_sim_cbd_io *cbd = user_data;
struct ril_sim_cbd *cbd = user_data;
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
if (status == RIL_E_SUCCESS) {
int locked = 0;
GRilIoParser rilp;
@@ -1407,9 +1399,9 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
{
struct ril_sim *sd = ril_sim_get_data(sim);
const char *type_str = ril_sim_facility_code(type);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
GRilIoRequest *req = grilio_request_array_utf8_new(4,
type_str, "", "0" /* class */, ril_sim_card_app_aid(sd->card));
type_str, "", "0" /* class */, ril_sim_app_id(sd));
/* Make sure that this request gets completed sooner or later */
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
@@ -1417,8 +1409,10 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
DBG_(sd, "%s", type_str);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_QUERY_FACILITY_LOCK,
ril_sim_query_facility_lock_cb);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
grilio_request_unref(req);
}
@@ -1453,7 +1447,7 @@ static gboolean ril_sim_register(gpointer user)
ril_sim_card_add_app_changed_handler(sd->card,
ril_sim_app_changed_cb, sd);
sd->sim_state_watch_id =
ofono_watch_add_sim_state_changed_handler(sd->watch,
sailfish_watch_add_sim_state_changed_handler(sd->watch,
ril_sim_state_changed_cb, sd);
/* And RIL events */
@@ -1478,7 +1472,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
sd->io = grilio_channel_ref(ril_modem_io(modem));
sd->card = ril_sim_card_ref(modem->sim_card);
sd->q = grilio_queue_new(sd->io);
sd->watch = ofono_watch_new(ril_modem_get_path(modem));
sd->watch = sailfish_watch_new(ril_modem_get_path(modem));
if (modem->log_prefix && modem->log_prefix[0]) {
sd->log_prefix = sd->allocated_log_prefix =
@@ -1516,8 +1510,8 @@ static void ril_sim_remove(struct ofono_sim *sim)
sd->query_passwd_state_sim_status_refresh_id);
}
ofono_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
ofono_watch_unref(sd->watch);
sailfish_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
sailfish_watch_unref(sd->watch);
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
G_N_ELEMENTS(sd->card_event_id));

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2015-2018 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,8 +13,6 @@
* 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"

View File

@@ -77,13 +77,9 @@ void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
/* Inline wrappers */
static inline enum ril_app_type ril_sim_card_app_type(struct ril_sim_card *sc)
static inline enum ril_app_type
ril_sim_card_app_type(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->app_type : RIL_APPTYPE_UNKNOWN; }
static inline const char *ril_sim_card_app_aid(struct ril_sim_card *sc)
{ return (sc && sc->app) ? sc->app->aid : NULL; }
#define ril_sim_card_remove_all_handlers(net, ids) \
ril_sim_card_remove_handlers(net, ids, G_N_ELEMENTS(ids))
#endif /* RIL_SIM_CARD_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2016-2017 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,12 +13,10 @@
* GNU General Public License for more details.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "ril_sim_settings.h"
#include "ril_log.h"
#include <ofono/watch.h>
#include "sailfish_watch.h"
#include <gutil_misc.h>
@@ -32,14 +30,14 @@
typedef GObjectClass RilSimSettingsClass;
typedef struct ril_sim_settings RilSimSettings;
enum ofono_watch_events {
enum sailfish_watch_events {
WATCH_EVENT_IMSI,
WATCH_EVENT_COUNT
};
struct ril_sim_settings_priv {
gulong watch_event_id[WATCH_EVENT_COUNT];
struct ofono_watch *watch;
struct sailfish_watch *watch;
char *imsi;
};
@@ -83,7 +81,7 @@ void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
}
}
static void ril_sim_settings_imsi_changed(struct ofono_watch *watch,
static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
void *user_data)
{
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
@@ -108,9 +106,9 @@ struct ril_sim_settings *ril_sim_settings_new(const char *path,
priv = self->priv;
self->techs = techs;
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
priv->watch = ofono_watch_new(path);
priv->watch = sailfish_watch_new(path);
priv->watch_event_id[WATCH_EVENT_IMSI] =
ofono_watch_add_imsi_changed_handler(priv->watch,
sailfish_watch_add_imsi_changed_handler(priv->watch,
ril_sim_settings_imsi_changed, self);
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
}
@@ -175,8 +173,8 @@ static void ril_sim_settings_finalize(GObject *object)
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
struct ril_sim_settings_priv *priv = self->priv;
ofono_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
ofono_watch_unref(priv->watch);
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
sailfish_watch_unref(priv->watch);
g_free(priv->imsi);
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2016-2018 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,8 +45,6 @@ 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 */

View File

@@ -17,14 +17,14 @@
# If it's set to true, all [ril_x] sections are ignored even
# if they are present, and no default configurtation is created.
#
# Default false
# Default is false
#
#EmptyConfig=false
# User and group for the ofono process. RIL clients are typically
# expected to run under radio:radio.
#
# Default radio:radio
# Default is radio:radio
#
#Identity=radio:radio
@@ -37,18 +37,11 @@
# 3G/LTE modules for each slot or you don't need 4G for both slots).
# Obviously, it only has any effect if you have more than one SIM.
#
# Defaults to true (switch the current data modem to 2G when changing
# Default is true (switch the current data modem to 2G when changing
# the data modems)
#
#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
@@ -56,7 +49,7 @@
#
# Possible values are auto, on and off
#
# Default auto (enable for RIL version >= 11)
# Default is auto (enable for RIL version >= 11)
#
#SetRadioCapability=auto
@@ -88,7 +81,7 @@ socket=/dev/socket/rild
# RIL request timeout, in milliseconds.
#
# Default zero (no timeout)
# The default is zero (no timeout)
#
#timeout=0
@@ -96,7 +89,7 @@ socket=/dev/socket/rild
# Valid technologies are "gsm", "umts" and "lte". The special value
# "all" means that all technologies are supported.
#
# Default all
# The default is all
#
#technologies=all
@@ -109,7 +102,7 @@ socket=/dev/socket/rild
# which RIL version it's dealing with, it makes the decision at runtime.
# Settings it to false disables the workaround and always sends 122.
#
# Default true (select SET_UICC_SUBSCRIPTION based on the RIL version)
# Default is true (select SET_UICC_SUBSCRIPTION based on the RIL version)
#
#uiccWorkaround=true
@@ -131,7 +124,7 @@ socket=/dev/socket/rild
# This option allows you to forcibly enable or disable use of this request.
# Possible values are auto, on and off
#
# Default auto (enable for RIL version >= 11)
# Default is auto (enable for RIL version >= 11)
#
#allowDataReq=auto
@@ -141,7 +134,7 @@ socket=/dev/socket/rild
# actually does check the empty pin (and decrements the retry count)
# then you should turn this feature off.
#
# Default true
# Default is true
#
#emptyPinQuery=true
@@ -153,7 +146,7 @@ socket=/dev/socket/rild
# but sometimes you have to explicitly tell ofono which one to use.
# Possible values are 6, 9, 11 and auto.
#
# Default auto
# Default is auto
#
#dataCallFormat=auto
@@ -162,7 +155,7 @@ socket=/dev/socket/rild
# this parameter. Usually, one retry is enough. The first retry occurs
# immediately, the subsequent ones after dataCallRetryDelay (see below)
#
# Default 4
# Default is 4
#
#dataCallRetryLimit=4
@@ -170,7 +163,7 @@ socket=/dev/socket/rild
# retry occurs immediately after the first failure, the delays are only
# applied if the first retry fails too.
#
# Default 200 ms
# Default is 200 ms
#
#dataCallRetryDelay=200
@@ -198,13 +191,6 @@ socket=/dev/socket/rild
#
#enableCellBroadcast=true
# Support for Sim Toolkit (STK). By default, its enabled but if your rild
# and/or modem is not happy about it, you can turn it off.
#
# Default true
#
#enableSimToolkit=true
# Timeout for the modem to show up, in milliseconds. Those that don't
# show up before this timeout expires, will be dropped (ignored).
#
@@ -212,7 +198,7 @@ socket=/dev/socket/rild
# optional modems (which may or may not be available), to speed up the
# boot up process.
#
# Default 20000 (20 seconds)
# The default is 20000 (20 seconds)
#
#startTimeout=20000
@@ -220,148 +206,6 @@ socket=/dev/socket/rild
# RIL_REQUEST_DEVICE_IDENTITY to query IMEI from the modem. Some
# RILs (e.g. MTK) still don't understand RIL_REQUEST_DEVICE_IDENTITY.
#
# Default false (use RIL_REQUEST_DEVICE_IDENTITY)
# Default is false (use RIL_REQUEST_DEVICE_IDENTITY)
#
#legacyImeiQuery=false
# Some devices don't support LTE RAT mode PREF_NET_TYPE_LTE_GSM_WCDMA.
# This option allows to set a custom LTE mode.
#
# Default 9 (PREF_NET_TYPE_LTE_GSM_WCDMA)
#
#lteNetworkMode=9
# 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)
#
#radioPowerCycle=true
# With some RILs it seems to be necessary to kick (RIL_REQUEST_RADIO_POWER)
# the modems with power on after one of the modems has been powered off.
# Otherwise bad things may happen (like the modem never registering
# on the network).
#
# On the other hand, with some RILs it's causing some trouble (like this
# extra RIL_REQUEST_RADIO_POWER getting stuck indefinitely).
#
# Default true (for historical reasons)
#
#confirmRadioPowerOn=true
# Normally we should be able to have two simultaneously active data
# contexts - one for mobile data and one for MMS. Some devices however
# require that mobile data is disconnected before we can send or receive
# MMS. In other words, activation of the second data context fails.
#
# Default false (more than one context is supported)
#
#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.
#
# Default true
#
#networkSelectionManual0=true
# Enables use of SET_DATA_PROFILE requests. Everything used to work without
# profiles, that's why it's disabled by default.
#
# Default false
#
#useDataProfiles=false
# Configures MMS data profile ID. Must be non-zero.
# This option is ignored if useDataProfiles is false.
#
# Default 2 (RIL_DATA_PROFILE_IMS)
#
#mmsDataProfileId=2
# Configures device state tracking (basically, power saving strategy).
# Possible values are:
#
# ss = Use legacy device state management (RIL_REQUEST_SCREEN_STATE)
# ds = Use newer device state management (RIL_REQUEST_SEND_DEVICE_STATE)
# 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

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2015-2018 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,7 +23,6 @@
#include <grilio_types.h>
#include <gutil_macros.h>
struct ofono_watch;
struct ofono_modem;
struct ofono_sim;
@@ -48,39 +46,17 @@ struct ril_modem;
struct ril_radio;
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_vendor_hook;
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;
gboolean confirm_radio_power_on;
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 */

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2015-2017 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
@@ -21,77 +20,46 @@
#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(struct ril_ussd *ud,
ofono_ussd_cb_t cb, void *data)
static struct ril_ussd_cbd *ril_ussd_cbd_new(ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd_cbd *cbd = g_slice_new(struct ril_ussd_cbd);
struct ril_ussd_cbd *cbd = g_new0(struct ril_ussd_cbd, 1);
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)
{
@@ -100,12 +68,6 @@ 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];
@@ -136,15 +98,10 @@ static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
}
grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length);
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_queue_send_request(ud->q, req,
RIL_REQUEST_SEND_USSD);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return;
}
}
@@ -157,16 +114,11 @@ static void ril_ussd_cancel(struct ofono_ussd *ussd,
ofono_ussd_cb_t cb, void *data)
{
struct ril_ussd *ud = ril_ussd_get_data(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);
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);
grilio_queue_send_request_full(ud->q, NULL, RIL_REQUEST_CANCEL_USSD,
ril_ussd_cancel_cb, ril_ussd_cbd_free,
ril_ussd_cbd_new(cb, data));
}
static void ril_ussd_notify(GRilIoChannel *io, guint code,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2015-2017 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,18 +18,14 @@
#include <grilio_channel.h>
#include <gutil_misc.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include "common.h"
#include "netreg.h"
#define RIL_PROTO_IP_STR "IP"
#define RIL_PROTO_IPV6_STR "IPV6"
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
const char *ril_error_to_string(int error)
{
#define RIL_E_(name) case RIL_E_##name: return #name
@@ -239,18 +235,6 @@ const char *ril_request_to_string(guint request)
RIL_REQUEST_(SHUTDOWN);
RIL_REQUEST_(GET_RADIO_CAPABILITY);
RIL_REQUEST_(SET_RADIO_CAPABILITY);
RIL_REQUEST_(START_LCE);
RIL_REQUEST_(STOP_LCE);
RIL_REQUEST_(GET_ACTIVITY_INFO);
RIL_REQUEST_(GET_CARRIER_RESTRICTIONS);
RIL_REQUEST_(SEND_DEVICE_STATE);
RIL_REQUEST_(SET_UNSOLICITED_RESPONSE_FILTER);
RIL_REQUEST_(SET_SIM_CARD_POWER);
RIL_REQUEST_(SET_CARRIER_INFO_IMSI_ENCRYPTION);
RIL_REQUEST_(START_NETWORK_SCAN);
RIL_REQUEST_(STOP_NETWORK_SCAN);
RIL_REQUEST_(START_KEEPALIVE);
RIL_REQUEST_(STOP_KEEPALIVE);
case RIL_RESPONSE_ACKNOWLEDGEMENT:
return "RESPONSE_ACK";
default:
@@ -337,56 +321,12 @@ const char *ril_radio_state_to_string(int radio_state)
}
}
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
return RIL_PROTO_IPV6_STR;
case OFONO_GPRS_PROTO_IPV4V6:
return RIL_PROTO_IPV4V6_STR;
case OFONO_GPRS_PROTO_IP:
return RIL_PROTO_IP_STR;
}
return NULL;
}
int ril_protocol_to_ofono(const gchar *str)
{
if (str) {
if (!strcmp(str, RIL_PROTO_IPV6_STR)) {
return OFONO_GPRS_PROTO_IPV6;
} else if (!strcmp(str, RIL_PROTO_IPV4V6_STR)) {
return OFONO_GPRS_PROTO_IPV4V6;
} else if (!strcmp(str, RIL_PROTO_IP_STR)) {
return OFONO_GPRS_PROTO_IP;
}
}
return -1;
}
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth)
{
switch (auth) {
case OFONO_GPRS_AUTH_METHOD_NONE:
return RIL_AUTH_NONE;
case OFONO_GPRS_AUTH_METHOD_CHAP:
return RIL_AUTH_CHAP;
case OFONO_GPRS_AUTH_METHOD_PAP:
return RIL_AUTH_PAP;
case OFONO_GPRS_AUTH_METHOD_ANY:
/* Use default */
break;
}
/* Default */
return RIL_AUTH_BOTH;
}
/* Returns enum access_technology or -1 on failure. */
int ril_parse_tech(const char *stech, int *ril_tech)
{
int access_tech = -1;
int tech = -1;
if (gutil_parse_int(stech, 0, &tech)) {
if (ril_parse_int(stech, 0, &tech)) {
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
@@ -409,7 +349,6 @@ 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:
@@ -472,6 +411,26 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
return FALSE;
}
gboolean ril_parse_int(const char *str, int base, int *value)
{
gboolean ok = FALSE;
if (str && str[0]) {
char *str2 = g_strstrip(g_strdup(str));
char *end = str2;
long l;
errno = 0;
l = strtol(str2, &end, base);
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
if (ok && value) {
*value = (int)l;
}
g_free(str2);
}
return ok;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2015-2017 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,19 +18,15 @@
#include "ril_types.h"
#include <ofono/gprs-context.h>
struct ofono_network_operator;
const char *ril_error_to_string(int error);
const char *ril_request_to_string(guint request);
const char *ril_unsol_event_to_string(guint event);
const char *ril_radio_state_to_string(int radio_state);
const char *ril_protocol_from_ofono(enum ofono_gprs_proto proto);
int ril_protocol_to_ofono(const char *str);
enum ril_auth ril_auth_method_from_ofono(enum ofono_gprs_auth_method auth);
int ril_parse_tech(const char *stech, int *ril_tech);
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
gboolean ril_parse_int(const char *str, int base, int *value);
#define ril_error_init_ok(err) \
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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
@@ -15,200 +14,147 @@
*/
#include "ril_vendor.h"
#include "ril_vendor_impl.h"
#include "ril_log.h"
#include <grilio_channel.h>
G_DEFINE_ABSTRACT_TYPE(RilVendor, ril_vendor, G_TYPE_OBJECT)
/* Vendor driver descriptors are in the "__vendor" section */
extern const struct ril_vendor_driver __start___vendor[];
extern const struct ril_vendor_driver __stop___vendor[];
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name)
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *config,
struct ril_network *network)
{
if (name) {
const struct ril_vendor_driver *d;
if (vendor) {
const void *data = vendor->driver_data;
for (d = __start___vendor; d < __stop___vendor; d++) {
if (!strcasecmp(d->name, name)) {
return d;
}
/*
* NOTE: we are looking for the callback in the base but
* keeping the original driver data.
*/
while (!vendor->create_hook && vendor->base) {
vendor = vendor->base;
}
if (vendor->create_hook) {
return vendor->create_hook(data, io, path, config,
network);
}
}
return NULL;
}
RilVendor *ril_vendor_create(const struct ril_vendor_driver *driver,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
const struct ril_vendor_hook_proc *proc,
ril_vendor_hook_free_proc free)
{
return (driver && driver->create_vendor) ?
driver->create_vendor(driver->driver_data, io, path, config) :
NULL;
self->proc = proc;
self->free = free;
g_atomic_int_set(&self->ref_count, 1);
return self;
}
RilVendor *ril_vendor_ref(RilVendor *self)
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
{
if (G_LIKELY(self)) {
g_object_ref(RIL_VENDOR(self));
if (self) {
GASSERT(self->ref_count > 0);
g_atomic_int_inc(&self->ref_count);
}
return self;
}
void ril_vendor_unref(RilVendor *self)
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
{
if (G_LIKELY(self)) {
g_object_unref(RIL_VENDOR(self));
if (self->free) {
self->free(self);
}
}
void ril_vendor_hook_unref(struct ril_vendor_hook *self)
{
if (self) {
GASSERT(self->ref_count > 0);
if (g_atomic_int_dec_and_test(&self->ref_count)) {
ril_vendor_hook_free(self);
}
}
}
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults)
{
if (vendor && vendor->get_defaults) {
vendor->get_defaults(defaults);
if (vendor) {
while (!vendor->get_defaults && vendor->base) {
vendor = vendor->base;
}
if (vendor->get_defaults) {
vendor->get_defaults(defaults);
}
}
}
const char *ril_vendor_request_to_string(RilVendor *self, guint request)
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *self,
guint request)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
request_to_string(self, request) : NULL;
}
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
const char *ril_vendor_event_to_string(RilVendor *self, guint event)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
event_to_string(self, event) : NULL;
}
void ril_vendor_set_network(RilVendor *self, struct ril_network *nw)
{
if (G_LIKELY(self)) {
RIL_VENDOR_GET_CLASS(self)->set_network(self, nw);
while (!proc->request_to_string && proc->base) {
proc = proc->base;
}
if (proc->request_to_string) {
return proc->request_to_string(self, request);
}
}
return NULL;
}
GRilIoRequest *ril_vendor_set_attach_apn_req(RilVendor *self, const char *apn,
const char *user, const char *password,
enum ril_auth auth, const char *proto)
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *self,
guint event)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
set_attach_apn_req(self, apn, user, password, auth, proto) :
NULL;
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->event_to_string && proc->base) {
proc = proc->base;
}
if (proc->event_to_string) {
return proc->event_to_string(self, event);
}
}
return NULL;
}
GRilIoRequest *ril_vendor_data_call_req(RilVendor *self, int tech,
enum ril_data_profile profile, const char *apn,
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *self,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
return G_LIKELY(self) ? RIL_VENDOR_GET_CLASS(self)->
data_call_req(self, tech, profile, apn, username, password,
auth, proto) : NULL;
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->data_call_req && proc->base) {
proc = proc->base;
}
if (proc->data_call_req) {
return proc->data_call_req(self, tech, profile, apn,
username, password, auth, proto);
}
}
return NULL;
}
gboolean ril_vendor_data_call_parse(RilVendor *self,
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *self,
struct ril_data_call *call, int ver, GRilIoParser *rilp)
{
return G_LIKELY(self) && RIL_VENDOR_GET_CLASS(self)->
data_call_parse(self, call, ver, rilp);
}
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
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)
{
if (self->network != network) {
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
while (!proc->data_call_parse && proc->base) {
proc = proc->base;
}
self->network = network;
if (self->network) {
g_object_add_weak_pointer(G_OBJECT(network),
(gpointer*) &self->network);
if (proc->data_call_parse) {
return proc->data_call_parse(self, call, ver, rilp);
}
}
}
static const char *ril_vendor_default_id_to_string(RilVendor *self, guint id)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_set_attach_apn_req(RilVendor *self,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto)
{
return NULL;
}
static GRilIoRequest *ril_vendor_default_data_call_req(RilVendor *self,
int tech, enum ril_data_profile profile,
const char *apn, const char *user, const char *passwd,
enum ril_auth auth, const char *proto)
{
return NULL;
}
static gboolean ril_vendor_default_data_call_parse(RilVendor *self,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
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);
}
static void ril_vendor_init(RilVendor *self)
{
}
static void ril_vendor_finalize(GObject* object)
{
RilVendor *self = RIL_VENDOR(object);
if (self->network) {
g_object_remove_weak_pointer(G_OBJECT(self->network),
(gpointer*) &self->network);
}
grilio_channel_unref(self->io);
G_OBJECT_CLASS(ril_vendor_parent_class)->finalize(object);
}
static void ril_vendor_class_init(RilVendorClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_finalize;
klass->set_network = ril_vendor_default_set_network;
klass->request_to_string = ril_vendor_default_id_to_string;
klass->event_to_string = ril_vendor_default_id_to_string;
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;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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
@@ -23,62 +22,75 @@ struct ril_vendor_defaults {
gboolean empty_pin_query;
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;
};
struct ril_vendor_driver {
const char *name;
const void *driver_data;
const struct ril_vendor_driver *base;
void (*get_defaults)(struct ril_vendor_defaults *defaults);
struct ril_vendor *(*create_vendor)(const void *driver_data,
struct ril_vendor_hook *(*create_hook)(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg);
const struct ril_slot_config *cfg,
struct ril_network *network);
};
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 */
struct ril_vendor_hook_proc {
const struct ril_vendor_hook_proc *base;
const char *(*request_to_string)(struct ril_vendor_hook *hook,
guint request);
const char *(*event_to_string)(struct ril_vendor_hook *hook,
guint event);
GRilIoRequest *(*data_call_req)(struct ril_vendor_hook *hook,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean (*data_call_parse)(struct ril_vendor_hook *hook,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
};
const struct ril_vendor_driver *ril_vendor_find_driver(const char *name);
struct ril_vendor *ril_vendor_create
typedef void (*ril_vendor_hook_free_proc)(struct ril_vendor_hook *hook);
struct ril_vendor_hook {
const struct ril_vendor_hook_proc *proc;
ril_vendor_hook_free_proc free;
gint ref_count;
};
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *cfg);
const char *path, const struct ril_slot_config *cfg,
struct ril_network *network);
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults);
struct ril_vendor *ril_vendor_ref(struct ril_vendor *vendor);
void ril_vendor_unref(struct ril_vendor *vendor);
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *hook,
const struct ril_vendor_hook_proc *proc,
ril_vendor_hook_free_proc free);
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);
const char *ril_vendor_request_to_string(struct ril_vendor *vendor,
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *hook,
guint request);
const char *ril_vendor_event_to_string(struct ril_vendor *vendor,
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *hook,
guint event);
void ril_vendor_set_network(struct ril_vendor *vendor, struct ril_network *nw);
GRilIoRequest *ril_vendor_set_attach_apn_req(struct ril_vendor *vendor,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto);
GRilIoRequest *ril_vendor_data_call_req(struct ril_vendor *vendor, int tech,
enum ril_data_profile profile, const char *apn,
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *hook,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean ril_vendor_data_call_parse(struct ril_vendor *vendor,
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *hook,
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 \
#define RIL_VENDOR_DRIVER_DEFINE(name) \
const struct ril_vendor_driver name \
__attribute__((used, section("__vendor"))) =
#define RIL_VENDOR_DRIVER_FOREACH(var) \
for ((var) = __start___vendor; (var) < __stop___vendor; (var)++)
extern const struct ril_vendor_driver __start___vendor[];
extern const struct ril_vendor_driver __stop___vendor[];
#endif /* RIL_VENDOR_H */

View File

@@ -1,70 +0,0 @@
/*
* 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef RIL_VENDOR_IMPL_H
#define RIL_VENDOR_IMPL_H
#include "ril_vendor.h"
#include <glib-object.h>
typedef struct ril_vendor {
GObject parent;
GRilIoChannel *io;
struct ril_network *network;
} RilVendor;
typedef struct ril_vendor_class {
GObjectClass parent;
void (*set_network)(RilVendor *vendor, struct ril_network *network);
const char *(*request_to_string)(RilVendor *vendor, guint request);
const char *(*event_to_string)(RilVendor *vendor, guint event);
GRilIoRequest *(*set_attach_apn_req)(RilVendor *vendor,
const char *apn, const char *username,
const char *password, enum ril_auth auth,
const char *proto);
GRilIoRequest *(*data_call_req)(RilVendor *vendor, int tech,
enum ril_data_profile profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
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);
#define RIL_VENDOR_TYPE (ril_vendor_get_type())
#define RIL_VENDOR(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE, RilVendor)
#define RIL_VENDOR_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
RIL_VENDOR_TYPE, RilVendorClass)
#define RIL_VENDOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
RIL_VENDOR_TYPE, RilVendorClass)
void ril_vendor_init_base(RilVendor *vendor, GRilIoChannel *io);
#endif /* RIL_VENDOR_IMPL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2020 Jolla Ltd.
* Copyright (C) 2019-2020 Open Mobile Platform LLC.
* Copyright (C) 2016-2018 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,25 +13,35 @@
* GNU General Public License for more details.
*/
#include "ril_plugin.h"
#include "ril_vendor.h"
#include "ril_vendor_impl.h"
#include "ril_network.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include "sailfish_watch.h"
#include <grilio_channel.h>
#include <grilio_parser.h>
#include <grilio_request.h>
#include <grilio_queue.h>
#include <gutil_misc.h>
#include <gutil_macros.h>
#include <ofono/watch.h>
#include <ofono/gprs.h>
#include "ofono.h"
#define SET_INITIAL_ATTACH_APN_TIMEOUT (20*1000)
enum ril_mtk_watch_events {
WATCH_EVENT_IMSI_CHANGED,
WATCH_EVENT_COUNT
};
enum ril_mtk_network_events {
NETWORK_EVENT_PREF_MODE_CHANGED,
NETWORK_EVENT_COUNT
};
enum ril_mtk_events {
MTK_EVENT_REGISTRATION_SUSPENDED,
MTK_EVENT_SET_ATTACH_APN,
@@ -41,53 +50,39 @@ enum ril_mtk_events {
MTK_EVENT_COUNT
};
typedef struct ril_vendor_mtk {
RilVendor vendor;
const struct ril_mtk_flavor *flavor;
struct ril_vendor_hook_mtk {
struct ril_vendor_hook hook;
const struct ril_mtk_msg *msg;
GRilIoQueue *q;
struct ofono_watch *watch;
GRilIoChannel *io;
struct ril_network *network;
struct sailfish_watch *watch;
guint set_initial_attach_apn_id;
gboolean initial_attach_apn_ok;
gulong network_event_id[NETWORK_EVENT_COUNT];
gulong watch_event_id[WATCH_EVENT_COUNT];
gulong ril_event_id[MTK_EVENT_COUNT];
guint slot;
} RilVendorMtk;
typedef struct ril_vendor_mtk_auto {
RilVendorMtk mtk;
gulong detect_id;
} RilVendorMtkAuto;
typedef RilVendorClass RilVendorMtkClass;
typedef RilVendorMtkClass RilVendorMtkAutoClass;
#define RIL_VENDOR_TYPE_MTK (ril_vendor_mtk_get_type())
#define RIL_VENDOR_TYPE_MTK_AUTO (ril_vendor_mtk_auto_get_type())
G_DEFINE_TYPE(RilVendorMtk, ril_vendor_mtk, RIL_VENDOR_TYPE)
G_DEFINE_TYPE(RilVendorMtkAuto, ril_vendor_mtk_auto, RIL_VENDOR_TYPE_MTK)
#define RIL_VENDOR_MTK(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE_MTK, RilVendorMtk)
#define RIL_VENDOR_MTK_AUTO(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RIL_VENDOR_TYPE_MTK_AUTO, RilVendorMtkAuto)
};
/* driver_data point this this: */
struct ril_mtk_flavor {
struct ril_vendor_mtk_driver_data {
const char *name;
const struct ril_mtk_msg *msg;
void (*build_attach_apn_req_fn)(GRilIoRequest *req, const char *apn,
const char *username, const char *password,
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);
const struct ril_vendor_hook_proc *proc;
};
/* Hook with auto-detection */
struct ril_vendor_hook_mtk_auto {
struct ril_vendor_hook_mtk mtk;
const struct ril_vendor_mtk_driver_data *type;
gulong detect_id;
};
/* MTK specific RIL messages (actual codes differ from model to model!) */
struct ril_mtk_msg {
gboolean attach_apn_has_roaming_protocol;
guint request_resume_registration;
guint request_set_call_indication;
/* See ril_vendor_mtk_auto_detect_event */
#define unsol_msgs unsol_ps_network_state_changed
@@ -100,8 +95,8 @@ struct ril_mtk_msg {
};
static const struct ril_mtk_msg msg_mtk1 = {
.attach_apn_has_roaming_protocol = TRUE,
.request_resume_registration = 2050,
.request_set_call_indication = 2065,
.unsol_ps_network_state_changed = 3012,
.unsol_registration_suspended = 3021,
.unsol_incoming_call_indication = 3037,
@@ -109,24 +104,34 @@ static const struct ril_mtk_msg msg_mtk1 = {
};
static const struct ril_mtk_msg msg_mtk2 = {
.attach_apn_has_roaming_protocol = FALSE,
.request_resume_registration = 2065,
.request_set_call_indication = 2086,
.unsol_ps_network_state_changed = 3015,
.unsol_registration_suspended = 3024,
.unsol_incoming_call_indication = 3042,
.unsol_set_attach_apn = 3073
};
static const char *ril_vendor_mtk_request_to_string(RilVendor *vendor,
guint request)
static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
(struct ril_vendor_hook *hook)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
const struct ril_mtk_msg *msg = self->flavor->msg;
return G_CAST(hook, struct ril_vendor_hook_mtk, hook);
}
static inline struct ril_vendor_hook_mtk_auto *ril_vendor_hook_mtk_auto_cast
(struct ril_vendor_hook *hook)
{
return G_CAST(hook, struct ril_vendor_hook_mtk_auto, mtk.hook);
}
static const char *ril_vendor_mtk_request_to_string
(struct ril_vendor_hook *hook, guint request)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
const struct ril_mtk_msg *msg = self->msg;
if (request == msg->request_resume_registration) {
return "MTK_RESUME_REGISTRATION";
} else if (request == msg->request_set_call_indication) {
return "MTK_SET_CALL_INDICATION";
} else {
return NULL;
}
@@ -148,19 +153,19 @@ static const char *ril_vendor_mtk_unsol_msg_name(const struct ril_mtk_msg *msg,
}
}
static const char *ril_vendor_mtk_event_to_string(RilVendor *vendor,
static const char *ril_vendor_mtk_event_to_string(struct ril_vendor_hook *hook,
guint event)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
return ril_vendor_mtk_unsol_msg_name(self->flavor->msg, event);
return ril_vendor_mtk_unsol_msg_name(self->msg, event);
}
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
const struct ril_mtk_msg *msg = self->flavor->msg;
struct ril_vendor_hook_mtk *self = user_data;
const struct ril_mtk_msg *msg = self->msg;
GRilIoParser rilp;
int session_id;
@@ -178,41 +183,80 @@ static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
}
}
static void ril_vendor_mtk_build_attach_apn_req_1(GRilIoRequest *req,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
static GRilIoRequest *ril_vendor_mtk_build_set_attach_apn_req
(const struct ofono_gprs_primary_context *pc,
gboolean roamingProtocol)
{
DBG("\"%s\" %s", apn, proto);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, proto);
grilio_request_append_utf8(req, proto); /* roamingProtocol */
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
GRilIoRequest *req = grilio_request_new();
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
DBG("%s %d", pc->apn, roamingProtocol);
grilio_request_append_utf8(req, pc->apn); /* apn */
grilio_request_append_utf8(req, proto); /* protocol */
if (roamingProtocol) {
grilio_request_append_utf8(req, proto); /* roamingProtocol */
}
if (pc->username[0]) {
int auth;
switch (pc->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
default:
auth = RIL_AUTH_NONE;
break;
}
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, pc->username);
grilio_request_append_utf8(req, pc->password);
} else {
grilio_request_append_int32(req, RIL_AUTH_NONE);
grilio_request_append_utf8(req, "");
grilio_request_append_utf8(req, "");
}
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
return req;
}
static void ril_vendor_mtk_build_attach_apn_req_2(GRilIoRequest *req,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
static const struct ofono_gprs_primary_context *ril_vendor_mtk_internet_context
(struct ril_vendor_hook_mtk *self)
{
DBG("\"%s\" %s", apn, proto);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, proto);
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, -1); /* dualApnPlmnList */
struct sailfish_watch *watch = self->watch;
if (watch->imsi) {
struct ofono_atom *atom = __ofono_modem_find_atom(watch->modem,
OFONO_ATOM_TYPE_GPRS);
if (atom) {
return __ofono_gprs_context_settings_by_type
(__ofono_atom_get_data(atom),
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
}
}
return NULL;
}
static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
int ril_status, const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
struct ril_vendor_hook_mtk *self = user_data;
GASSERT(self->set_initial_attach_apn_id);
self->set_initial_attach_apn_id = 0;
@@ -222,35 +266,19 @@ static void ril_vendor_mtk_initial_attach_apn_resp(GRilIoChannel *io,
}
}
static void ril_vendor_mtk_initial_attach_apn_check(RilVendorMtk *self)
static void ril_vendor_mtk_initial_attach_apn_check
(struct ril_vendor_hook_mtk *self)
{
if (!self->set_initial_attach_apn_id && !self->initial_attach_apn_ok) {
struct ofono_watch *watch = self->watch;
const struct ofono_gprs_primary_context *pc =
ofono_gprs_context_settings_by_type(watch->gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET);
ril_vendor_mtk_internet_context(self);
if (pc) {
const char *username;
const char *password;
enum ril_auth auth;
GRilIoRequest *req = grilio_request_new();
GRilIoRequest *req =
ril_vendor_mtk_build_set_attach_apn_req(pc,
self->msg->attach_apn_has_roaming_protocol);
if (pc->username[0] || pc->password[0]) {
username = pc->username;
password = pc->password;
auth = ril_auth_method_from_ofono
(pc->auth_method);
} else {
username = "";
password = "";
auth = RIL_AUTH_NONE;
}
self->flavor->build_attach_apn_req_fn(req,
pc->apn, username, password, auth,
ril_protocol_from_ofono(pc->proto));
grilio_request_set_timeout(req,
SET_INITIAL_ATTACH_APN_TIMEOUT);
self->set_initial_attach_apn_id =
@@ -263,80 +291,74 @@ static void ril_vendor_mtk_initial_attach_apn_check(RilVendorMtk *self)
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
static void ril_vendor_mtk_initial_attach_apn_reset
(struct ril_vendor_hook_mtk *self)
{
ril_vendor_mtk_initial_attach_apn_check(RIL_VENDOR_MTK(user_data));
self->initial_attach_apn_ok = FALSE;
if (self->set_initial_attach_apn_id) {
grilio_queue_cancel_request(self->q,
self->set_initial_attach_apn_id, FALSE);
self->set_initial_attach_apn_id = 0;
}
}
static void ril_vendor_mtk_watch_imsi_changed(struct sailfish_watch *watch,
void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
if (watch->imsi) {
ril_vendor_mtk_initial_attach_apn_check(self);
} else {
ril_vendor_mtk_initial_attach_apn_reset(self);
}
}
static void ril_vendor_mtk_network_pref_mode_changed(struct ril_network *net,
void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
if (net->pref_mode >= OFONO_RADIO_ACCESS_MODE_LTE) {
ril_vendor_mtk_initial_attach_apn_check(self);
} else {
ril_vendor_mtk_initial_attach_apn_reset(self);
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *self)
{
ril_vendor_mtk_initial_attach_apn_check(self);
}
static void ril_vendor_mtk_ps_network_state_changed(GRilIoChannel *io,
guint id, const void *data, guint len, void *user_data)
{
ril_network_query_registration_state(RIL_VENDOR(user_data)->network);
struct ril_vendor_hook_mtk *self = user_data;
ril_network_query_registration_state(self->network);
}
static void ril_vendor_mtk_incoming_call_indication(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
static void ril_vendor_mtk_call_state_changed(GRilIoChannel *io,
guint id, const void *data, guint len, void *user_data)
{
RilVendorMtk *self = RIL_VENDOR_MTK(user_data);
const struct ril_mtk_msg *msg = self->flavor->msg;
GRilIoRequest* req = NULL;
GASSERT(id == msg->unsol_incoming_call_indication);
if (msg->request_set_call_indication) {
int nparams, cid, seq;
gchar *call_id = NULL, *seq_no = NULL;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &nparams) && nparams >= 5 &&
(call_id = grilio_parser_get_utf8(&rilp)) != NULL &&
grilio_parser_skip_string(&rilp) /* number */ &&
grilio_parser_skip_string(&rilp) /* type */ &&
grilio_parser_skip_string(&rilp) /* call_mode */ &&
(seq_no = grilio_parser_get_utf8(&rilp)) != NULL &&
gutil_parse_int(call_id, 10, &cid) &&
gutil_parse_int(seq_no, 10, &seq)) {
DBG("slot=%u,cid=%d,seq=%d", self->slot, cid, seq);
req = grilio_request_new();
grilio_request_append_int32(req, 3); /* Param count */
/* mode - IMS_ALLOW_INCOMING_CALL_INDICATION: */
grilio_request_append_int32(req, 0);
grilio_request_append_int32(req, cid);
grilio_request_append_int32(req, seq);
} else {
DBG("failed to parse INCOMING_CALL_INDICATION");
}
g_free(call_id);
g_free(seq_no);
}
if (req) {
grilio_queue_send_request(self->q, req,
msg->request_set_call_indication);
grilio_request_unref(req);
} else {
/* Let ril_voicecall.c know that something happened */
grilio_channel_inject_unsol_event(io,
/* Ignore the payload, let ril_voicecall.c do its normal stuff */
grilio_channel_inject_unsol_event(io,
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
}
}
static GRilIoRequest *ril_vendor_mtk_data_call_req(RilVendor *vendor, int tech,
enum ril_data_profile profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
static GRilIoRequest *ril_vendor_mtk_data_call_req
(struct ril_vendor_hook *hook, int tech, const char *profile,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, 8); /* Number of parameters */
grilio_request_append_format(req, "%d", tech);
grilio_request_append_format(req, "%d", profile);
grilio_request_append_utf8(req, profile);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
@@ -346,19 +368,9 @@ static GRilIoRequest *ril_vendor_mtk_data_call_req(RilVendor *vendor, int tech,
return req;
}
static GRilIoRequest *ril_vendor_mtk_set_attach_apn_req(RilVendor *vendor,
const char *apn, const char *user, const char *pass,
enum ril_auth auth, const char *prot)
{
RilVendorMtk *self = RIL_VENDOR_MTK(vendor);
GRilIoRequest *req = grilio_request_new();
self->flavor->build_attach_apn_req_fn(req, apn, user, pass, auth, prot);
return req;
}
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_data_call *call,
int version, GRilIoParser *rilp)
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
if (version < 11) {
int prot;
@@ -373,7 +385,7 @@ static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_data_call *call,
grilio_parser_get_uint32(rilp, &active);
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
prot_str = grilio_parser_get_utf8(rilp);
prot = ril_protocol_to_ofono(prot_str);
prot = ril_data_protocol_to_ofono(prot_str);
g_free(prot_str);
if (prot >= 0) {
@@ -392,108 +404,6 @@ static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_data_call *call,
return FALSE;
}
static gboolean ril_vendor_mtk_data_call_parse(RilVendor *vendor,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
const struct ril_mtk_flavor *flavor = RIL_VENDOR_MTK(vendor)->flavor;
return flavor->data_call_parse_fn ?
flavor->data_call_parse_fn(call, version, rilp) :
RIL_VENDOR_CLASS(ril_vendor_mtk_parent_class)->
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)
{
/*
@@ -508,204 +418,231 @@ 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,
const char *path, const struct ril_slot_config *config)
static void ril_vendor_mtk_hook_subscribe(struct ril_vendor_hook_mtk *self)
{
ril_vendor_init_base(&self->vendor, io);
self->q = grilio_queue_new(io);
self->watch = ofono_watch_new(path);
self->slot = config->slot;
}
const struct ril_mtk_msg *msg = self->msg;
static void ril_vendor_mtk_set_flavor(RilVendorMtk *self,
const struct ril_mtk_flavor *flavor)
{
GRilIoChannel *io = self->vendor.io;
const struct ril_mtk_msg *msg = flavor->msg;
grilio_channel_remove_all_handlers(io, self->ril_event_id);
self->flavor = flavor;
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
grilio_channel_add_unsol_event_handler(io,
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_registration_suspended,
msg->unsol_registration_suspended, self);
if (msg->unsol_set_attach_apn) {
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
grilio_channel_add_unsol_event_handler(io,
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_set_attach_apn,
msg->unsol_set_attach_apn, self);
}
if (msg->unsol_ps_network_state_changed) {
self->ril_event_id[MTK_EVENT_PS_NETWORK_STATE_CHANGED] =
grilio_channel_add_unsol_event_handler(io,
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_ps_network_state_changed,
msg->unsol_ps_network_state_changed, self);
}
if (msg->unsol_incoming_call_indication) {
self->ril_event_id[MTK_EVENT_INCOMING_CALL_INDICATION] =
grilio_channel_add_unsol_event_handler(io,
ril_vendor_mtk_incoming_call_indication,
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_call_state_changed,
msg->unsol_incoming_call_indication, self);
}
}
static RilVendor *ril_vendor_mtk_create_from_data(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
static void ril_vendor_mtk_hook_init(struct ril_vendor_hook_mtk *self,
const struct ril_vendor_mtk_driver_data *mtk_driver_data,
ril_vendor_hook_free_proc free, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config, struct ril_network *network)
{
const struct ril_mtk_flavor *flavor = driver_data;
RilVendorMtk *mtk = g_object_new(RIL_VENDOR_TYPE_MTK, NULL);
ril_vendor_mtk_base_init(mtk, io, path, config);
ril_vendor_mtk_set_flavor(mtk, flavor);
DBG("%s slot %u", flavor->name, mtk->slot);
return &mtk->vendor;
self->msg = mtk_driver_data->msg;
self->q = grilio_queue_new(io);
self->io = grilio_channel_ref(io);
self->watch = sailfish_watch_new(path);
self->slot = config->slot;
self->network = ril_network_ref(network);
self->watch_event_id[WATCH_EVENT_IMSI_CHANGED] =
sailfish_watch_add_imsi_changed_handler(self->watch,
ril_vendor_mtk_watch_imsi_changed, self);
self->network_event_id[NETWORK_EVENT_PREF_MODE_CHANGED] =
ril_network_add_pref_mode_changed_handler(self->network,
ril_vendor_mtk_network_pref_mode_changed, self);
ril_vendor_mtk_hook_subscribe(self);
ril_vendor_hook_init(&self->hook, mtk_driver_data->proc, free);
}
static void ril_vendor_mtk_init(RilVendorMtk *self)
static void ril_vendor_mtk_destroy(struct ril_vendor_hook_mtk *self)
{
grilio_queue_cancel_all(self->q, FALSE);
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
grilio_queue_unref(self->q);
grilio_channel_unref(self->io);
sailfish_watch_remove_all_handlers(self->watch, self->watch_event_id);
sailfish_watch_unref(self->watch);
ril_network_remove_all_handlers(self->network, self->network_event_id);
ril_network_unref(self->network);
}
static void ril_vendor_mtk_finalize(GObject* object)
static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
{
RilVendorMtk *self = RIL_VENDOR_MTK(object);
RilVendor *vendor = &self->vendor;
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
DBG("slot %u", self->slot);
grilio_queue_cancel_all(self->q, FALSE);
grilio_queue_unref(self->q);
ofono_watch_unref(self->watch);
grilio_channel_remove_all_handlers(vendor->io, self->ril_event_id);
G_OBJECT_CLASS(ril_vendor_mtk_parent_class)->finalize(object);
ril_vendor_mtk_destroy(self);
g_free(self);
}
static void ril_vendor_mtk_class_init(RilVendorMtkClass* klass)
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config,
struct ril_network *network)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_finalize;
klass->request_to_string = ril_vendor_mtk_request_to_string;
klass->event_to_string = ril_vendor_mtk_event_to_string;
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;
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
struct ril_vendor_hook_mtk *self =
g_new0(struct ril_vendor_hook_mtk, 1);
ril_vendor_mtk_hook_init(self, mtk_driver_data, ril_vendor_mtk_free,
io, path, config, network);
DBG("%s slot %u", mtk_driver_data->name, self->slot);
return &self->hook;
}
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,
.signal_strength_fn = &ril_vendor_mtk_signal_strength_1
static const struct ril_vendor_hook_proc ril_vendor_mtk_hook_base_proc = {
.request_to_string = ril_vendor_mtk_request_to_string,
.event_to_string = ril_vendor_mtk_event_to_string,
.data_call_req = ril_vendor_mtk_data_call_req
};
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,
.signal_strength_fn = &ril_vendor_mtk_signal_strength_2
static const struct ril_vendor_driver ril_vendor_mtk_base = {
.get_defaults = ril_vendor_mtk_get_defaults,
.create_hook = ril_vendor_mtk_create_hook_from_data
};
#define DEFAULT_MTK_TYPE (&ril_mtk_flavor1)
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk1_data = {
.name = "mtk1",
.msg = &msg_mtk1,
.proc = &ril_vendor_mtk_hook_base_proc
};
static const struct ril_mtk_flavor *mtk_flavors [] = {
&ril_mtk_flavor1,
&ril_mtk_flavor2
static struct ril_vendor_hook_proc ril_vendor_mtk2_proc = {
.base = &ril_vendor_mtk_hook_base_proc,
.data_call_parse = ril_vendor_mtk_data_call_parse_v6
};
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk2_data = {
.name = "mtk2",
.msg = &msg_mtk2,
.proc = &ril_vendor_mtk2_proc
};
#define DEFAULT_MTK_TYPE (&ril_vendor_mtk1_data)
static const struct ril_vendor_mtk_driver_data *mtk_types [] = {
&ril_vendor_mtk1_data,
&ril_vendor_mtk2_data
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk1) {
.name = "mtk1",
.driver_data = &ril_mtk_flavor1,
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_create_from_data
.driver_data = &ril_vendor_mtk1_data,
.base = &ril_vendor_mtk_base
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk2) {
.name = "mtk2",
.driver_data = &ril_mtk_flavor2,
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_create_from_data
.driver_data = &ril_vendor_mtk2_data,
.base = &ril_vendor_mtk_base
};
/* Auto-selection */
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
static gboolean ril_vendor_mtk_auto_set_type
(struct ril_vendor_hook_mtk_auto *self,
const struct ril_vendor_mtk_driver_data *type)
{
struct ril_vendor_hook_mtk *mtk = &self->mtk;
gboolean changed = FALSE;
if (self->type != type) {
DBG("switching type %s -> %s", self->type->name, type->name);
self->type = type;
mtk->msg = type->msg;
mtk->hook.proc = type->proc;
grilio_channel_remove_all_handlers(mtk->io, mtk->ril_event_id);
ril_vendor_mtk_hook_subscribe(mtk);
changed = TRUE;
}
grilio_channel_remove_handler(mtk->io, self->detect_id);
self->detect_id = 0;
return changed;
}
static void ril_vendor_mtk_auto_detect_event(GRilIoChannel *io, guint id,
const void *data, guint len, void *self)
{
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(user_data);
guint i;
for (i = 0; i < G_N_ELEMENTS(mtk_flavors); i++) {
const struct ril_mtk_flavor *flavor = mtk_flavors[i];
const struct ril_mtk_msg *msg = flavor->msg;
for (i = 0; i < G_N_ELEMENTS(mtk_types); i++) {
const struct ril_vendor_mtk_driver_data *type = mtk_types[i];
const struct ril_mtk_msg *msg = type->msg;
const guint *ids = &msg->unsol_msgs;
guint j;
for (j = 0; j < MTK_UNSOL_MSGS; j++) {
if (ids[j] == id) {
DBG("event %u is %s %s", id, flavor->name,
DBG("event %u is %s %s", id, type->name,
ril_vendor_mtk_unsol_msg_name(msg,id));
ril_vendor_mtk_set_flavor(&self->mtk, flavor);
/* We are done */
grilio_channel_remove_handler(io,
self->detect_id);
self->detect_id = 0;
/* And repeat the event to invoke the handler */
grilio_channel_inject_unsol_event(io, id,
data, len);
if (ril_vendor_mtk_auto_set_type(self, type)) {
/* And repeat the event to invoke
* the handler */
grilio_channel_inject_unsol_event(io,
id, data, len);
}
return;
}
}
}
}
static void ril_vendor_mtk_auto_init(RilVendorMtkAuto *self)
static void ril_vendor_mtk_auto_free(struct ril_vendor_hook *hook)
{
struct ril_vendor_hook_mtk_auto *self =
ril_vendor_hook_mtk_auto_cast(hook);
struct ril_vendor_hook_mtk *mtk = &self->mtk;
DBG("slot %u", mtk->slot);
grilio_channel_remove_handler(mtk->io, self->detect_id);
ril_vendor_mtk_destroy(mtk);
g_free(self);
}
static void ril_vendor_mtk_auto_finalize(GObject* object)
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_auto
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg, struct ril_network *network)
{
RilVendorMtkAuto *self = RIL_VENDOR_MTK_AUTO(object);
struct ril_vendor_hook_mtk_auto *self =
g_new0(struct ril_vendor_hook_mtk_auto, 1);
struct ril_vendor_hook_mtk *mtk = &self->mtk;
DBG("slot %u", self->mtk.slot);
grilio_channel_remove_handler(self->mtk.vendor.io, self->detect_id);
G_OBJECT_CLASS(ril_vendor_mtk_auto_parent_class)->finalize(object);
}
static void ril_vendor_mtk_auto_class_init(RilVendorMtkAutoClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = ril_vendor_mtk_auto_finalize;
}
static RilVendor *ril_vendor_mtk_auto_create_vendor(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
RilVendorMtkAuto *self = g_object_new(RIL_VENDOR_TYPE_MTK_AUTO, NULL);
RilVendorMtk *mtk = &self->mtk;
ril_vendor_mtk_base_init(mtk, io, path, config);
ril_vendor_mtk_set_flavor(mtk, DEFAULT_MTK_TYPE);
DBG("%s slot %u", mtk->flavor->name, mtk->slot);
/* Pick the default */
self->type = DEFAULT_MTK_TYPE;
ril_vendor_mtk_hook_init(mtk, self->type, ril_vendor_mtk_auto_free,
io, path, cfg, network);
DBG("%s slot %u", self->type->name, mtk->slot);
/*
* Subscribe for (all) unsolicited events. Keep on listening until
* we receive an MTK specific event that tells us which particular
* kind of MTK adaptation we are using.
*/
self->detect_id = grilio_channel_add_unsol_event_handler(io,
self->detect_id = grilio_channel_add_unsol_event_handler(mtk->io,
ril_vendor_mtk_auto_detect_event, 0, self);
return &mtk->vendor;
return &mtk->hook;
}
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
.name = "mtk",
.get_defaults = ril_vendor_mtk_get_defaults,
.create_vendor = ril_vendor_mtk_auto_create_vendor
.create_hook = ril_vendor_mtk_create_hook_auto
};
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2019 Jolla Ltd.
* Copyright (C) 2015-2017 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
@@ -587,75 +587,39 @@ static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
grilio_request_unref(ioreq);
}
static void ril_voicecall_hangup(struct ofono_voicecall *vc,
gboolean (*filter)(struct ofono_call *call),
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
struct ril_voicecall_request_data *req = NULL;
GSList *l;
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
if (vd->calls) {
GSList *l;
struct ril_voicecall_request_data *req =
ril_voicecall_request_data_new(vc, cb, data);
if (!filter || filter(call)) {
if (!req) {
req = ril_voicecall_request_data_new(vc, cb,
data);
}
/*
* Here the idea is that we submit (potentially) multiple
* hangup requests to RIL and invoke the callback after
* the last request has completed (pending call count
* becomes zero).
*/
for (l = vd->calls; l; l = l->next) {
struct ofono_call *call = l->data;
/* Send request to RIL */
DBG("Hanging up call with id %d", call->id);
ril_voicecall_submit_hangup_req(vc, call->id, req);
} else {
DBG("Skipping call with id %d", call->id);
}
}
if (req) {
/* Release our reference (if any) */
/* Release our reference */
ril_voicecall_request_data_unref(req);
} else {
/* No requests were submitted */
/* No calls */
struct ofono_error error;
cb(ril_error_ok(&error), data);
}
}
static gboolean ril_voicecall_hangup_active_filter(struct ofono_call *call)
{
switch (call->status) {
case CALL_STATUS_ACTIVE:
case CALL_STATUS_DIALING:
case CALL_STATUS_ALERTING:
case CALL_STATUS_INCOMING:
return TRUE;
case CALL_STATUS_HELD:
case CALL_STATUS_WAITING:
case CALL_STATUS_DISCONNECTED:
break;
}
return FALSE;
}
static void ril_voicecall_hangup_active(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_hangup(vc, ril_voicecall_hangup_active_filter, cb, data);
}
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
ril_voicecall_hangup(vc, NULL, cb, data);
}
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
int id, ofono_voicecall_cb_t cb, void *data)
{
@@ -693,7 +657,7 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
grilio_parser_get_int32(&rilp, &type);
grilio_parser_get_int32(&rilp, &code);
grilio_parser_get_int32(&rilp, &index);
grilio_parser_get_int32(&rilp, &phone.type);
grilio_parser_get_int32(&rilp, NULL);
tmp = grilio_parser_get_utf8(&rilp);
if (tmp) {
@@ -704,18 +668,13 @@ static void ril_voicecall_supp_svc_notification_event(GRilIoChannel *io,
phone.number[0] = 0;
}
DBG("RIL data: MT/MO: %d, code: %d, index: %d", type, code, index);
DBG("RIL data: MT/MO: %i, code: %i, index: %i", type, code, index);
switch (type) {
case 0: /* MO intermediate result code */
ofono_voicecall_ssn_mo_notify(vd->vc, 0, code, index);
break;
case 1: /* MT unsolicited result code */
/* 0 stands for MO intermediate (support TBD), 1 for MT unsolicited */
if (type == 1) {
ofono_voicecall_ssn_mt_notify(vd->vc, 0, code, index, &phone);
break;
default:
} else {
ofono_error("Unknown SS notification");
break;
}
}
@@ -852,7 +811,8 @@ static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
ofono_voicecall_cb_t cb, void *data)
{
DBG("");
ril_voicecall_request(RIL_REQUEST_UDUB, vc, NULL, cb, data);
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
vc, NULL, cb, data);
}
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
@@ -986,7 +946,6 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
.remove = ril_voicecall_remove,
.dial = ril_voicecall_dial,
.answer = ril_voicecall_answer,
.hangup_active = ril_voicecall_hangup_active,
.hangup_all = ril_voicecall_hangup_all,
.release_specific = ril_voicecall_release_specific,
.send_tones = ril_voicecall_send_dtmf,

View File

@@ -1,255 +0,0 @@
/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Intel Corporation. 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/log.h>
#include <ofono/ims.h>
#include "gatchat.h"
#include "gatresult.h"
#include "xmm7modem.h"
static const char *none_prefix[] = { NULL };
static const char *cireg_prefix[] = { "+CIREG:", NULL };
struct ims_driver_data {
GAtChat *chat;
};
static void xmm_cireg_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_ims_status_cb_t cb = cbd->cb;
struct ofono_error error;
GAtResultIter iter;
int reg_info, ext_info;
DBG("ok %d", ok);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, -1, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (g_at_result_iter_next(&iter, "+CIREG:") == FALSE)
goto error;
/* skip value of n */
g_at_result_iter_skip_next(&iter);
if (g_at_result_iter_next_number(&iter, &reg_info) == FALSE)
goto error;
if (reg_info == 0)
ext_info = -1;
else
if (g_at_result_iter_next_number(&iter, &ext_info) == FALSE)
goto error;
cb(&error, reg_info, ext_info, cbd->data);
return;
error:
CALLBACK_WITH_FAILURE(cb, -1, -1, cbd->data);
}
static void xmm_ims_registration_status(struct ofono_ims *ims,
ofono_ims_status_cb_t cb, void *data)
{
struct ims_driver_data *idd = ofono_ims_get_data(ims);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(idd->chat, "AT+CIREG?", cireg_prefix,
xmm_cireg_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, -1, -1, data);
g_free(cbd);
}
static void xmm_ims_register_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_ims_register_cb_t cb = cbd->cb;
struct ofono_error error;
DBG("ok %d", ok);
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
}
static void xmm_ims_register(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
struct ims_driver_data *idd = ofono_ims_get_data(ims);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(idd->chat, "AT+XIREG=1", none_prefix,
xmm_ims_register_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static void xmm_ims_unregister(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
struct ims_driver_data *idd = ofono_ims_get_data(ims);
struct cb_data *cbd = cb_data_new(cb, data);
if (g_at_chat_send(idd->chat, "AT+XIREG=0", none_prefix,
xmm_ims_register_cb, cbd, g_free) > 0)
return;
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static void ciregu_notify(GAtResult *result, gpointer user_data)
{
struct ofono_ims *ims = user_data;
int reg_info, ext_info;
GAtResultIter iter;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CIREGU:"))
return;
if (!g_at_result_iter_next_number(&iter, &reg_info))
return;
if (reg_info == 0)
ext_info = -1;
else
if (!g_at_result_iter_next_number(&iter, &ext_info))
return;
DBG("reg_info:%d, ext_info:%d", reg_info, ext_info);
ofono_ims_status_notify(ims, reg_info, ext_info);
}
static void xmm_cireg_set_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_ims *ims = user_data;
if (!ok) {
ofono_ims_remove(ims);
return;
}
ofono_ims_register(ims);
}
static void cireg_support_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct ofono_ims *ims = user_data;
struct ims_driver_data *idd = ofono_ims_get_data(ims);
if (!ok) {
ofono_ims_remove(ims);
return;
}
g_at_chat_register(idd->chat, "+CIREGU:", ciregu_notify,
FALSE, ims, NULL);
g_at_chat_send(idd->chat, "AT+CIREG=2", none_prefix,
xmm_cireg_set_cb, ims, NULL);
}
static int xmm_ims_probe(struct ofono_ims *ims, void *data)
{
GAtChat *chat = data;
struct ims_driver_data *idd;
DBG("at ims probe");
idd = g_try_new0(struct ims_driver_data, 1);
if (!idd)
return -ENOMEM;
idd->chat = g_at_chat_clone(chat);
ofono_ims_set_data(ims, idd);
g_at_chat_send(idd->chat, "AT+CIREG=?", cireg_prefix,
cireg_support_cb, ims, NULL);
return 0;
}
static void xmm_ims_remove(struct ofono_ims *ims)
{
struct ims_driver_data *idd = ofono_ims_get_data(ims);
DBG("at ims remove");
g_at_chat_unref(idd->chat);
ofono_ims_set_data(ims, NULL);
g_free(idd);
}
static struct ofono_ims_driver driver = {
.name = "xmm7modem",
.probe = xmm_ims_probe,
.remove = xmm_ims_remove,
.ims_register = xmm_ims_register,
.ims_unregister = xmm_ims_unregister,
.registration_status = xmm_ims_registration_status,
};
void xmm_ims_init(void)
{
ofono_ims_driver_register(&driver);
}
void xmm_ims_exit(void)
{
ofono_ims_driver_unregister(&driver);
}

View File

@@ -36,7 +36,6 @@
static int xmm7modem_init(void)
{
xmm_radio_settings_init();
xmm_ims_init();
return 0;
}
@@ -44,7 +43,6 @@ static int xmm7modem_init(void)
static void xmm7modem_exit(void)
{
xmm_radio_settings_exit();
xmm_ims_exit();
}
OFONO_PLUGIN_DEFINE(xmm7modem, "Intel xmm7xxx series modem driver",

View File

@@ -25,6 +25,3 @@
extern void xmm_radio_settings_init(void);
extern void xmm_radio_settings_exit(void);
extern void xmm_ims_init(void);
extern void xmm_ims_exit(void);

View File

@@ -54,7 +54,7 @@ static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
unsigned int len = sizeof(saddr);
int fd;
struct ofono_emulator *em;
GList *i;
struct ofono_modem *modem;
if (cond != G_IO_IN)
return FALSE;
@@ -63,16 +63,15 @@ static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
if (fd == -1)
return FALSE;
DBG("Using all modems for emulator.");
/* Pick the first powered modem */
modem = modems->data;
DBG("Picked modem %p for emulator", modem);
em = ofono_emulator_create(GPOINTER_TO_INT(user));
if (em) {
for (i = modems; i; i = i->next)
ofono_emulator_add_modem(em, i->data);
ofono_emulator_register(em, fd);
} else
em = ofono_emulator_create(modem, GPOINTER_TO_INT(user));
if (em == NULL)
close(fd);
else
ofono_emulator_register(em, fd);
return TRUE;
}

View File

@@ -1,173 +0,0 @@
/*
* oFono - Open Source Telephony
*
* 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
* 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_ACCESS_H
#define __OFONO_DBUS_ACCESS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ofono/types.h>
enum ofono_dbus_access {
OFONO_DBUS_ACCESS_DENY, /* Deny access */
OFONO_DBUS_ACCESS_ALLOW, /* Allow access */
OFONO_DBUS_ACCESS_DONT_CARE /* No decision */
};
enum ofono_dbus_access_intf {
OFONO_DBUS_ACCESS_INTF_MESSAGE, /* org.ofono.Message */
OFONO_DBUS_ACCESS_INTF_MESSAGEMGR, /* org.ofono.MessageManager */
OFONO_DBUS_ACCESS_INTF_VOICECALL, /* org.ofono.VoiceCall */
OFONO_DBUS_ACCESS_INTF_VOICECALLMGR, /* org.ofono.VoiceCallManager */
OFONO_DBUS_ACCESS_INTF_CONNCTX, /* org.ofono.ConnectionContext */
OFONO_DBUS_ACCESS_INTF_CONNMGR, /* org.ofono.ConnectionManager */
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
};
/* OFONO_DBUS_ACCESS_INTF_MESSAGE */
enum ofono_dbus_access_message_method {
OFONO_DBUS_ACCESS_MESSAGE_CANCEL,
OFONO_DBUS_ACCESS_MESSAGE_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_MESSAGEMGR */
enum ofono_dbus_access_messagemgr_method {
OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_MESSAGE,
OFONO_DBUS_ACCESS_MESSAGEMGR_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_VOICECALL */
enum ofono_dbus_access_voicecall_method {
OFONO_DBUS_ACCESS_VOICECALL_DEFLECT,
OFONO_DBUS_ACCESS_VOICECALL_HANGUP,
OFONO_DBUS_ACCESS_VOICECALL_ANSWER,
OFONO_DBUS_ACCESS_VOICECALL_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_VOICECALLMGR */
enum ofono_dbus_access_voicecallmgr_method {
OFONO_DBUS_ACCESS_VOICECALLMGR_DIAL,
OFONO_DBUS_ACCESS_VOICECALLMGR_TRANSFER,
OFONO_DBUS_ACCESS_VOICECALLMGR_SWAP_CALLS,
OFONO_DBUS_ACCESS_VOICECALLMGR_RELEASE_AND_ANSWER,
OFONO_DBUS_ACCESS_VOICECALLMGR_RELEASE_AND_SWAP,
OFONO_DBUS_ACCESS_VOICECALLMGR_HOLD_AND_ANSWER,
OFONO_DBUS_ACCESS_VOICECALLMGR_HANGUP_ALL,
OFONO_DBUS_ACCESS_VOICECALLMGR_CREATE_MULTIPARTY,
OFONO_DBUS_ACCESS_VOICECALLMGR_HANGUP_MULTIPARTY,
OFONO_DBUS_ACCESS_VOICECALLMGR_SEND_TONES,
OFONO_DBUS_ACCESS_VOICECALLMGR_REGISTER_VOICECALL_AGENT,
OFONO_DBUS_ACCESS_VOICECALLMGR_UNREGISTER_VOICECALL_AGENT,
OFONO_DBUS_ACCESS_VOICECALLMGR_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_CONNCTX */
enum ofono_dbus_access_connctx_method {
OFONO_DBUS_ACCESS_CONNCTX_SET_PROPERTY,
OFONO_DBUS_ACCESS_CONNCTX_PROVISION_CONTEXT,
OFONO_DBUS_ACCESS_CONNCTX_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_CONNMGR */
enum ofono_dbus_access_connmgr_method {
OFONO_DBUS_ACCESS_CONNMGR_SET_PROPERTY,
OFONO_DBUS_ACCESS_CONNMGR_DEACTIVATE_ALL,
OFONO_DBUS_ACCESS_CONNMGR_RESET_CONTEXTS,
OFONO_DBUS_ACCESS_CONNMGR_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_SIMMGR */
enum ofono_dbus_access_simmgr_method {
OFONO_DBUS_ACCESS_SIMMGR_SET_PROPERTY,
OFONO_DBUS_ACCESS_SIMMGR_CHANGE_PIN,
OFONO_DBUS_ACCESS_SIMMGR_ENTER_PIN,
OFONO_DBUS_ACCESS_SIMMGR_RESET_PIN,
OFONO_DBUS_ACCESS_SIMMGR_LOCK_PIN,
OFONO_DBUS_ACCESS_SIMMGR_UNLOCK_PIN,
OFONO_DBUS_ACCESS_SIMMGR_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_MODEM */
enum ofono_dbus_access_modem_method {
OFONO_DBUS_ACCESS_MODEM_SET_PROPERTY,
OFONO_DBUS_ACCESS_MODEM_METHOD_COUNT
};
/* OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS */
enum ofono_dbus_access_radiosettings_method {
OFONO_DBUS_ACCESS_RADIOSETTINGS_SET_PROPERTY,
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)
struct ofono_dbus_access_plugin {
const char *name;
int priority;
enum ofono_dbus_access (*method_access)(const char *sender,
enum ofono_dbus_access_intf intf,
int method, const char *arg);
void (*_reserved[10])(void);
/* api_level will remain zero (and ignored) until we run out of
* the above placeholders. */
int api_level;
};
int ofono_dbus_access_plugin_register
(const struct ofono_dbus_access_plugin *plugin);
void ofono_dbus_access_plugin_unregister
(const struct ofono_dbus_access_plugin *plugin);
const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf);
const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
int method);
#ifdef __cplusplus
}
#endif
#endif /* __OFONO_DBUS_ACCESS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -59,16 +59,12 @@ extern "C" {
#define OFONO_LOCATION_REPORTING_INTERFACE OFONO_SERVICE ".LocationReporting"
#define OFONO_GNSS_INTERFACE "org.ofono.AssistedSatelliteNavigation"
#define OFONO_GNSS_POSR_AGENT_INTERFACE "org.ofono.PositioningRequestAgent"
#define OFONO_USIM_APPLICATION_INTERFACE "org.ofono.USimApplication"
#define OFONO_ISIM_APPLICATION_INTERFACE "org.ofono.ISimApplication"
#define OFONO_SIM_AUTHENTICATION_INTERFACE "org.ofono.SimAuthentication"
#define OFONO_HANDSFREE_INTERFACE OFONO_SERVICE ".Handsfree"
#define OFONO_NETWORK_TIME_INTERFACE OFONO_SERVICE ".NetworkTime"
#define OFONO_SIRI_INTERFACE OFONO_SERVICE ".Siri"
#define OFONO_NETMON_INTERFACE OFONO_SERVICE ".NetworkMonitor"
#define OFONO_NETMON_AGENT_INTERFACE OFONO_SERVICE ".NetworkMonitorAgent"
#define OFONO_LTE_INTERFACE OFONO_SERVICE ".LongTermEvolution"
#define OFONO_IMS_INTERFACE OFONO_SERVICE ".IpMultimediaSystem"
/* CDMA Interfaces */
#define OFONO_CDMA_VOICECALL_MANAGER_INTERFACE "org.ofono.cdma.VoiceCallManager"

View File

@@ -63,8 +63,6 @@ void ofono_devinfo_remove(struct ofono_devinfo *info);
void ofono_devinfo_set_data(struct ofono_devinfo *info, void *data);
void *ofono_devinfo_get_data(struct ofono_devinfo *info);
struct ofono_modem *ofono_devinfo_get_modem(struct ofono_devinfo *info);
#ifdef __cplusplus
}
#endif

View File

@@ -68,9 +68,8 @@ typedef void (*ofono_emulator_request_cb_t)(struct ofono_emulator *em,
struct ofono_emulator_request *req,
void *data);
struct ofono_emulator *ofono_emulator_create(enum ofono_emulator_type type);
void ofono_emulator_add_modem(struct ofono_emulator *em,
struct ofono_modem *modem);
struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
enum ofono_emulator_type type);
void ofono_emulator_register(struct ofono_emulator *em, int fd);

View File

@@ -122,8 +122,6 @@ void ofono_gprs_context_set_ipv4_address(struct ofono_gprs_context *gc,
ofono_bool_t static_ip);
void ofono_gprs_context_set_ipv4_netmask(struct ofono_gprs_context *gc,
const char *netmask);
void ofono_gprs_context_set_ipv4_prefix_length(struct ofono_gprs_context *gc,
unsigned int prefix);
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,

View File

@@ -22,14 +22,12 @@ extern "C" {
#include <ofono/types.h>
struct ofono_gprs;
struct ofono_gprs_context;
struct ofono_gprs_primary_context;
/* If ctx is NULL then activation gets cancelled */
typedef void (*ofono_gprs_filter_activate_cb_t)
(const struct ofono_gprs_primary_context *ctx, void *data);
typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
#define OFONO_GPRS_FILTER_PRIORITY_LOW (-100)
#define OFONO_GPRS_FILTER_PRIORITY_DEFAULT (0)
@@ -40,7 +38,7 @@ typedef void (*ofono_gprs_filter_check_cb_t)(ofono_bool_t allow, void *data);
* even if struct ofono_gprs_filter gets extended with new callbacks.
*/
#define OFONO_GPRS_FILTER_API_VERSION (1)
#define OFONO_GPRS_FILTER_API_VERSION (0)
/*
* The filter callbacks either invoke the completion callback directly
@@ -61,9 +59,6 @@ struct ofono_gprs_filter {
const struct ofono_gprs_primary_context *ctx,
ofono_gprs_filter_activate_cb_t cb,
void *data);
/* API version 1 */
unsigned int (*filter_check)(struct ofono_gprs *gprs,
ofono_gprs_filter_check_cb_t cb, void *data);
};
int ofono_gprs_filter_register(const struct ofono_gprs_filter *filter);

View File

@@ -26,9 +26,10 @@
extern "C" {
#endif
#include <ofono/gprs-context.h>
#include <ofono/types.h>
struct ofono_gprs;
struct ofono_gprs_context;
typedef void (*ofono_gprs_status_cb_t)(const struct ofono_error *error,
int status, void *data);
@@ -82,11 +83,6 @@ void ofono_gprs_add_context(struct ofono_gprs *gprs,
void ofono_gprs_cid_activated(struct ofono_gprs *gprs, unsigned int cid,
const char *apn);
void ofono_gprs_attached_update(struct ofono_gprs *gprs);
const struct ofono_gprs_primary_context *ofono_gprs_context_settings_by_type
(struct ofono_gprs *gprs, enum ofono_gprs_context_type type);
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More