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
276 changed files with 13957 additions and 39066 deletions

25
ofono/.gitignore vendored
View File

@@ -9,7 +9,7 @@ Makefile.in
aclocal.m4
config.guess
config.h
config.h.in*
config.h.in
config.log
config.status
config.sub
@@ -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
@@ -42,34 +40,25 @@ unit/test-sms-root
unit/test-simutil
unit/test-mux
unit/test-caif
unit/test-cell-info
unit/test-cell-info-dbus
unit/test-stkutil
unit/test-cdmasms
unit/test-conf
unit/test-dbus-access
unit/test-dbus-clients
unit/test-dbus-queue
unit/test-gprs-filter
unit/test-ril_config
unit/test-ril_ecclist
unit/test-ril_util
unit/test-ril_vendor
unit/test-ril-transport
unit/test-rilmodem-cb
unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_access
unit/test-slot-manager
unit/test-watch
unit/test-sim-info
unit/test-sim-info-dbus
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-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,11 +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>
Mariem Cherif <mariem.cherif@ardia.com.tn>
Bassem Boubaker <bassem.boubaker@actia.fr>
Bob Ham <bob.ham@puri.sm>
Varun Gargi <varun.gargi@intel.com>
Florent Beillonnet <florent.beillonnet@gmail.com>

View File

@@ -1,34 +1,3 @@
ver 1.24:
Fix issue with property changed signals and CDMA networks.
Fix issue with handling SIM filesystem and SIM removal.
Fix issue with handling PIN state and incorrect codes.
Fix issue with handling of parsing AID type.
Fix issue with SIM detection and QMI devices.
Fix issue with PIN handling and QMI devices.
Fix issue with USSD handling and QMI devices.
Fix issue with handling USSD TERMINATED response.
Fix issue with handling USSD reset and STK REFRESH.
Add support for detecting Gemalto ALS3 modems.
Add support for SIMCom based SIM7100E modems.
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,16 +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/dbus-clients.h \
include/netmon.h include/lte.h include/ims.h \
include/slot.h include/cell-info.h \
include/storage.h include/conf.h include/misc.h \
include/mtu-limit.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)))
@@ -65,7 +66,7 @@ endif
builtin_modules =
builtin_sources =
builtin_libadd =
builtin_cflags = -DSAILFISH_OS
builtin_cflags =
noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
@@ -121,13 +122,15 @@ builtin_modules += udevng
builtin_sources += plugins/udevng.c
endif
if SAILFISH_ACCESS
builtin_modules += sailfish_access
builtin_sources += plugins/sailfish_access.c
endif
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
if SAILFISH_MANAGER
builtin_modules += sailfish_manager
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.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 \
plugins/sailfish_manager/sailfish_watch.c
endif
if RILMODEM
@@ -140,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 \
@@ -176,6 +172,10 @@ builtin_sources += drivers/ril/ril_call_barring.c \
# Vendor specific extensions
builtin_sources += drivers/ril/ril_vendor_mtk.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
else
builtin_sources += $(gril_sources)
@@ -281,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) \
@@ -298,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
@@ -331,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
@@ -467,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
@@ -564,9 +562,6 @@ builtin_sources += plugins/samsung.c
builtin_modules += sim900
builtin_sources += plugins/sim900.c
builtin_modules += sim7100
builtin_sources += plugins/sim7100.c
builtin_modules += connman
builtin_sources += plugins/connman.c
@@ -712,39 +707,10 @@ 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 \
src/mtu-watch.c \
src/main.c src/ofono.h src/log.c src/plugin.c \
src/modem.c src/common.h src/common.c \
src/manager.c src/dbus.c src/util.h src/util.c \
@@ -770,16 +736,10 @@ 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-clients.c src/dbus-queue.c src/dbus-access.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/netmonagent.c src/netmonagent.h \
src/slot-manager.c src/slot-manager-dbus.c \
src/cell-info.c src/cell-info-dbus.c \
src/sim-info.c src/sim-info-dbus.c \
src/conf.c src/mtu-limit.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) \
@GLIB_LIBS@ @DBUS_LIBS@ -ldl
@@ -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
@@ -830,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 \
@@ -940,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
@@ -966,114 +921,92 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
unit/test-simutil unit/test-stkutil \
unit/test-sms unit/test-cdmasms
unit_test_cell_info_SOURCES = unit/test-cell-info.c src/cell-info.c src/log.c
unit_test_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT)
unit_test_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_cell_info_OBJECTS)
unit_tests += unit/test-cell-info
if SAILFISH_MANAGER
unit_test_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-cell-info-dbus.c unit/fake_cell_info.c \
src/cell-info.c src/cell-info-dbus.c \
gdbus/object.c src/dbus-clients.c \
src/dbus.c src/log.c
unit_test_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@
unit_test_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_cell_info_dbus_OBJECTS)
unit_tests += unit/test-cell-info-dbus
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-Iplugins/sailfish_manager
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info
unit_test_sim_info_SOURCES = unit/test-sim-info.c unit/fake_watch.c \
src/sim-info.c src/storage.c src/watchlist.c src/log.c
unit_test_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-DSTORAGEDIR='"/tmp/ofono"'
unit_test_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sim_info_OBJECTS)
unit_tests += unit/test-sim-info
unit_test_sim_info_dbus_SOURCES = unit/test-sim-info-dbus.c \
unit/test-dbus.c unit/fake_watch.c \
src/sim-info.c src/sim-info-dbus.c \
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-sailfish_cell_info_dbus.c \
unit/fake_sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
gdbus/object.c \
src/dbus.c src/storage.c src/watchlist.c src/log.c
unit_test_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"'
unit_test_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sim-info-dbus
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@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_slot_manager_SOURCES = unit/test-slot-manager.c unit/fake_watch.c \
src/slot-manager.c src/cell-info.c src/sim-info.c \
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
src/storage.c src/watch.c src/log.c
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
-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_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/watch.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@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_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_slot_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-DSTORAGEDIR='"/tmp/ofono"'
unit_test_slot_manager_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_slot_manager_OBJECTS)
unit_tests += unit/test-slot-manager
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-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
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
unit_test_conf_SOURCES = unit/test-conf.c drivers/ril/ril_util.c \
src/conf.c src/util.c src/log.c
unit_test_conf_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_conf_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_conf_OBJECTS)
unit_tests += unit/test-conf
unit_test_ril_config_SOURCES = unit/test-ril_config.c drivers/ril/ril_util.c \
drivers/ril/ril_config.c src/conf.c src/util.c src/log.c
drivers/ril/ril_config.c src/log.c
unit_test_ril_config_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
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/util.c src/log.c
src/log.c
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
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/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 \
@@ -1084,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
@@ -1150,14 +1076,6 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
src/dbus-clients.c gdbus/object.c \
src/dbus.c src/log.c
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_clients_OBJECTS)
unit_tests += unit/test-dbus-clients
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
src/dbus-queue.c gdbus/object.c \
src/dbus.c src/log.c
@@ -1175,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)
@@ -1196,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 \
@@ -1241,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.24)
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.49, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.49 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

@@ -278,13 +278,6 @@ Properties boolean Active [readwrite]
via this proxy. All other values are left
out in this case.
array{string} ProxyCSCF [readonly, optional]
Holds the list of P-CSCF (SIP proxy) for this
context. Only used by IMS connections.
This is a Sailfish OS specific extension.
dict IPv6.Settings [readonly, optional]
Holds all the IPv6 network settings
@@ -311,13 +304,6 @@ Properties boolean Active [readwrite]
Holds the gateway IP for this connection.
array{string} ProxyCSCF [readonly, optional]
Holds the list of P-CSCF (SIP proxy) for this
context. Only used by IMS connections.
This is a Sailfish OS specific extension.
string MessageProxy [readwrite, MMS only]
Holds the MMS Proxy setting.

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

@@ -48,51 +48,6 @@ struct cbs_data {
unsigned int vendor;
};
static void at_xmm_etw_sec_notify(GAtResult *result, gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
const char *hexpdu;
int pdulen;
GAtResultIter iter;
unsigned char pdu[88];
long hexpdulen;
DBG("");
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+XETWSECWARN:"))
return;
if (!g_at_result_iter_next_number(&iter, &pdulen))
return;
if (pdulen != 88) {
ofono_error("Got a CBM message with invalid PDU size!");
return;
}
hexpdu = g_at_result_pdu(result);
if (hexpdu == NULL) {
ofono_error("Got a CBM, but no PDU. Are we in text mode?");
return;
}
DBG("Got new Cell Broadcast via XETWSECWARN: %s, %d", hexpdu, pdulen);
if (decode_hex_own_buf(hexpdu, -1, &hexpdulen, 0, pdu) == NULL) {
ofono_error("Unable to hex-decode the PDU");
return;
}
if (hexpdulen != pdulen) {
ofono_error("hexpdu length not equal to reported pdu length");
return;
}
ofono_cbs_notify(cbs, pdu, pdulen);
}
static void at_cbm_notify(GAtResult *result, gpointer user_data)
{
struct ofono_cbs *cbs = user_data;
@@ -169,10 +124,6 @@ static void at_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
NULL, NULL, NULL);
break;
case OFONO_VENDOR_XMM:
g_at_chat_send(data->chat, "AT+XETWNTFYSTART=2", none_prefix,
NULL, NULL, NULL);
break;
default:
break;
}
@@ -200,10 +151,6 @@ static void at_cbs_clear_topics(struct ofono_cbs *cbs,
DBG("");
if (data->vendor == OFONO_VENDOR_XMM)
g_at_chat_send(data->chat, "AT+XETWNTFYSTOP=2", none_prefix,
NULL, NULL, NULL);
if (g_at_chat_send(data->chat, "AT+CSCB=0", none_prefix,
at_cscb_set_cb, cbd, g_free) > 0)
return;
@@ -228,10 +175,6 @@ static void at_cbs_register(gboolean ok, GAtResult *result, gpointer user)
*/
g_at_chat_register(data->chat, "+CBM:", at_cbm_notify, TRUE, cbs, NULL);
if (data->vendor == OFONO_VENDOR_XMM)
g_at_chat_register(data->chat, "+XETWSECWARN:",
at_xmm_etw_sec_notify, TRUE, cbs, NULL);
ofono_cbs_register(cbs);
}
@@ -280,13 +223,6 @@ static int at_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
ofono_cbs_set_data(cbs, data);
if (vendor == OFONO_VENDOR_XMM) {
g_at_chat_send(data->chat, "AT+XCMAS=1", cscb_prefix,
NULL, NULL, NULL);
g_at_chat_send(data->chat, "AT+XETWCFG=1,1,0,0; ", none_prefix,
NULL, NULL, NULL);
}
g_at_chat_send(data->chat, "AT+CSCB=?", cscb_prefix,
at_cscb_support_cb, cbs, NULL);

View File

@@ -91,7 +91,7 @@ static gboolean lte_delayed_register(gpointer user_data)
return FALSE;
}
static int at_lte_probe(struct ofono_lte *lte, unsigned int vendor, void *data)
static int at_lte_probe(struct ofono_lte *lte, void *data)
{
GAtChat *chat = data;
struct lte_driver_data *ldd;

View File

@@ -48,7 +48,6 @@ static const char *cops_prefix[] = { "+COPS:", NULL };
static const char *csq_prefix[] = { "+CSQ:", NULL };
static const char *cind_prefix[] = { "+CIND:", NULL };
static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *smoni_prefix[] = { "^SMONI:", NULL };
static const char *zpas_prefix[] = { "+ZPAS:", NULL };
static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
@@ -179,31 +178,6 @@ static int option_parse_tech(GAtResult *result)
return tech;
}
static int cinterion_parse_tech(GAtResult *result)
{
int tech = -1;
GAtResultIter iter;
const char *technology;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "^SMONI: "))
return tech;
if (!g_at_result_iter_next_unquoted_string(&iter, &technology))
return tech;
if (strcmp(technology, "2G") == 0) {
tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
} else if (strcmp(technology, "3G") == 0) {
tech = ACCESS_TECHNOLOGY_UTRAN;
} else if (strcmp(technology, "4G") == 0) {
tech = ACCESS_TECHNOLOGY_EUTRAN;
}
return tech;
}
static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -231,18 +205,6 @@ static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, status, lac, ci, tech, cbd->data);
}
static void cinterion_query_tech_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct tech_query *tq = user_data;
int tech;
tech = cinterion_parse_tech(result);
ofono_netreg_status_notify(tq->netreg,
tq->status, tq->lac, tq->ci, tech);
}
static void zte_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
@@ -1556,12 +1518,6 @@ static void creg_notify(GAtResult *result, gpointer user_data)
option_query_tech_cb, tq, g_free) > 0)
return;
break;
case OFONO_VENDOR_CINTERION:
if (g_at_chat_send(nd->chat, "AT^SMONI",
smoni_prefix,
cinterion_query_tech_cb, tq, g_free) > 0)
return;
break;
}
g_free(tq);

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));
@@ -1359,12 +1411,12 @@ static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
char buf[64];
int ret;
cbd->user = sim;
cbd->user = sd;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, 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

@@ -104,7 +104,7 @@ static void at_csca_set(struct ofono_sms *sms,
{
struct sms_data *data = ofono_sms_get_data(sms);
struct cb_data *cbd = cb_data_new(cb, user_data);
char buf[128];
char buf[64];
snprintf(buf, sizeof(buf), "AT+CSCA=\"%s\",%d", sca->number, sca->type);

View File

@@ -1120,7 +1120,6 @@ static int at_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
switch (vd->vendor) {
case OFONO_VENDOR_QUALCOMM_MSM:
case OFONO_VENDOR_SIMCOM:
g_at_chat_send(vd->chat, "AT+COLP=0", NULL, NULL, NULL, NULL);
break;
default:

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

@@ -129,7 +129,6 @@ static void get_ids_cb(struct qmi_result *result, void *user_data)
str = qmi_result_get_string(result, QMI_DMS_RESULT_ESN);
/* Telit qmi modems return a "0" string when ESN is not available. */
if (!str || strcmp(str, "0") == 0) {
qmi_free(str);
str = qmi_result_get_string(result, QMI_DMS_RESULT_IMEI);
if (!str) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);

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,265 +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,
unsigned int vendor, 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

@@ -47,13 +47,6 @@ struct discovery {
qmi_destroy_func_t destroy;
};
struct qmi_version {
uint8_t type;
uint16_t major;
uint16_t minor;
const char *name;
};
struct qmi_device {
int ref_count;
int fd;
@@ -87,6 +80,7 @@ struct qmi_device {
struct qmi_service {
int ref_count;
struct qmi_device *device;
bool shared;
uint8_t type;
uint16_t major;
uint16_t minor;
@@ -167,25 +161,25 @@ void qmi_free(void *ptr)
static struct qmi_request *__request_alloc(uint8_t service,
uint8_t client, uint16_t message,
const void *data,
uint16_t headroom, const void *data,
uint16_t length, qmi_message_func_t func,
void *user_data)
void *user_data, void **head)
{
struct qmi_request *req;
struct qmi_mux_hdr *hdr;
struct qmi_message_hdr *msg;
uint16_t headroom;
req = g_new0(struct qmi_request, 1);
if (service == QMI_SERVICE_CONTROL)
headroom = QMI_CONTROL_HDR_SIZE;
else
headroom = QMI_SERVICE_HDR_SIZE;
req = g_try_new0(struct qmi_request, 1);
if (!req)
return NULL;
req->len = QMI_MUX_HDR_SIZE + headroom + QMI_MESSAGE_HDR_SIZE + length;
req->buf = g_malloc(req->len);
req->buf = g_try_malloc(req->len);
if (!req->buf) {
g_free(req);
return NULL;
}
req->client = client;
@@ -209,6 +203,8 @@ static struct qmi_request *__request_alloc(uint8_t service,
req->callback = func;
req->user_data = user_data;
*head = req->buf + QMI_MUX_HDR_SIZE;
return req;
}
@@ -260,6 +256,9 @@ static gboolean __service_compare_shared(gpointer key, gpointer value,
struct qmi_service *service = value;
uint8_t type = GPOINTER_TO_UINT(user_data);
if (!service->shared)
return FALSE;
if (service->type == type)
return TRUE;
@@ -477,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)
{
@@ -696,37 +684,14 @@ static void wakeup_writer(struct qmi_device *device)
can_write_data, device, write_watch_destroy);
}
static uint16_t __request_submit(struct qmi_device *device,
struct qmi_request *req)
static void __request_submit(struct qmi_device *device,
struct qmi_request *req, uint16_t transaction)
{
struct qmi_mux_hdr *mux;
mux = req->buf;
if (mux->service == QMI_SERVICE_CONTROL) {
struct qmi_control_hdr *hdr;
hdr = req->buf + QMI_MUX_HDR_SIZE;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
if (device->next_control_tid == 0)
device->next_control_tid = 1;
req->tid = hdr->transaction;
} else {
struct qmi_service_hdr *hdr;
hdr = req->buf + QMI_MUX_HDR_SIZE;
hdr->type = 0x00;
hdr->transaction = device->next_service_tid++;
if (device->next_service_tid < 256)
device->next_service_tid = 256;
req->tid = hdr->transaction;
}
req->tid = transaction;
g_queue_push_tail(device->req_queue, req);
wakeup_writer(device);
return req->tid;
}
static void service_notify(gpointer key, gpointer value, gpointer user_data)
@@ -985,9 +950,6 @@ struct qmi_device *qmi_device_new(int fd)
device->service_list = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, service_destroy);
device->next_control_tid = 1;
device->next_service_tid = 256;
return device;
}
@@ -1105,48 +1067,12 @@ static const void *tlv_get(const void *data, uint16_t size,
return NULL;
}
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
uint16_t *major, uint16_t *minor)
{
struct qmi_version *info;
int i;
for (i = 0, info = device->version_list;
i < device->version_count;
i++, info++) {
if (info->type == type) {
*major = info->major;
*minor = info->minor;
return true;
}
}
return false;
}
bool qmi_device_has_service(struct qmi_device *device, uint8_t type)
{
struct qmi_version *info;
int i;
for (i = 0, info = device->version_list;
i < device->version_count;
i++, info++) {
if (info->type == type) {
return true;
}
}
return false;
}
struct discover_data {
struct discovery super;
struct qmi_device *device;
qmi_discover_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
uint8_t tid;
guint timeout;
};
@@ -1207,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;
@@ -1226,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);
@@ -1234,12 +1160,19 @@ 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;
if (data->func)
data->func(data->user_data);
data->func(count, list, data->user_data);
__qmi_device_discovery_complete(data->device, &data->super);
}
@@ -1248,37 +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(data->user_data);
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;
}
@@ -1288,7 +1198,7 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
{
struct discover_data *data;
struct qmi_request *req;
uint8_t tid;
struct qmi_control_hdr *hdr;
if (!device)
return false;
@@ -1312,12 +1222,20 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
}
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_VERSION_INFO,
NULL, 0, discover_callback, data);
QMI_CTL_GET_VERSION_INFO, QMI_CONTROL_HDR_SIZE,
NULL, 0, discover_callback, data, (void **) &hdr);
if (!req) {
g_free(data);
return false;
}
tid = __request_submit(device, req);
if (device->next_control_tid < 1)
device->next_control_tid = 1;
data->tid = tid;
hdr->type = 0x00;
hdr->transaction = device->next_control_tid++;
__request_submit(device, req, hdr->transaction);
data->timeout = g_timeout_add_seconds(5, discover_reply, data);
__qmi_device_discovery_started(device, &data->super);
@@ -1331,13 +1249,24 @@ static void release_client(struct qmi_device *device,
{
unsigned char release_req[] = { 0x01, 0x02, 0x00, type, client_id };
struct qmi_request *req;
struct qmi_control_hdr *hdr;
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_RELEASE_CLIENT_ID,
QMI_CTL_RELEASE_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
release_req, sizeof(release_req),
func, user_data);
func, user_data, (void **) &hdr);
if (!req) {
func(0x0000, 0x0000, NULL, user_data);
return;
}
__request_submit(device, req);
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);
}
static void shutdown_destroy(gpointer user_data)
@@ -1394,58 +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 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,
NULL, 0,
qmi_device_sync_callback, func_data);
__request_submit(device, req);
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)
{
@@ -1932,6 +1809,7 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
struct service_create_data {
struct discovery super;
struct qmi_device *device;
bool shared;
uint8_t type;
uint16_t major;
uint16_t minor;
@@ -2002,6 +1880,7 @@ static void service_create_callback(uint16_t message, uint16_t length,
service->ref_count = 1;
service->device = data->device;
service->shared = data->shared;
service->type = data->type;
service->major = data->major;
@@ -2024,52 +1903,100 @@ done:
__qmi_device_discovery_complete(data->device, &data->super);
}
static bool service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
static void service_create_discover(uint8_t count,
const struct qmi_version *list, void *user_data)
{
struct service_create_data *data;
unsigned char client_req[] = { 0x01, 0x01, 0x00, type };
struct service_create_data *data = user_data;
struct qmi_device *device = data->device;
struct qmi_request *req;
int i;
struct qmi_control_hdr *hdr;
unsigned char client_req[] = { 0x01, 0x01, 0x00, data->type };
unsigned int i;
data = g_try_new0(struct service_create_data, 1);
if (!data)
return false;
__debug_device(device, "service create [type=%d]", data->type);
if (!device->version_list)
return false;
data->super.destroy = service_create_data_free;
data->device = device;
data->type = type;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
__debug_device(device, "service create [type=%d]", type);
for (i = 0; i < device->version_count; i++) {
if (device->version_list[i].type == data->type) {
data->major = device->version_list[i].major;
data->minor = device->version_list[i].minor;
for (i = 0; i < count; i++) {
if (list[i].type == data->type) {
data->major = list[i].major;
data->minor = list[i].minor;
break;
}
}
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_CLIENT_ID,
QMI_CTL_GET_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
client_req, sizeof(client_req),
service_create_callback, data);
service_create_callback, data, (void **) &hdr);
if (!req) {
if (data->timeout > 0)
g_source_remove(data->timeout);
__request_submit(device, req);
data->timeout = g_timeout_add_seconds(0,
service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return;
}
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);
}
static bool service_create(struct qmi_device *device, bool shared,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
struct service_create_data *data;
data = g_try_new0(struct service_create_data, 1);
if (!data)
return false;
data->super.destroy = service_create_data_free;
data->device = device;
data->shared = shared;
data->type = type;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
if (device->version_list) {
service_create_discover(device->version_count,
device->version_list, data);
goto done;
}
if (qmi_device_discover(device, service_create_discover, data, NULL))
goto done;
g_free(data);
return false;
done:
data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
__qmi_device_discovery_started(device, &data->super);
return true;
}
bool qmi_service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
if (!device || !func)
return false;
if (type == QMI_SERVICE_CONTROL)
return false;
return service_create(device, false, type, func, user_data, destroy);
}
struct service_create_shared_data {
struct discovery super;
struct qmi_service *service;
@@ -2145,15 +2072,7 @@ bool qmi_service_create_shared(struct qmi_device *device,
return 0;
}
return service_create(device, type, func, user_data, destroy);
}
bool qmi_service_create(struct qmi_device *device,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
return qmi_service_create_shared(device, type, func,
user_data, destroy);
return service_create(device, true, type, func, user_data, destroy);
}
static void service_release_callback(uint16_t message, uint16_t length,
@@ -2230,6 +2149,8 @@ bool qmi_service_get_version(struct qmi_service *service,
}
struct service_send_data {
struct qmi_service *service;
struct qmi_param *param;
qmi_result_func_t func;
void *user_data;
qmi_destroy_func_t destroy;
@@ -2240,6 +2161,8 @@ static void service_send_free(struct service_send_data *data)
if (data->destroy)
data->destroy(data->user_data);
qmi_param_free(data->param);
g_free(data);
}
@@ -2280,7 +2203,7 @@ uint16_t qmi_service_send(struct qmi_service *service,
struct qmi_device *device;
struct service_send_data *data;
struct qmi_request *req;
uint16_t tid;
struct qmi_service_hdr *hdr;
if (!service)
return 0;
@@ -2296,21 +2219,31 @@ uint16_t qmi_service_send(struct qmi_service *service,
if (!data)
return 0;
data->service = service;
data->param = param;
data->func = func;
data->user_data = user_data;
data->destroy = destroy;
req = __request_alloc(service->type, service->client_id,
message,
param ? param->data : NULL,
param ? param->length : 0,
service_send_callback, data);
message, QMI_SERVICE_HDR_SIZE,
data->param ? data->param->data : NULL,
data->param ? data->param->length : 0,
service_send_callback, data, (void **) &hdr);
if (!req) {
g_free(data);
return 0;
}
qmi_param_free(param);
if (device->next_service_tid < 256)
device->next_service_tid = 256;
tid = __request_submit(device, req);
hdr->type = 0x00;
hdr->transaction = device->next_service_tid++;
return tid;
__request_submit(device, req, hdr->transaction);
return hdr->transaction;
}
bool qmi_service_cancel(struct qmi_service *service, uint16_t id)

View File

@@ -61,6 +61,13 @@ enum qmi_device_expected_data_format {
QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP,
};
struct qmi_version {
uint8_t type;
uint16_t major;
uint16_t minor;
const char *name;
};
void qmi_free(void *ptr);
typedef void (*qmi_destroy_func_t)(void *user_data);
@@ -69,9 +76,10 @@ 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)(void *user_data);
typedef void (*qmi_discover_func_t)(uint8_t count,
const struct qmi_version *list, void *user_data);
struct qmi_device *qmi_device_new(int fd);
@@ -88,14 +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_has_service(struct qmi_device *device, uint8_t type);
bool qmi_device_get_service_version(struct qmi_device *device, uint8_t type,
uint16_t *major, uint16_t *minor);
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,
@@ -140,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

@@ -493,15 +493,8 @@ static bool get_card_status(const struct qmi_uim_slot_info *slot,
case 0x03: /* PUK1 or PUK for UPIN is required */
sim_stat->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
break;
case 0x00: /* Unknown */
case 0x01: /* Detected */
case 0x04: /* Personalization state must be checked. */
case 0x05: /* PIN1 blocked */
case 0x06: /* Illegal */
/*
* This could be temporary, we should retry and
* expect another result
*/
/* This is temporary, we could retry and get another result */
sim_stat->passwd_state = OFONO_SIM_PASSWORD_INVALID;
need_retry = true;
break;
@@ -564,7 +557,7 @@ static enum get_card_status_result handle_get_card_status_result(
index = GUINT16_FROM_LE(status->index_gw_pri);
if ((index & 0xff) == n && (index >> 8) == i) {
if ((index & 0xff) == i && (index >> 8) == n) {
if (get_card_status(slot, info1, info2,
sim_stat))
res = GET_CARD_STATUS_RESULT_TEMP_ERROR;
@@ -602,32 +595,20 @@ static void query_passwd_state_cb(struct qmi_result *result,
struct sim_status sim_stat;
enum get_card_status_result res;
struct cb_data *retry_cbd;
unsigned int i;
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim_stat.retries[i] = -1;
res = handle_get_card_status_result(result, &sim_stat);
switch (res) {
case GET_CARD_STATUS_RESULT_OK:
DBG("passwd state %d", sim_stat.passwd_state);
data->retry_count = 0;
if (sim_stat.passwd_state == OFONO_SIM_PASSWORD_INVALID) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
} else
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state,
cbd->data);
CALLBACK_WITH_SUCCESS(cb, sim_stat.passwd_state, cbd->data);
break;
case GET_CARD_STATUS_RESULT_TEMP_ERROR:
data->retry_count++;
if (data->retry_count > MAX_RETRY_COUNT) {
DBG("Failed after %d attempts. Card state:%d",
data->retry_count,
sim_stat.card_state);
DBG("Failed after %d attempts", data->retry_count);
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
} else {
DBG("Retry command");
retry_cbd = cb_data_new(cb, cbd->data);
@@ -641,7 +622,6 @@ static void query_passwd_state_cb(struct qmi_result *result,
DBG("Command failed");
data->retry_count = 0;
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
ofono_sim_inserted_notify(sim, FALSE);
break;
}
}
@@ -670,13 +650,9 @@ static void query_pin_retries_cb(struct qmi_result *result, void *user_data)
struct cb_data *cbd = user_data;
ofono_sim_pin_retries_cb_t cb = cbd->cb;
struct sim_status sim_stat;
unsigned int i;
DBG("");
for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
sim_stat.retries[i] = -1;
if (handle_get_card_status_result(result, &sim_stat) !=
GET_CARD_STATUS_RESULT_OK) {
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);

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);
g_free(utf8);
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(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-2021 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,10 +14,11 @@
*/
#include "ril_plugin.h"
#include "ril_sim_card.h"
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
/* See 3GPP 27.007 7.4 for possible values */
#define RIL_MAX_SERVICE_LENGTH 3
@@ -25,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;
};
@@ -105,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);
@@ -122,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);
@@ -175,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,
@@ -236,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);
@@ -254,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-2021 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
@@ -17,7 +17,7 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/netreg.h>
#include "common.h"
struct ril_call_forward {
GRilIoQueue *q;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -17,6 +17,8 @@
#include "ril_util.h"
#include "ril_log.h"
#include "common.h"
struct ril_call_settings {
GRilIoQueue *q;
guint timer_id;

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-2021 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,11 +23,10 @@
#include <grilio_request.h>
#include <grilio_parser.h>
#include <gutil_idlepool.h>
#include <gutil_macros.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;
@@ -36,20 +34,19 @@ typedef struct ril_cell_info RilCellInfo;
struct ril_cell_info {
GObject object;
struct ofono_cell_info info;
struct ofono_cell **cells;
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;
guint set_rate_id;
gboolean enabled;
};
enum ril_cell_info_signal {
@@ -61,79 +58,58 @@ enum ril_cell_info_signal {
static guint ril_cell_info_signals[SIGNAL_COUNT] = { 0 };
#define PARENT_TYPE G_TYPE_OBJECT
#define PARENT_CLASS ril_cell_info_parent_class
#define THIS_TYPE (ril_cell_info_get_type())
#define THIS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), THIS_TYPE, RilCellInfo))
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, PARENT_TYPE)
G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
#define RIL_CELL_INFO_TYPE (ril_cell_info_get_type())
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
RIL_CELL_INFO_TYPE, RilCellInfo))
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
static const char *ril_cell_info_int_format(int value, const char *format)
static inline void ril_cell_free(struct sailfish_cell *cell)
{
if (value == OFONO_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;
}
g_slice_free(struct sailfish_cell, cell);
}
static gint ril_cell_info_list_sort_cb(gconstpointer a, gconstpointer b)
static void ril_cell_free1(gpointer cell)
{
return ofono_cell_compare_location(*(struct ofono_cell **)a,
*(struct ofono_cell **)b);
ril_cell_free(cell);
}
static gboolean ril_cell_info_list_identical(const ofono_cell_ptr *l1,
const ofono_cell_ptr *l2)
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
{
if (l1 && l2) {
while (*l1 && *l2) {
if (memcmp(*l1, *l2, sizeof(struct ofono_cell))) {
return FALSE;
}
l1++;
l2++;
while (l1 && l2) {
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
return FALSE;
}
return !*l1 && !*l2;
} else {
return (!l1 || !*l1) && (!l2 || !*l2);
l1 = l1->next;
l2 = l2->next;
}
return !l1 && !l2;
}
/* Takes ownership of GPtrArray */
static void ril_cell_info_update_cells(RilCellInfo *self, GPtrArray *l)
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
{
if (l && !ril_cell_info_list_identical(self->cells,
(struct ofono_cell **)l->pdata)) {
gutil_ptrv_free((void**)self->cells);
self->info.cells = (struct ofono_cell **)
g_ptr_array_free(l, FALSE);
if (!ril_cell_info_list_identical(self->info.cells, l)) {
g_slist_free_full(self->info.cells, ril_cell_free1);
self->info.cells = l;
g_signal_emit(self, ril_cell_info_signals
[SIGNAL_CELLS_CHANGED], 0);
} else if (l) {
g_ptr_array_set_free_func(l, g_free);
g_ptr_array_free(l, TRUE);
} else {
g_slist_free_full(l, ril_cell_free1);
}
}
static struct ofono_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
struct ofono_cell_info_gsm *gsm = &cell->info.gsm;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
/* Optional RIL_CellIdentityGsm_v12 part */
gsm->arfcn = OFONO_CELL_INVALID_VALUE;
gsm->bsic = OFONO_CELL_INVALID_VALUE;
gsm->arfcn = SAILFISH_CELL_INVALID_VALUE;
gsm->bsic = SAILFISH_CELL_INVALID_VALUE;
/* Optional RIL_GSM_SignalStrength_v12 part */
gsm->timingAdvance = OFONO_CELL_INVALID_VALUE;
gsm->timingAdvance = SAILFISH_CELL_INVALID_VALUE;
/* RIL_CellIdentityGsm */
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
grilio_parser_get_int32(rilp, &gsm->mnc) &&
@@ -147,35 +123,29 @@ static struct ofono_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"));
cell->type = OFONO_CELL_TYPE_GSM;
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;
}
ofono_error("failed to parse GSM cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static struct ofono_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
struct ofono_cell_info_wcdma *wcdma = &cell->info.wcdma;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
/* Optional RIL_CellIdentityWcdma_v12 part */
wcdma->uarfcn = OFONO_CELL_INVALID_VALUE;
wcdma->uarfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
grilio_parser_get_int32(rilp, &wcdma->lac) &&
@@ -185,34 +155,28 @@ static struct ofono_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"));
cell->type = OFONO_CELL_TYPE_WCDMA;
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;
}
ofono_error("failed to parse WCDMA cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static struct ofono_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
guint version, gboolean registered)
{
struct ofono_cell *cell = g_new0(struct ofono_cell, 1);
struct ofono_cell_info_lte *lte = &cell->info.lte;
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
struct sailfish_cell_info_lte *lte = &cell->info.lte;
/* Optional RIL_CellIdentityLte_v12 part */
lte->earfcn = OFONO_CELL_INVALID_VALUE;
lte->earfcn = SAILFISH_CELL_INVALID_VALUE;
if (grilio_parser_get_int32(rilp, &lte->mcc) &&
grilio_parser_get_int32(rilp, &lte->mnc) &&
grilio_parser_get_int32(rilp, &lte->ci) &&
@@ -226,31 +190,23 @@ static struct ofono_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"));
cell->type = OFONO_CELL_TYPE_LTE;
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;
}
ofono_error("failed to parse LTE cell info");
g_free(cell);
ril_cell_free(cell);
return NULL;
}
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
struct ofono_cell **cell_ptr)
struct sailfish_cell **cell_ptr)
{
int type, reg;
@@ -259,7 +215,7 @@ static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
/* Skip timestamp */
grilio_parser_get_int32_array(rilp, NULL, 3)) {
int skip = 0;
struct ofono_cell *cell = NULL;
struct sailfish_cell *cell = NULL;
/* Normalize the boolean value */
reg = (reg != FALSE);
@@ -300,25 +256,23 @@ static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
return FALSE;
}
static GPtrArray *ril_cell_info_parse_list(guint v, const void *data, guint len)
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
{
GPtrArray *l = NULL;
GSList *l = NULL;
GRilIoParser rilp;
int i, n;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
struct ofono_cell *c;
struct sailfish_cell *c;
l = g_ptr_array_sized_new(n + 1);
DBG("%d cell(s):", n);
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
if (c) {
g_ptr_array_add(l, c);
l = g_slist_insert_sorted(l, c,
sailfish_cell_compare_func);
}
}
g_ptr_array_sort(l, ril_cell_info_list_sort_cb);
g_ptr_array_add(l, NULL);
}
GASSERT(grilio_parser_at_end(&rilp));
@@ -328,7 +282,7 @@ static GPtrArray *ril_cell_info_parse_list(guint v, const void *data, guint len)
static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
RilCellInfo *self = THIS(user_data);
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
ril_cell_info_update_cells(self, ril_cell_info_parse_list
@@ -338,46 +292,30 @@ static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
RilCellInfo *self = THIS(user_data);
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
GASSERT(self->query_id);
self->query_id = 0;
ril_cell_info_update_cells(self,
(status == RIL_E_SUCCESS && self->enabled) ?
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
}
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
RilCellInfo *self = THIS(user_data);
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
DBG_(self, "");
GASSERT(self->set_rate_id);
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)
{
RilCellInfo *self = THIS(user_data);
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return self->enabled;
}
}
static void ril_cell_info_query(RilCellInfo *self)
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,
@@ -385,14 +323,13 @@ static void ril_cell_info_query(RilCellInfo *self)
grilio_request_unref(req);
}
static void ril_cell_info_set_rate(RilCellInfo *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->enabled) ?
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,
@@ -400,11 +337,24 @@ static void ril_cell_info_set_rate(RilCellInfo *self)
grilio_request_unref(req);
}
static void ril_cell_info_refresh(RilCellInfo *self)
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 */
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
self->sim_card_ready) {
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
ril_cell_info_query(self);
} else {
ril_cell_info_update_cells(self, NULL);
@@ -413,7 +363,7 @@ static void ril_cell_info_refresh(RilCellInfo *self)
static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
{
RilCellInfo *self = THIS(arg);
struct ril_cell_info *self = RIL_CELL_INFO(arg);
DBG_(self, "%s", ril_radio_state_to_string(radio->state));
ril_cell_info_refresh(self);
@@ -421,109 +371,95 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
{
RilCellInfo *self = THIS(arg);
struct ril_cell_info *self = RIL_CELL_INFO(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);
}
/* ofono_cell_info interface callbacks */
/* sailfish_cell_info interface callbacks */
typedef struct ril_cell_info_closure {
GCClosure cclosure;
ofono_cell_info_cb_t cb;
struct ril_cell_info_signal_data {
sailfish_cell_info_cb_t cb;
void *arg;
} RilCellInfoClosure;
};
static inline RilCellInfo *ril_cell_info_cast(struct ofono_cell_info *info)
static inline struct ril_cell_info *ril_cell_info_cast
(struct sailfish_cell_info *info)
{
return G_CAST(info, RilCellInfo, info);
return G_CAST(info, struct ril_cell_info, info);
}
static void ril_cell_info_ref_proc(struct ofono_cell_info *info)
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
{
g_object_ref(ril_cell_info_cast(info));
}
static void ril_cell_info_unref_proc(struct ofono_cell_info *info)
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
{
g_object_unref(ril_cell_info_cast(info));
}
static void ril_cell_info_cells_changed_cb(RilCellInfo *self,
RilCellInfoClosure *closure)
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
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
(struct ofono_cell_info *info, ofono_cell_info_cb_t cb, void *arg)
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg)
{
if (cb) {
RilCellInfoClosure *closure = (RilCellInfoClosure *)
g_closure_new_simple(sizeof(RilCellInfoClosure), 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;
}
}
static void ril_cell_info_remove_handler_proc(struct ofono_cell_info *info,
gulong id)
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
gulong id)
{
if (G_LIKELY(id)) {
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
}
}
static void ril_cell_info_set_update_interval_proc
(struct ofono_cell_info *info, int ms)
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, MceDisplay *display,
struct ril_radio *radio, struct ril_sim_card *sim_card)
{
RilCellInfo *self = ril_cell_info_cast(info);
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
};
if (self->update_rate_ms != ms) {
self->update_rate_ms = ms;
DBG_(self, "%d ms", ms);
if (self->enabled && self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
}
void ril_cell_info_set_enabled_proc(struct ofono_cell_info *info,
gboolean enabled)
{
RilCellInfo *self = ril_cell_info_cast(info);
if (self->enabled != enabled) {
self->enabled = enabled;
DBG_(self, "%d", enabled);
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
}
struct ofono_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card)
{
RilCellInfo *self = g_object_new(THIS_TYPE, 0);
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]) ?
@@ -531,6 +467,9 @@ struct ofono_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);
@@ -539,34 +478,17 @@ struct ofono_cell_info *ril_cell_info_new(GRilIoChannel *io,
ril_cell_info_sim_status_cb, self);
self->sim_card_ready = ril_sim_card_ready(sim_card);
ril_cell_info_refresh(self);
/* Disable updates by default */
self->enabled = FALSE;
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
ril_cell_info_update_rate(self);
return &self->info;
}
static void ril_cell_info_init(RilCellInfo *self)
static void ril_cell_info_init(struct ril_cell_info *self)
{
static const struct ofono_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_set_enabled_proc
};
self->update_rate_ms = DEFAULT_UPDATE_RATE_MS;
self->info.cells = self->cells = g_new0(struct ofono_cell*, 1);
self->info.proc = &ril_cell_info_proc;
}
static void ril_cell_info_dispose(GObject *object)
{
RilCellInfo *self = THIS(object);
struct ril_cell_info *self = RIL_CELL_INFO(object);
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
if (self->query_id) {
@@ -578,25 +500,26 @@ static void ril_cell_info_dispose(GObject *object)
FALSE);
self->set_rate_id = 0;
}
/* xxx_remove_handlers() zero the ids */
ril_radio_remove_handlers(self->radio,
&self->radio_state_event_id, 1);
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);
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
&self->sim_status_event_id, 1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
}
static void ril_cell_info_finalize(GObject *object)
{
RilCellInfo *self = THIS(object);
struct ril_cell_info *self = RIL_CELL_INFO(object);
DBG_(self, "");
gutil_ptrv_free((void**)self->cells);
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_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
g_slist_free_full(self->info.cells, ril_cell_free1);
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
}
static void ril_cell_info_class_init(RilCellInfoClass *klass)

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2021 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>
#include <ofono/cell-info.h>
struct ofono_cell_info *ril_cell_info_new(GRilIoChannel *io,
const char *log_prefix, struct ril_radio *radio,
struct ril_sim_card *sim_card);
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
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-2021 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>
@@ -28,10 +26,168 @@
/* Utilities for parsing ril_subscription.conf */
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
{
char *val = g_key_file_get_string(file, group, key, NULL);
if (!val && strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
val = g_key_file_get_string(file, RILCONF_SETTINGS_GROUP, key,
NULL);
}
return val;
}
char **ril_config_get_strings(GKeyFile *file, const char *group,
const char *key, char delimiter)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
char **strv, **p;
char delimiter_str[2];
delimiter_str[0] = delimiter;
delimiter_str[1] = 0;
strv = g_strsplit(str, delimiter_str, -1);
/* Strip whitespaces */
for (p = strv; *p; p++) {
*p = g_strstrip(*p);
}
g_free(str);
return strv;
}
return NULL;
}
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *out_value)
{
GError *error = NULL;
int value = g_key_file_get_integer(file, group, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
} else {
g_error_free(error);
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
error = NULL;
value = g_key_file_get_integer(file,
RILCONF_SETTINGS_GROUP, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
}
g_error_free(error);
}
return FALSE;
}
}
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *out_value)
{
GError *error = NULL;
gboolean value = g_key_file_get_boolean(file, group, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
} else {
g_error_free(error);
if (strcmp(group, RILCONF_SETTINGS_GROUP)) {
/* Check the common section */
error = NULL;
value = g_key_file_get_boolean(file,
RILCONF_SETTINGS_GROUP, key, &error);
if (!error) {
if (out_value) {
*out_value = value;
}
return TRUE;
}
g_error_free(error);
}
return FALSE;
}
}
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
const char *key, int flag, int *flags)
{
gboolean value;
if (ril_config_get_boolean(file, group, key, &value)) {
if (value) {
*flags |= flag;
} else {
*flags &= ~flag;
}
return TRUE;
} else {
return FALSE;
}
}
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
const char *key, int *result,
const char *name, int value, ...)
{
char *str = ril_config_get_string(file, group, key);
if (str) {
/*
* Some people are thinking that # is a comment
* anywhere on the line, not just at the beginning
*/
char *comment = strchr(str, '#');
if (comment) *comment = 0;
g_strstrip(str);
if (strcasecmp(str, name)) {
va_list args;
va_start(args, value);
while ((name = va_arg(args, char*)) != NULL) {
value = va_arg(args, int);
if (!strcasecmp(str, name)) {
break;
}
}
va_end(args);
}
if (!name) {
ofono_error("Invalid %s config value (%s)", key, str);
}
g_free(str);
if (name) {
if (result) {
*result = value;
}
return TRUE;
}
}
return FALSE;
}
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
const char *key)
{
char *value = ofono_conf_get_string(file, group, key);
char *value = ril_config_get_string(file, group, key);
if (value) {
GUtilIntArray *array = gutil_int_array_new();
@@ -50,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);
}
}
@@ -80,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-2021 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
@@ -19,10 +18,25 @@
#include "ril_types.h"
#include <ofono/conf.h>
/* Utilities for parsing ril_subscription.conf */
#define RILCONF_SETTINGS_GROUP OFONO_COMMON_SETTINGS_GROUP
#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,
const char *key, char delimiter);
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
const char *key, int *value);
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
const char *key, gboolean *value);
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, ...);
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,621 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 <ofono/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-2021 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,8 +28,11 @@
#include <grilio_parser.h>
#include <grilio_request.h>
/* Yes, it does sometimes take minutes in roaming */
#define SETUP_DATA_CALL_TIMEOUT (300*1000) /* ms */
#define DATA_PROFILE_DEFAULT_STR "0"
#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,
@@ -76,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,
@@ -101,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 {
@@ -169,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;
@@ -189,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)
{
@@ -241,7 +227,6 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
dc->dnses = g_strdupv(call->dnses);
dc->gateways = g_strdupv(call->gateways);
dc->addresses = g_strdupv(call->addresses);
dc->pcscf = g_strdupv(call->pcscf);
return dc;
} else {
return NULL;
@@ -252,9 +237,8 @@ static void ril_data_call_destroy(struct ril_data_call *call)
{
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->gateways);
g_strfreev(call->addresses);
g_strfreev(call->pcscf);
g_strfreev(call->gateways);
}
void ril_data_call_free(struct ril_data_call *call)
@@ -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);
}
@@ -322,7 +334,8 @@ static gboolean ril_data_call_parse_default(struct ril_data_call *call,
/* RIL_Data_Call_Response_v9 */
if (version >= 9) {
call->pcscf = grilio_parser_split_utf8(rilp, " ");
/* PCSCF */
grilio_parser_skip_string(rilp);
/* RIL_Data_Call_Response_v11 */
if (version >= 11) {
@@ -335,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) {
@@ -353,19 +366,16 @@ static struct ril_data_call *ril_data_call_parse(struct ril_vendor *vendor,
if (parsed) {
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
"mtu=%d,address=%s,dns=%s %s,gateways=%s,pcscf=%s %s]",
"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] : "",
call->dnses ? call->dnses[0] : "",
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
(call->dnses && call->dnses[0] &&
call->dnses[1]) ? call->dnses[1] : "",
call->gateways ? call->gateways[0] : "",
call->pcscf ? call->pcscf[0] : "",
(call->pcscf && call->pcscf[0] &&
call->pcscf[1]) ? call->pcscf[1] : "");
call->gateways ? call->gateways[0] : NULL);
return call;
} else {
ril_data_call_free(call);
@@ -374,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;
@@ -395,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) {
@@ -431,8 +441,7 @@ static gboolean ril_data_call_equal(const struct ril_data_call *c1,
!g_strcmp0(c1->ifname, c2->ifname) &&
gutil_strv_equal(c1->dnses, c2->dnses) &&
gutil_strv_equal(c1->gateways, c2->gateways) &&
gutil_strv_equal(c1->addresses, c2->addresses) &&
gutil_strv_equal(c1->pcscf, c2->pcscf);
gutil_strv_equal(c1->addresses, c2->addresses);
} else {
return FALSE;
}
@@ -444,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;
@@ -528,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);
@@ -540,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,
@@ -614,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,
@@ -631,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);
@@ -825,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)
{
@@ -861,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) {
@@ -874,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 ==
OFONO_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);
@@ -940,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;
@@ -954,19 +861,37 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
*
* Makes little sense but it is what it is.
*/
tech = (setup->profile_id == RIL_DATA_PROFILE_IMS) ?
RADIO_TECH_LTE : priv->network->data.ril_tech;
tech = priv->network->data.ril_tech;
if (tech > 2) {
tech += 2;
} else {
/*
* This value used to be hardcoded, let's keep using it
* as the default.
*/
tech = RADIO_TECH_HSPA;
}
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) {
@@ -974,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);
@@ -983,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);
@@ -1004,30 +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 = RIL_DATA_PROFILE_DEFAULT;
if (priv->use_data_profiles) {
switch (context_type) {
case OFONO_GPRS_CONTEXT_TYPE_MMS:
setup->profile_id = priv->mms_data_profile_id;
break;
case OFONO_GPRS_CONTEXT_TYPE_IMS:
setup->profile_id = RIL_DATA_PROFILE_IMS;
break;
case OFONO_GPRS_CONTEXT_TYPE_ANY:
case OFONO_GPRS_CONTEXT_TYPE_INTERNET:
case OFONO_GPRS_CONTEXT_TYPE_WAP:
break;
}
}
setup->apn = g_strdup(ctx->apn);
setup->username = g_strdup(ctx->username);
setup->password = g_strdup(ctx->password);
@@ -1138,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
*==========================================================================*/
@@ -1169,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);
@@ -1206,39 +1109,9 @@ static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
return req;
}
static gboolean ril_data_allow_can_submit(struct ril_data *self)
{
if (self) {
switch (self->priv->options.allow_data) {
case RIL_ALLOW_DATA_ENABLED:
return TRUE;
case RIL_ALLOW_DATA_DISABLED:
case RIL_ALLOW_DATA_AUTO:
break;
}
}
return FALSE;
}
static gboolean ril_data_allow_submit_request(struct ril_data *data,
gboolean allow)
{
if (ril_data_allow_can_submit(data)) {
ril_data_request_queue(ril_data_allow_new(data, allow));
return TRUE;
} else {
return FALSE;
}
}
/*==========================================================================*
* ril_data
*==========================================================================*/
static enum ofono_radio_access_mode ril_data_max_mode(struct ril_data *self)
{
return self->priv->downgraded_tech ? OFONO_RADIO_ACCESS_MODE_UMTS :
OFONO_RADIO_ACCESS_MODE_ANY;
}
gulong ril_data_add_allow_changed_handler(struct ril_data *self,
ril_data_cb_t cb, void *arg)
@@ -1261,39 +1134,12 @@ void ril_data_remove_handler(struct ril_data *self, gulong id)
}
}
static void ril_data_imsi_changed(struct ril_sim_settings *settings,
void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
struct ril_data_priv *priv = self->priv;
if (!settings->imsi) {
/*
* Most likely, SIM removal. In any case, no data requests
* make sense when IMSI is unavailable.
*/
ril_data_cancel_all_requests(self);
}
ril_data_manager_check_network_mode(priv->dm);
}
static void ril_data_settings_changed(struct ril_sim_settings *settings,
void *user_data)
{
ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
}
static void ril_data_ril_disconnected_cb(GRilIoChannel *io, void *user_data)
{
struct ril_data *self = RIL_DATA(user_data);
struct ril_data_priv *priv = self->priv;
DBG_(self, "disconnected");
priv->flags = RIL_DATA_FLAG_NONE;
priv->restricted_state = 0;
ril_data_cancel_all_requests(self);
}
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
{
const struct ril_data *d1 = a;
@@ -1308,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)) {
@@ -1335,31 +1181,20 @@ 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,
ril_data_imsi_changed, self);
ril_data_settings_changed, self);
priv->settings_event_id[SETTINGS_EVENT_PREF_MODE] =
ril_sim_settings_add_pref_mode_changed_handler(settings,
ril_data_settings_changed, self);
@@ -1429,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);
@@ -1445,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));
}
}
}
@@ -1482,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;
@@ -1517,15 +1338,19 @@ static void ril_data_disallow(struct ril_data *self)
*/
ril_data_deactivate_all(self);
/* Tell rild that the data is now disabled */
if (!ril_data_allow_submit_request(self, FALSE)) {
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
/* Tell rild that the data is now disabled */
ril_data_request_queue(ril_data_allow_new(self, FALSE));
} else {
priv->flags &= ~RIL_DATA_FLAG_ON;
GASSERT(!ril_data_allowed(self));
DBG_(self, "data off");
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)
@@ -1605,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;
@@ -1625,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)
@@ -1665,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);
}
@@ -1680,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);
@@ -1694,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);
}
@@ -1768,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) {
@@ -1811,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);
}
@@ -1821,21 +1619,19 @@ 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);
}
}
}
static struct ril_data *ril_data_manager_allowed(struct ril_data_manager *self)
{
if (self) {
GSList *l;
GSList *l;
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
return data;
}
for (l= self->data_list; l; l = l->next) {
struct ril_data *data = l->data;
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
return data;
}
}
@@ -1852,10 +1648,12 @@ 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 (!ril_data_allow_submit_request(data, TRUE)) {
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
} else {
priv->flags |= RIL_DATA_FLAG_ON;
GASSERT(ril_data_allowed(data));
DBG_(data, "data on");
@@ -1863,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.
@@ -1879,7 +1677,12 @@ void ril_data_manager_check_data(struct ril_data_manager *self)
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
{
ril_data_allow_submit_request(ril_data_manager_allowed(self), TRUE);
if (self) {
struct ril_data *data = ril_data_manager_allowed(self);
if (data) {
ril_data_request_queue(ril_data_allow_new(data, TRUE));
}
}
}
/*

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2021 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
@@ -40,7 +39,6 @@ struct ril_data_call {
char **dnses;
char **gateways;
char **addresses;
char **pcscf;
};
struct ril_data_call_list {
@@ -56,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 {
@@ -80,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);
@@ -98,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);
@@ -115,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-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 ofono_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,82 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2019-2021 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_types.h"
#include <ofono/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 ofono_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 ofono_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-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 ofono_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-2021 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 ofono_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-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 ofono_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)
{
ofono_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);
ofono_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 ofono_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 = ofono_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-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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 ofono_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)
{
ofono_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);
ofono_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 ofono_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 = ofono_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-2021 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 ofono_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)
{
ofono_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);
ofono_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 ofono_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 = ofono_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-2021 Jolla Ltd.
* Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,12 +15,11 @@
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_netreg.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/misc.h>
#include "common.h"
/*
* This module is the ofono_gprs_driver implementation for rilmodem.
@@ -48,7 +47,7 @@ struct ril_gprs {
GRilIoQueue *q;
gboolean attached;
int max_cids;
enum ofono_netreg_status registration_status;
enum network_registration_status registration_status;
guint register_id;
gulong network_event_id;
gulong data_event_id;
@@ -79,11 +78,11 @@ static struct ril_gprs_cbd *ril_gprs_cbd_new(struct ril_gprs *gd,
return cbd;
}
static enum ofono_netreg_status ril_gprs_fix_registration_status(
struct ril_gprs *gd, enum ofono_netreg_status status)
static enum network_registration_status ril_gprs_fix_registration_status(
struct ril_gprs *gd, enum network_registration_status status)
{
if (!ril_data_allowed(gd->data)) {
return OFONO_NETREG_STATUS_NOT_REGISTERED;
return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
} else {
/* TODO: need a way to make sure that SPDI information has
* already been read from the SIM (i.e. sim_spdi_read_cb in
@@ -95,13 +94,13 @@ static enum ofono_netreg_status ril_gprs_fix_registration_status(
static void ril_gprs_data_update_registration_state(struct ril_gprs *gd)
{
const enum ofono_netreg_status status =
const enum network_registration_status status =
ril_gprs_fix_registration_status(gd, gd->network->data.status);
if (gd->registration_status != status) {
ofono_info("data reg changed %d -> %d (%s), attached %d",
gd->registration_status, status,
ofono_netreg_status_to_string(status),
registration_status_to_string(status),
gd->attached);
gd->registration_status = status;
ofono_gprs_status_notify(gd->gprs, gd->registration_status);
@@ -189,10 +188,12 @@ static void ril_gprs_registration_status(struct ofono_gprs *gprs,
{
struct ril_gprs *gd = ril_gprs_get_data(gprs);
struct ofono_error error;
const enum ofono_netreg_status status = gd->attached ?
gd->registration_status : OFONO_NETREG_STATUS_NOT_REGISTERED;
const enum network_registration_status status = gd->attached ?
gd->registration_status :
NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
DBG("%d (%s)", status, ofono_netreg_status_to_string(status));
DBG("%d (%s)", status, registration_status_to_string(status));
cb(ril_error_ok(&error), status, data);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -15,20 +15,21 @@
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_netreg.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/mtu-limit.h>
#include <gutil_strv.h>
#include <arpa/inet.h>
#include "ofono.h"
#include "common.h"
#include "mtu-watch.h"
#define CTX_ID_NONE ((unsigned int)(-1))
#define MAX_MMS_MTU 1280
#define MAX_MTU 1280
struct ril_gprs_context_call {
struct ril_data_request *req;
@@ -43,7 +44,7 @@ struct ril_gprs_context {
struct ril_data *data;
guint active_ctx_cid;
gulong calls_changed_id;
struct ofono_mtu_limit *mtu_limit;
struct mtu_watch *mtu_watch;
struct ril_data_call *active_call;
struct ril_gprs_context_call activate;
struct ril_gprs_context_call deactivate;
@@ -87,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;
}
@@ -95,9 +95,9 @@ static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
ril_data_remove_handler(gcd->data, gcd->calls_changed_id);
gcd->calls_changed_id = 0;
}
if (gcd->mtu_limit) {
ofono_mtu_limit_free(gcd->mtu_limit);
gcd->mtu_limit = NULL;
if (gcd->mtu_watch) {
mtu_watch_free(gcd->mtu_watch);
gcd->mtu_watch = NULL;
}
}
@@ -107,19 +107,10 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
if (call) {
ril_data_call_free(gcd->active_call);
gcd->active_call = ril_data_call_dup(call);
if (ofono_gprs_context_get_type(gcd->gc) ==
OFONO_GPRS_CONTEXT_TYPE_MMS) {
/*
* Some MMS providers have a problem with MTU
* greater than 1280. Let's be safe.
*/
if (!gcd->mtu_limit) {
gcd->mtu_limit =
ofono_mtu_limit_new(MAX_MMS_MTU);
}
if (!gcd->mtu_watch) {
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
}
ofono_mtu_limit_set_ifname(gcd->mtu_limit, call->ifname);
ril_data_call_grab(gcd->data, call->cid, gcd);
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
} else {
ril_gprs_context_free_active_call(gcd);
}
@@ -254,59 +245,34 @@ static void ril_gprs_context_set_gateway(struct ofono_gprs_context *gc,
ofono_gprs_context_set_ipv6_gateway(gc, ipv6_gw);
}
typedef void (*ofono_gprs_context_list_setter_t)(struct ofono_gprs_context *gc,
const char **list);
static void ril_gprs_context_set_servers(struct ofono_gprs_context *gc,
char * const *list, ofono_gprs_context_list_setter_t set_ipv4,
ofono_gprs_context_list_setter_t set_ipv6)
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
int i;
const char **ip_list = NULL, **ip_ptr = NULL;
const char **ipv6_list = NULL, **ipv6_ptr = NULL;
char * const *list = call->dnses;
const int n = gutil_strv_length(list);
const char **ip_dns = g_new0(const char *, n+1);
const char **ipv6_dns = g_new0(const char *, n+1);
const char **ip_ptr = ip_dns;
const char **ipv6_ptr = ipv6_dns;
for (i = 0; i < n; i++) {
const char *addr = list[i];
switch (ril_gprs_context_address_family(addr)) {
case AF_INET:
if (!ip_ptr) {
ip_list = g_new0(const char *, n - i + 1);
ip_ptr = ip_list;
}
*ip_ptr++ = addr;
break;
case AF_INET6:
if (!ipv6_ptr) {
ipv6_list = g_new0(const char *, n - i + 1);
ipv6_ptr = ipv6_list;
}
*ipv6_ptr++ = addr;
break;
}
}
set_ipv4(gc, ip_list);
set_ipv6(gc, ipv6_list);
ofono_gprs_context_set_ipv4_dns_servers(gc, ip_dns);
ofono_gprs_context_set_ipv6_dns_servers(gc, ipv6_dns);
g_free(ip_list);
g_free(ipv6_list);
}
static void ril_gprs_context_set_dns_servers(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
ril_gprs_context_set_servers(gc, call->dnses,
ofono_gprs_context_set_ipv4_dns_servers,
ofono_gprs_context_set_ipv6_dns_servers);
}
static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
const struct ril_data_call *call)
{
ril_gprs_context_set_servers(gc, call->pcscf,
ofono_gprs_context_set_ipv4_proxy_cscf,
ofono_gprs_context_set_ipv6_proxy_cscf);
g_free(ip_dns);
g_free(ipv6_dns);
}
/* Only compares the stuff that's important to us */
@@ -314,8 +280,7 @@ static void ril_gprs_context_set_proxy_cscf(struct ofono_gprs_context *gc,
#define DATA_CALL_ADDRESS_CHANGED (0x02)
#define DATA_CALL_GATEWAY_CHANGED (0x04)
#define DATA_CALL_DNS_CHANGED (0x08)
#define DATA_CALL_PCSCF_CHANGED (0x10)
#define DATA_CALL_ALL_CHANGED (0x1f)
#define DATA_CALL_ALL_CHANGED (0x0f)
static int ril_gprs_context_data_call_change(
const struct ril_data_call *c1,
const struct ril_data_call *c2)
@@ -341,10 +306,6 @@ static int ril_gprs_context_data_call_change(
changes |= DATA_CALL_DNS_CHANGED;
}
if (!gutil_strv_equal(c1->pcscf, c2->pcscf)) {
changes |= DATA_CALL_PCSCF_CHANGED;
}
return changes;
} else {
return DATA_CALL_ALL_CHANGED;
@@ -417,11 +378,6 @@ static void ril_gprs_context_call_list_changed(struct ril_data *data, void *arg)
ril_gprs_context_set_dns_servers(gc, call);
}
if (change & DATA_CALL_PCSCF_CHANGED) {
DBG("P-CSCF changed");
ril_gprs_context_set_proxy_cscf(gc, call);
}
ofono_gprs_context_signal_change(gc, gcd->active_ctx_cid);
ril_data_call_free(prev_call);
}
@@ -463,7 +419,6 @@ static void ril_gprs_context_activate_primary_cb(struct ril_data *data,
ril_gprs_context_set_address(gc, call);
ril_gprs_context_set_gateway(gc, call);
ril_gprs_context_set_dns_servers(gc, call);
ril_gprs_context_set_proxy_cscf(gc, call);
ril_error_init_ok(&error);
}
@@ -487,14 +442,14 @@ static void ril_gprs_context_activate_primary(struct ofono_gprs_context *gc,
{
struct ril_gprs_context *gcd = ril_gprs_context_get_data(gc);
struct ofono_netreg *netreg = ril_modem_ofono_netreg(gcd->modem);
const enum ofono_netreg_status rs = ofono_netreg_get_status(netreg);
const int rs = ofono_netreg_get_status(netreg);
/* Let's make sure that we aren't connecting when roaming not allowed */
if (rs == OFONO_NETREG_STATUS_ROAMING) {
if (rs == NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_gprs *gprs = ril_modem_ofono_gprs(gcd->modem);
if (!ofono_gprs_get_roaming_allowed(gprs) &&
if (!__ofono_gprs_get_roaming_allowed(gprs) &&
ril_netreg_check_if_really_roaming(netreg, rs) ==
OFONO_NETREG_STATUS_ROAMING) {
NETWORK_REGISTRATION_STATUS_ROAMING) {
struct ofono_error error;
ofono_info("Can't activate context %u (roaming)",
ctx->cid);
@@ -511,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);
}
@@ -526,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;
}
}
@@ -556,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) {
@@ -623,7 +578,7 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
ril_data_unref(gcd->data);
ril_network_unref(gcd->network);
ril_data_call_free(gcd->active_call);
ofono_mtu_limit_free(gcd->mtu_limit);
mtu_watch_free(gcd->mtu_watch);
g_free(gcd);
}

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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,16 +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/message-waiting.h>
#include <ofono/cell-info.h>
#include <ofono/sim-auth.h>
#include <ofono/watch.h>
#include "ofono.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 {
@@ -45,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;
@@ -62,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;
@@ -92,26 +79,40 @@ static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
return md;
}
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *m)
static void *ril_modem_get_atom_data(struct ril_modem *modem,
enum ofono_atom_type type)
{
return (m && m->ofono) ? ofono_modem_get_sim(m->ofono) : NULL;
if (modem && modem->ofono) {
struct ofono_atom *atom =
__ofono_modem_find_atom(modem->ofono, type);
if (atom) {
return __ofono_atom_get_data(atom);
}
}
return NULL;
}
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *m)
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem)
{
return (m && m->ofono) ? ofono_modem_get_gprs(m->ofono) : NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_SIM);
}
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *m)
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem)
{
return (m && m->ofono) ? ofono_modem_get_netreg(m->ofono) : NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_GPRS);
}
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem)
{
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_NETREG);
}
static inline struct ofono_radio_settings *ril_modem_radio_settings(
struct ril_modem *modem)
{
return (modem && modem->ofono) ?
ofono_modem_get_radio_settings(modem->ofono) : NULL;
return ril_modem_get_atom_data(modem, OFONO_ATOM_TYPE_RADIO_SETTINGS);
}
void ril_modem_delete(struct ril_modem *md)
@@ -121,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) {
@@ -142,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;
@@ -175,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;
@@ -205,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");
}
}
}
@@ -228,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;
@@ -239,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);
@@ -291,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);
}
}
@@ -314,20 +284,11 @@ 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);
}
ofono_sim_auth_create(modem);
}
static void ril_modem_post_online(struct ofono_modem *modem)
@@ -409,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);
@@ -430,16 +389,13 @@ 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);
ofono_cell_info_unref(modem->cell_info);
sailfish_cell_info_unref(modem->cell_info);
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);
@@ -452,8 +408,8 @@ 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 ofono_cell_info *cell_info)
struct ril_sim_settings *settings,
struct sailfish_cell_info *cell_info)
{
/* Skip the slash from the path, it looks like "/ril_0" */
struct ofono_modem *ofono = ofono_modem_create(path + 1,
@@ -479,39 +435,27 @@ 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);
modem->sim_settings = ril_sim_settings_ref(settings);
modem->cell_info = ofono_cell_info_ref(cell_info);
modem->cell_info = sailfish_cell_info_ref(cell_info);
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,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2021 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
@@ -17,12 +17,13 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/sim-mnclength.h>
#include <ofono/cell-info.h>
#include <sailfish_cell_info.h>
#include "ofono.h"
struct ril_netmon {
struct ofono_netmon *netmon;
struct ofono_cell_info *cell_info;
struct sailfish_cell_info *cell_info;
guint register_id;
};
@@ -47,9 +48,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
if (mcc >= 0 && mcc <= 999) {
snprintf(s_mcc, OFONO_MAX_MCC_LENGTH + 1, "%03d", mcc);
if (mnc >= 0 && mnc <= 999) {
const int mnclen =
ofono_sim_mnclength_get_mnclength_mccmnc(mcc,
mnc);
const unsigned int mnclen = mnclength(mcc, mnc);
const char *format[] = { "%d", "%02d", "%03d" };
const char *fmt = (mnclen > 0 &&
mnclen <= G_N_ELEMENTS(format)) ?
@@ -70,7 +69,7 @@ static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
/* Better not to push uninitialized data to the stack ... */
for (i = nparams; i < RIL_NETMON_MAX_OFONO_PARAMS; i++) {
params[i].type = OFONO_NETMON_INFO_INVALID;
params[i].value = OFONO_CELL_INVALID_VALUE;
params[i].value = SAILFISH_CELL_INVALID_VALUE;
}
ril_netmon_format_mccmnc(s_mcc, s_mnc, mcc, mnc);
@@ -89,36 +88,36 @@ static void ril_netmon_notify_ofono(struct ofono_netmon *netmon,
}
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
const struct ofono_cell_info_gsm *gsm)
const struct sailfish_cell_info_gsm *gsm)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (gsm->lac != OFONO_CELL_INVALID_VALUE) {
if (gsm->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = gsm->lac;
n++;
}
if (gsm->cid != OFONO_CELL_INVALID_VALUE) {
if (gsm->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = gsm->cid;
n++;
}
if (gsm->arfcn != OFONO_CELL_INVALID_VALUE) {
if (gsm->arfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = gsm->arfcn;
n++;
}
if (gsm->signalStrength != OFONO_CELL_INVALID_VALUE) {
if (gsm->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = gsm->signalStrength;
n++;
}
if (gsm->bitErrorRate != OFONO_CELL_INVALID_VALUE) {
if (gsm->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = gsm->bitErrorRate;
n++;
@@ -129,42 +128,42 @@ static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
}
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
const struct ofono_cell_info_wcdma *wcdma)
const struct sailfish_cell_info_wcdma *wcdma)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (wcdma->lac != OFONO_CELL_INVALID_VALUE) {
if (wcdma->lac != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_LAC;
params[n].value = wcdma->lac;
n++;
}
if (wcdma->cid != OFONO_CELL_INVALID_VALUE) {
if (wcdma->cid != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = wcdma->cid;
n++;
}
if (wcdma->psc != OFONO_CELL_INVALID_VALUE) {
if (wcdma->psc != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_PSC;
params[n].value = wcdma->psc;
n++;
}
if (wcdma->uarfcn != OFONO_CELL_INVALID_VALUE) {
if (wcdma->uarfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_ARFCN;
params[n].value = wcdma->uarfcn;
n++;
}
if (wcdma->signalStrength != OFONO_CELL_INVALID_VALUE) {
if (wcdma->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = wcdma->signalStrength;
n++;
}
if (wcdma->bitErrorRate != OFONO_CELL_INVALID_VALUE) {
if (wcdma->bitErrorRate != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_BER;
params[n].value = wcdma->bitErrorRate;
n++;
@@ -175,48 +174,48 @@ static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
}
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
const struct ofono_cell_info_lte *lte)
const struct sailfish_cell_info_lte *lte)
{
struct ril_netmon_ofono_param params[RIL_NETMON_MAX_OFONO_PARAMS];
int n = 0;
if (lte->ci != OFONO_CELL_INVALID_VALUE) {
if (lte->ci != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CI;
params[n].value = lte->ci;
n++;
}
if (lte->earfcn != OFONO_CELL_INVALID_VALUE) {
if (lte->earfcn != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_EARFCN;
params[n].value = lte->earfcn;
n++;
}
if (lte->signalStrength != OFONO_CELL_INVALID_VALUE) {
if (lte->signalStrength != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSSI;
params[n].value = lte->signalStrength;
n++;
}
if (lte->rsrp != OFONO_CELL_INVALID_VALUE) {
if (lte->rsrp != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRQ;
params[n].value = lte->rsrp;
n++;
}
if (lte->rsrq != OFONO_CELL_INVALID_VALUE) {
if (lte->rsrq != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_RSRP;
params[n].value = lte->rsrq;
n++;
}
if (lte->cqi != OFONO_CELL_INVALID_VALUE) {
if (lte->cqi != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_CQI;
params[n].value = lte->cqi;
n++;
}
if (lte->timingAdvance != OFONO_CELL_INVALID_VALUE) {
if (lte->timingAdvance != SAILFISH_CELL_INVALID_VALUE) {
params[n].type = OFONO_NETMON_INFO_TIMING_ADVANCE;
params[n].value = lte->timingAdvance;
n++;
@@ -230,32 +229,28 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
ofono_netmon_cb_t cb, void *data)
{
struct ril_netmon *nm = ril_netmon_get_data(netmon);
const ofono_cell_ptr *cells = nm->cell_info->cells;
struct ofono_error error;
GSList *l;
if (cells) {
const ofono_cell_ptr *ptr;
for (l = nm->cell_info->cells; l; l = l->next) {
const struct sailfish_cell *cell = l->data;
for (ptr = cells; *ptr; ptr++) {
const struct ofono_cell *cell = *ptr;
if (cell->registered) {
switch (cell->type) {
case OFONO_CELL_TYPE_GSM:
ril_netmon_notify_gsm(netmon,
&cell->info.gsm);
break;
case OFONO_CELL_TYPE_WCDMA:
ril_netmon_notify_wcdma(netmon,
&cell->info.wcdma);
break;
case OFONO_CELL_TYPE_LTE:
ril_netmon_notify_lte(netmon,
&cell->info.lte);
break;
default:
break;
}
if (cell->registered) {
switch (cell->type) {
case SAILFISH_CELL_TYPE_GSM:
ril_netmon_notify_gsm(netmon,
&cell->info.gsm);
break;
case SAILFISH_CELL_TYPE_WCDMA:
ril_netmon_notify_wcdma(netmon,
&cell->info.wcdma);
break;
case SAILFISH_CELL_TYPE_LTE:
ril_netmon_notify_lte(netmon,
&cell->info.lte);
break;
default:
break;
}
}
}
@@ -283,7 +278,7 @@ static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
if (modem->cell_info) {
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
nm->cell_info = ofono_cell_info_ref(modem->cell_info);
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
nm->netmon = netmon;
ofono_netmon_set_data(netmon, nm);
@@ -309,7 +304,7 @@ static void ril_netmon_remove(struct ofono_netmon *netmon)
g_source_remove(nm->register_id);
}
ofono_cell_info_unref(nm->cell_info);
sailfish_cell_info_unref(nm->cell_info);
g_slice_free(struct ril_netmon, nm);
}

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -16,15 +15,11 @@
#include "ril_plugin.h"
#include "ril_network.h"
#include "ril_netreg.h"
#include "ril_util.h"
#include "ril_vendor.h"
#include "ril_log.h"
#include <ofono/watch.h>
#include <ofono/gprs-provision.h>
#define REGISTRATION_MAX_RETRIES (2)
#include "common.h"
#include "simutil.h"
enum ril_netreg_events {
NETREG_RIL_EVENT_NITZ_TIME_RECEIVED,
@@ -41,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 {
@@ -73,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;
@@ -91,17 +77,20 @@ static struct ril_netreg_cbd *ril_netreg_cbd_new(struct ril_netreg *nd,
return cbd;
}
enum ofono_netreg_status ril_netreg_check_if_really_roaming
(struct ofono_netreg *netreg, enum ofono_netreg_status status)
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg,
gint status)
{
if (status == OFONO_NETREG_STATUS_ROAMING) {
if (status == NETWORK_REGISTRATION_STATUS_ROAMING) {
/* These functions tolerate NULL argument */
const char *net_mcc = ofono_netreg_get_mcc(netreg);
const char *net_mnc = ofono_netreg_get_mnc(netreg);
struct sim_spdi *spdi = ofono_netreg_get_spdi(netreg);
if (ofono_netreg_spdi_lookup(netreg, net_mcc, net_mnc)) {
ofono_info("not roaming based on spdi");
return OFONO_NETREG_STATUS_REGISTERED;
if (spdi && net_mcc && net_mnc) {
if (sim_spdi_lookup(spdi, net_mcc, net_mnc)) {
ofono_info("not roaming based on spdi");
return NETWORK_REGISTRATION_STATUS_REGISTERED;
}
}
}
@@ -120,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,
@@ -135,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);
}
}
@@ -149,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);
@@ -162,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;
@@ -192,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 != OFONO_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;
@@ -301,22 +227,21 @@ static void ril_netreg_list_operators_cb(GRilIoChannel *io, int status,
}
/* Set the proper status */
op->status = OFONO_OPERATOR_STATUS_UNKNOWN;
if (status) {
if (!strcmp(status, "available")) {
op->status = OFONO_OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) {
op->status = OFONO_OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) {
op->status = OFONO_OPERATOR_STATUS_FORBIDDEN;
}
if (!strcmp(status, "available")) {
list[i].status = OPERATOR_STATUS_AVAILABLE;
} else if (!strcmp(status, "current")) {
list[i].status = OPERATOR_STATUS_CURRENT;
} else if (!strcmp(status, "forbidden")) {
list[i].status = OPERATOR_STATUS_FORBIDDEN;
} else {
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);
@@ -331,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);
@@ -366,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,
@@ -425,11 +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);
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,
@@ -437,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,
@@ -532,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,
@@ -547,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));
@@ -583,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]
@@ -650,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);
@@ -676,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);
@@ -693,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);

View File

@@ -1,34 +0,0 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* 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_NETREG_H
#define RIL_NETREG_H
#include "ril_types.h"
#include <ofono/netreg.h>
enum ofono_netreg_status ril_netreg_check_if_really_roaming
(struct ofono_netreg *reg, enum ofono_netreg_status status);
#endif /* RIL_NETREG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

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-2021 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
@@ -19,16 +18,13 @@
#include "ril_types.h"
#include <ofono/netreg.h>
#include <glib-object.h>
struct ofono_network_operator;
struct ril_radio_caps;
struct ril_registration_state {
enum ofono_netreg_status status;
enum ofono_access_technology access_tech;
int status; /* enum network_registration_status */
int access_tech; /* enum access_technology or -1 if none */
int ril_tech;
int max_calls;
int lac;
@@ -46,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);
@@ -73,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-2021 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
@@ -18,9 +17,8 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/gdbus.h>
#include <ofono/dbus.h>
#include <ofono/dbus-access.h>
#include "gdbus.h"
#include "ofono.h"
#define RIL_OEM_RAW_INTERFACE "org.ofono.OemRaw"
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
@@ -34,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)
{
@@ -47,23 +40,30 @@ 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");
reply = ofono_dbus_error_timed_out(msg);
reply = __ofono_error_timed_out(msg);
} else {
DBG("Error %s", ril_error_to_string(ril_status));
reply = ofono_dbus_error_failed(msg);
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,
@@ -72,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_dbus_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) {
@@ -100,12 +94,12 @@ 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 {
DBG_(oem, "Unexpected signature");
return ofono_dbus_error_invalid_args(msg);
return __ofono_error_invalid_args(msg);
}
}

View File

@@ -5,7 +5,8 @@
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) ST-Ericsson SA 2010.
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2021 Jolla Ltd
* Copyright (C) 2013-2016 Jolla Ltd
* Contact: Jussi Kangas <jussi.kangas@tieto.com>
* Copyright (C) 2014 Canonical Ltd
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +21,10 @@
#include "ril_plugin.h"
#include <ofono/modem.h>
#include <ofono/misc.h>
#include <ofono/log.h>
#include <ofono.h>
#include "simutil.h"
#include "util.h"
#define CALLBACK_WITH_FAILURE(cb, args...) \
do { \
@@ -42,8 +44,6 @@
} while (0)
#define SIM_EFPBR_FILEID 0x4F30
#define SIM_EFADN_FILEID 0x6F3A
#define SIM_EFEXT1_FILEID 0x6F4A
#define UNUSED 0xFF
@@ -148,7 +148,8 @@ static gint comp_int(gconstpointer a, gconstpointer b)
return a_val - b_val;
}
static const struct pb_file_info *ext1_info(const GSList *pb_files)
static const struct pb_file_info *
ext1_info(const GSList *pb_files)
{
const GSList *l;
for (l = pb_files; l; l = l->next) {
@@ -169,7 +170,7 @@ static struct phonebook_entry *handle_adn(size_t len, const unsigned char *msg,
unsigned extension_record = UNUSED;
unsigned i, prefix;
char *number = NULL;
char *name = ofono_sim_string_to_utf8(msg, name_length);
char *name = sim_string_to_utf8(msg, name_length);
struct phonebook_entry *new_entry;
/* Length contains also TON & NPI */
@@ -244,7 +245,7 @@ static struct phonebook_entry *handle_adn(size_t len, const unsigned char *msg,
return new_entry;
end:
ofono_sim_string_free(name);
g_free(name);
g_free(number);
return NULL;
@@ -302,7 +303,7 @@ static void handle_sne(size_t len, const unsigned char *msg,
if (rec_data->set_by_iap)
len -= 2;
sne = ofono_sim_string_to_utf8(msg, len);
sne = sim_string_to_utf8(msg, len);
if (sne && *sne != '\0') {
struct phonebook_entry *entry;
@@ -311,17 +312,19 @@ static void handle_sne(size_t len, const unsigned char *msg,
GINT_TO_POINTER(rec_data->adn_idx));
if (entry) {
/* If one already exists, delete it */
ofono_sim_string_free(entry->sne);
if (entry->sne)
g_free(entry->sne);
DBG("Adding SNE %s to %d", sne, rec_data->adn_idx);
DBG("name %s", entry->name);
entry->sne = sne;
sne = NULL;
} else {
g_free(sne);
}
} else {
g_free(sne);
}
ofono_sim_string_free(sne);
}
static void handle_anr(size_t len,
@@ -415,31 +418,33 @@ static void handle_email(size_t len, const unsigned char *msg,
const struct record_to_read *rec_data)
{
char *email;
struct phonebook_entry *entry;
/* There are additional fields for type 2 files */
if (rec_data->set_by_iap)
len -= 2;
email = ofono_sim_string_to_utf8(msg, len);
if (email && *email) {
struct phonebook_entry *entry;
entry = g_tree_lookup(ref->phonebook,
GINT_TO_POINTER(rec_data->adn_idx));
if (entry) {
/* if one already exists, delete it */
ofono_sim_string_free(entry->email);
DBG("Adding email to entry %d", rec_data->adn_idx);
DBG("name %s", entry->name);
entry->email = email;
email = NULL;
}
email = sim_string_to_utf8(msg, len);
if (email == NULL || *email == '\0') {
g_free(email);
return;
}
ofono_sim_string_free(email);
entry = g_tree_lookup(ref->phonebook,
GINT_TO_POINTER(rec_data->adn_idx));
if (entry == NULL) {
g_free(email);
return;
}
/* if one already exists, delete it */
if (entry->email)
g_free(entry->email);
DBG("Adding email to entry %d", rec_data->adn_idx);
DBG("name %s", entry->name);
entry->email = email;
}
static void handle_ext1(size_t len, const unsigned char *msg,
@@ -566,11 +571,11 @@ static gboolean free_entry(gpointer key, gpointer value, gpointer data)
{
struct phonebook_entry *entry = value;
ofono_sim_string_free(entry->name);
ofono_sim_string_free(entry->email);
ofono_sim_string_free(entry->sne);
g_free(entry->name);
g_free(entry->number);
g_free(entry->email);
g_free(entry->anr);
g_free(entry->sne);
g_free(entry);
return FALSE;
@@ -993,9 +998,8 @@ static void ril_export_entries(struct ofono_phonebook *pb,
pbd->df_path = usim_path;
pbd->df_size = sizeof(usim_path);
ofono_sim_read_path(pbd->sim_context, SIM_EFPBR_FILEID,
ofono_sim_read(pbd->sim_context, SIM_EFPBR_FILEID,
OFONO_SIM_FILE_STRUCTURE_FIXED,
pbd->df_path, pbd->df_size,
pb_reference_data_cb, pb);
}
@@ -1017,7 +1021,7 @@ static int ril_phonebook_probe(struct ofono_phonebook *pb,
if (pd == NULL)
return -ENOMEM;
pd->sim = ofono_modem_get_sim(modem);
pd->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
if (pd->sim == NULL)
return -ENOENT;

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-2021 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
@@ -18,6 +17,7 @@
#define RIL_PLUGIN_H
#include "ril_types.h"
#include "sailfish_manager.h"
#include <ofono/modem.h>
#include <ofono/call-barring.h>
@@ -51,8 +51,7 @@ struct ril_modem {
const char *log_prefix;
const char *ecclist_file;
struct ofono_modem *ofono;
struct ofono_cell_info *cell_info;
struct ril_vendor *vendor;
struct sailfish_cell_info *cell_info;
struct ril_radio *radio;
struct ril_data *data;
struct ril_network *network;
@@ -71,8 +70,8 @@ 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 ofono_cell_info *cell_info);
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);
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
@@ -84,6 +83,7 @@ struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
#define ril_modem_io(modem) ((modem)->io)
int ril_sim_app_type(struct ofono_sim *sim);
int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
extern const struct ofono_call_barring_driver ril_call_barring_driver;
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;

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-2021 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,10 +18,10 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/misc.h>
#include <ofono/watch.h>
#include <gutil_misc.h>
#include "sailfish_watch.h"
#include "simutil.h"
#include "util.h"
#include "ofono.h"
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
#define FAC_LOCK_QUERY_TIMEOUT_SECS (10)
@@ -85,7 +85,6 @@ struct ril_sim {
gboolean empty_pin_query_allowed;
gboolean inserted;
guint idle_id; /* Used by register and SIM reset callbacks */
guint list_apps_id;
gulong card_event_id[SIM_CARD_EVENT_COUNT];
gulong io_event_id[IO_EVENT_COUNT];
guint query_pin_retries_id;
@@ -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,34 +108,20 @@ 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;
ofono_sim_write_cb_t write;
ofono_sim_imsi_cb_t imsi;
ofono_query_facility_lock_cb_t query_facility_lock;
ofono_sim_open_channel_cb_t open_channel;
ofono_sim_close_channel_cb_t close_channel;
gpointer ptr;
} cb;
gpointer data;
guint req_id;
};
struct ril_sim_session_cbd {
struct ril_sim *sd;
struct ril_sim_card *card;
ofono_sim_logical_access_cb_t cb;
gpointer data;
int ref_count;
int session_id;
int cla;
guint req_id;
};
struct ril_sim_pin_cbd {
struct ril_sim *sd;
ofono_sim_lock_unlock_cb_t cb;
@@ -163,16 +148,6 @@ struct ril_sim_retry_query {
GRilIoRequest *(*new_req)(struct ril_sim *sd);
};
/* TS 102.221 */
#define APP_TEMPLATE_TAG 0x61
#define APP_ID_TAG 0x4F
struct ril_sim_list_apps {
struct ril_sim *sd;
ofono_sim_list_apps_cb_t cb;
void *data;
};
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
@@ -204,82 +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 struct ril_sim_session_cbd *ril_sim_session_cbd_new(struct ril_sim *sd,
int session_id, int cla, ofono_sim_logical_access_cb_t cb, void *data)
{
struct ril_sim_session_cbd *cbd = g_new0(struct ril_sim_session_cbd, 1);
cbd->sd = sd;
cbd->cb = cb;
cbd->data = data;
cbd->card = ril_sim_card_ref(sd->card);
cbd->session_id = session_id;
cbd->cla = cla;
cbd->ref_count = 1;
return cbd;
}
static void ril_sim_session_cbd_unref(void *data)
{
struct ril_sim_session_cbd *cbd = data;
if (--(cbd->ref_count) < 1) {
ril_sim_card_sim_io_finished(cbd->card, cbd->req_id);
ril_sim_card_unref(cbd->card);
g_free(cbd);
}
}
static void ril_sim_session_cbd_start(struct ril_sim_session_cbd *cbd,
GRilIoRequest* req, guint code, GRilIoChannelResponseFunc cb)
{
struct ril_sim *sd = cbd->sd;
const guint finished_req = cbd->req_id;
cbd->ref_count++;
cbd->req_id = grilio_queue_send_request_full(sd->q, req, code, cb,
ril_sim_session_cbd_unref, cbd);
ril_sim_card_sim_io_started(cbd->card, cbd->req_id);
ril_sim_card_sim_io_finished(cbd->card, finished_req);
}
static void ril_sim_pin_cbd_state_event_count_cb(struct ril_sim_card *sc,
void *user_data)
{
@@ -338,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);
@@ -348,7 +270,7 @@ static void ril_sim_append_path(struct ril_sim *sd, GRilIoRequest *req,
const int fileid, const guchar *path, const guint path_len)
{
const enum ril_app_type app_type = ril_sim_card_app_type(sd->card);
guchar db_path[OFONO_EF_PATH_BUFFER_SIZE] = { 0x00 };
guchar db_path[6] = { 0x00 };
char *hex_path = NULL;
int len;
@@ -356,26 +278,43 @@ static void ril_sim_append_path(struct ril_sim *sd, GRilIoRequest *req,
memcpy(db_path, path, path_len);
len = path_len;
} else if (app_type == RIL_APPTYPE_USIM) {
len = ofono_get_ef_path_3g(fileid, db_path);
len = sim_ef_db_get_path_3g(fileid, db_path);
} else if (app_type == RIL_APPTYPE_SIM) {
len = ofono_get_ef_path_2g(fileid, db_path);
len = sim_ef_db_get_path_2g(fileid, db_path);
} else {
ofono_error("Unsupported app type %d", app_type);
len = 0;
}
if (len > 0) {
hex_path = ril_encode_hex(db_path, len);
hex_path = encode_hex(db_path, len, 0);
grilio_request_append_utf8(req, hex_path);
DBG_(sd, "%s", hex_path);
g_free(hex_path);
} else if (fileid == SIM_EF_ICCID_FILEID || fileid == SIM_EFPL_FILEID) {
/*
* Special catch-all for EF_ICCID (unique card ID)
* and EF_PL files which exist in the root directory.
* As the sim_info_cb function may not have yet
* recorded the app_type for the SIM, and the path
* for both files is the same for 2g|3g, just hard-code.
*
* See 'struct ef_db' in:
* ../../src/simutil.c for more details.
*/
DBG_(sd, "%s", ROOTMF);
grilio_request_append_utf8(req, ROOTMF);
} else {
/*
* Catch-all for EF_ICCID, EF_PL and other files absent
* from ef_db table in src/simutil.c, hard-code ROOTMF.
* The only known case of this is EFPHASE_FILED (0x6FAE).
* The ef_db table ( see /src/simutil.c ) entry for
* EFPHASE contains a value of 0x0000 for it's
* 'parent3g' member. This causes a NULL path to
* be returned.
*/
DBG_(sd, "%s (default)", ROOTMF);
grilio_request_append_utf8(req, ROOTMF);
DBG_(sd, "returning empty path.");
grilio_request_append_utf8(req, NULL);
}
}
@@ -390,15 +329,17 @@ static struct ril_sim_io_response *ril_sim_parse_io_response(const void *data,
if (grilio_parser_get_int32(&rilp, &sw1) &&
grilio_parser_get_int32(&rilp, &sw2)) {
char *hex = grilio_parser_get_utf8(&rilp);
char *hex_data = grilio_parser_get_utf8(&rilp);
DBG("sw1=0x%02X,sw2=0x%02X,%s", sw1, sw2, hex);
DBG("sw1=0x%02X,sw2=0x%02X,%s", sw1, sw2, hex_data);
res = g_slice_new0(struct ril_sim_io_response);
res->sw1 = sw1;
res->sw2 = sw2;
if (hex) {
res->data = ril_decode_hex(hex, -1, &res->data_len);
g_free(hex);
if (hex_data) {
long num_bytes = 0;
res->data = decode_hex(hex_data, -1, &num_bytes, 0);
res->data_len = num_bytes;
g_free(hex_data);
}
}
@@ -488,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);
@@ -504,15 +446,15 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
gboolean ok = FALSE;
guchar access[3] = { 0x00, 0x00, 0x00 };
guchar file_status = EF_STATUS_VALID;
unsigned int flen = 0, rlen = 0, str = 0;
int flen = 0, rlen = 0, str = 0;
if (res->data_len) {
if (res->data[0] == 0x62) {
ok = ofono_parse_get_response_3g(res->data,
ok = sim_parse_3g_get_response(res->data,
res->data_len, &flen, &rlen, &str,
access, NULL);
} else {
ok = ofono_parse_get_response_2g(res->data,
ok = sim_parse_2g_get_response(res->data,
res->data_len, &flen, &rlen, &str,
access, &file_status);
}
@@ -538,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);
@@ -554,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);
}
@@ -568,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) {
@@ -599,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,
@@ -629,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) {
@@ -653,10 +597,9 @@ static void ril_sim_write(struct ofono_sim *sim, guint cmd, int fileid,
ofono_sim_write_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
char *hex_data = ril_encode_hex(value, length);
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);
}
@@ -693,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;
@@ -721,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);
@@ -734,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);
}
@@ -917,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);
@@ -943,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);
@@ -1177,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 {
@@ -1197,7 +1146,8 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
ril_status, cbd->passwd_type, retry_count);
if (ril_status == RIL_E_SUCCESS && retry_count == 0) {
enum ofono_sim_password_type pin_type = ofono_sim_puk2pin(type);
enum ofono_sim_password_type associated_pin =
__ofono_sim_puk2pin(type);
/*
* If PIN/PUK request has succeeded, zero retry count
* makes no sense, we have to assume that it's unknown.
@@ -1205,9 +1155,9 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
* it can't be queried it will remain unknown.
*/
sd->retries[type] = -1;
if (pin_type != OFONO_SIM_PASSWORD_INVALID) {
if (associated_pin != OFONO_SIM_PASSWORD_INVALID) {
/* Successful PUK requests affect PIN retry count */
sd->retries[pin_type] = -1;
sd->retries[associated_pin] = -1;
}
} else {
sd->retries[type] = retry_count;
@@ -1215,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));
@@ -1253,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);
}
}
@@ -1266,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,
@@ -1293,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);
}
@@ -1342,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;
@@ -1380,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,
@@ -1400,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);
@@ -1418,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;
@@ -1450,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);
@@ -1460,298 +1409,13 @@ 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);
}
static gboolean ril_sim_list_apps_cb(void *data)
{
struct ril_sim_list_apps *rd = data;
struct ril_sim *sd = rd->sd;
const struct ril_sim_card_status *status = sd->card->status;
struct ofono_error error;
GASSERT(sd->list_apps_id);
sd->list_apps_id = 0;
if (status) {
int i, n = status->num_apps;
GByteArray *tlv = g_byte_array_sized_new(n * 20);
/* Reconstruct EFdir contents */
for (i = 0; i < n; i++) {
const char *hex = status->apps[i].aid;
gsize hex_len = hex ? strlen(hex) : 0;
guint8 aid[16];
if (hex_len >= 2 && hex_len <= 2 * sizeof(aid) &&
gutil_hex2bin(hex, hex_len, aid)) {
const guint8 aid_size = (guint8)hex_len/2;
guint8 buf[4];
/*
* TS 102.221
* 13 Application independent files
* 13.1 EFdir
*
* Application template TLV object.
*/
buf[0] = APP_TEMPLATE_TAG;
buf[1] = aid_size + 2;
buf[2] = APP_ID_TAG;
buf[3] = aid_size;
g_byte_array_append(tlv, buf, sizeof(buf));
g_byte_array_append(tlv, aid, aid_size);
}
}
DBG_(sd, "reporting %u apps %u bytes", n, tlv->len);
rd->cb(ril_error_ok(&error), tlv->data, tlv->len, rd->data);
g_byte_array_unref(tlv);
} else {
DBG_(sd, "no SIM card, no apps");
rd->cb(ril_error_failure(&error), NULL, 0, rd->data);
}
return G_SOURCE_REMOVE;
}
static void ril_sim_list_apps(struct ofono_sim *sim,
ofono_sim_list_apps_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
struct ril_sim_list_apps *rd = g_new(struct ril_sim_list_apps, 1);
rd->sd = sd;
rd->cb = cb;
rd->data = data;
if (sd->list_apps_id) {
g_source_remove(sd->list_apps_id);
}
sd->list_apps_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ril_sim_list_apps_cb, rd, g_free);
}
static void ril_sim_open_channel_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
ofono_sim_open_channel_cb_t cb = cbd->cb.open_channel;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
guint32 n, session_id;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_uint32(&rilp, &n) && n >= 1 &&
grilio_parser_get_uint32(&rilp, &session_id)) {
DBG_(cbd->sd, "%u", session_id);
cb(ril_error_ok(&error), session_id, cbd->data);
return;
}
} else {
ofono_error("Open logical channel failure: %s",
ril_error_to_string(status));
}
cb(ril_error_failure(&error), 0, cbd->data);
}
static void ril_sim_open_channel(struct ofono_sim *sim,
const unsigned char *aid, unsigned int len,
ofono_sim_open_channel_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
GRilIoRequest *req = grilio_request_new();
char *aid_hex = ril_encode_hex(aid, len);
DBG_(sd, "%s", aid_hex);
grilio_request_append_utf8(req, aid_hex);
grilio_request_append_int32(req, 0);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_OPEN_CHANNEL,
ril_sim_open_channel_cb);
grilio_request_unref(req);
g_free(aid_hex);
}
static void ril_sim_close_channel_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_cbd_io *cbd = user_data;
struct ofono_error error;
if (status == RIL_E_SUCCESS) {
ril_error_init_ok(&error);
} else {
ofono_error("Close logical channel failure: %s",
ril_error_to_string(status));
ril_error_init_failure(&error);
}
cbd->cb.close_channel(&error, cbd->data);
}
static void ril_sim_close_channel(struct ofono_sim *sim, int session_id,
ofono_sim_close_channel_cb_t cb, void *data)
{
struct ril_sim *sd = ril_sim_get_data(sim);
struct ril_sim_cbd_io *cbd = ril_sim_cbd_io_new(sd, cb, data);
GRilIoRequest *req = grilio_request_new();
DBG_(sd, "%u", session_id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, session_id);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
ril_sim_cbd_io_start(cbd, req, RIL_REQUEST_SIM_CLOSE_CHANNEL,
ril_sim_close_channel_cb);
grilio_request_unref(req);
}
static void ril_sim_logical_access_get_results_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_session_cbd *cbd = user_data;
ofono_sim_logical_access_cb_t cb = cbd->cb;
struct ril_sim_io_response *res;
struct ofono_error err;
res = ril_sim_parse_io_response(data, len);
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
cb(ril_error_ok(&err), res->data, res->data_len, cbd->data);
} else if (res) {
cb(ril_error_sim(&err, res->sw1, res->sw2), NULL, 0, cbd->data);
} else {
cb(ril_error_failure(&err), NULL, 0, cbd->data);
}
ril_sim_io_response_free(res);
}
static void ril_sim_logical_access_transmit(struct ril_sim_session_cbd *cbd,
int ins, int p1, int p2, int p3, const char *hex_data,
GRilIoChannelResponseFunc cb)
{
GRilIoRequest *req = grilio_request_new();
DBG_(cbd->sd, "session=%u,cmd=%02X,%02X,%02X,%02X,%02X,%s",
cbd->session_id, cbd->cla, ins, p1, p2, p3,
hex_data ? hex_data : "");
grilio_request_append_int32(req, cbd->session_id);
grilio_request_append_int32(req, cbd->cla);
grilio_request_append_int32(req, ins);
grilio_request_append_int32(req, p1);
grilio_request_append_int32(req, p2);
grilio_request_append_int32(req, p3);
grilio_request_append_utf8(req, hex_data);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
ril_sim_session_cbd_start(cbd, req,
RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, cb);
grilio_request_unref(req);
}
static void ril_sim_logical_access_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ril_sim_session_cbd *cbd = user_data;
ofono_sim_logical_access_cb_t cb = cbd->cb;
struct ril_sim_io_response *res;
struct ofono_error error;
DBG_(cbd->sd, "");
cbd->req_id = 0;
res = ril_sim_parse_io_response(data, len);
if (res && status == RIL_E_SUCCESS) {
/*
* TS 102 221
* 7.3.1.1.5.2 Case 4 commands
*
* If the UICC receives a case 4 command, after processing
* the data sent with the C-APDU, it shall return:
*
* a) procedure bytes '61 xx' instructing the transport
* layer of the terminal to issue a GET RESPONSE command
* with a maximum length of 'xx'; or
* b) status indicating a warning or error condition (but
* not SW1 SW2 = '90 00').
*
* The GET RESPONSE command so issued is then treated as
* described for case 2 commands.
*/
if (res->sw1 == 0x61) {
ril_sim_logical_access_transmit(cbd,
CMD_GET_RESPONSE, 0, 0, res->sw2, NULL,
ril_sim_logical_access_get_results_cb);
} else if (ril_sim_io_response_ok(res)) {
cb(ril_error_ok(&error), res->data, res->data_len,
cbd->data);
} else {
cb(ril_error_sim(&error, res->sw1, res->sw2), NULL, 0,
cbd->data);
}
} else {
cb(ril_error_failure(&error), NULL, 0, cbd->data);
}
ril_sim_io_response_free(res);
}
static void ril_sim_logical_access(struct ofono_sim *sim, int session_id,
const unsigned char *pdu, unsigned int len,
ofono_sim_logical_access_cb_t cb, void *data)
{
/* SIM Command APDU: CLA INS P1 P2 P3 Data */
struct ril_sim *sd = ril_sim_get_data(sim);
const char* hex_data;
char *tmp;
struct ril_sim_session_cbd *cbd = ril_sim_session_cbd_new(sd,
session_id, pdu[0], cb, data);
GASSERT(len >= 5);
if (len > 5) {
hex_data = tmp = ril_encode_hex(pdu + 5, len - 5);
} else {
tmp = NULL;
hex_data = "";
}
ril_sim_logical_access_transmit(cbd, pdu[1], pdu[2], pdu[3], pdu[4],
hex_data, ril_sim_logical_access_cb);
ril_sim_session_cbd_unref(cbd);
g_free(tmp);
}
static void ril_sim_session_read_binary(struct ofono_sim *sim, int session,
int fileid, int start, int length,
const unsigned char *path, unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
struct ofono_error error;
ofono_error("session_read_binary not implemented");
cb(ril_error_failure(&error), NULL, 0, data);
}
static void ril_sim_session_read_record(struct ofono_sim *sim, int session_id,
int fileid, int record, int length,
const unsigned char *path, unsigned int path_len,
ofono_sim_read_cb_t cb, void *data)
{
struct ofono_error error;
ofono_error("session_read_record not implemented");
cb(ril_error_failure(&error), NULL, 0, data);
}
static void ril_sim_session_read_info(struct ofono_sim *sim, int session_id,
int fileid, const unsigned char *path,
unsigned int path_len, ofono_sim_file_info_cb_t cb,
void *data)
{
struct ofono_error error;
ofono_error("session_read_info not implemented");
cb(ril_error_failure(&error), -1, -1, -1, NULL, 0, data);
}
static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
const void *data, guint len, void *user_data)
{
@@ -1762,7 +1426,7 @@ static void ril_sim_refresh_cb(GRilIoChannel *io, guint code,
* so we could be more descrete here. However I have't actually
* seen that in real life, let's just refresh everything for now.
*/
ofono_sim_refresh_full(sd->sim);
__ofono_sim_refresh(sd->sim, NULL, TRUE, TRUE);
}
static gboolean ril_sim_register(gpointer user)
@@ -1783,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 */
@@ -1808,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 =
@@ -1833,9 +1497,6 @@ static void ril_sim_remove(struct ofono_sim *sim)
grilio_queue_cancel_all(sd->q, FALSE);
ofono_sim_set_data(sim, NULL);
if (sd->list_apps_id) {
g_source_remove(sd->list_apps_id);
}
if (sd->idle_id) {
g_source_remove(sd->idle_id);
}
@@ -1849,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));
@@ -1880,14 +1541,7 @@ const struct ofono_sim_driver ril_sim_driver = {
.reset_passwd = ril_sim_pin_send_puk,
.change_passwd = ril_sim_change_passwd,
.query_pin_retries = ril_sim_query_pin_retries,
.query_facility_lock = ril_sim_query_facility_lock,
.list_apps = ril_sim_list_apps,
.open_channel2 = ril_sim_open_channel,
.close_channel = ril_sim_close_channel,
.session_read_binary = ril_sim_session_read_binary,
.session_read_record = ril_sim_session_read_record,
.session_read_info = ril_sim_session_read_info,
.logical_access = ril_sim_logical_access
.query_facility_lock = ril_sim_query_facility_lock
};
/*

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

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -17,6 +17,10 @@
#include "ril_util.h"
#include "ril_log.h"
#include "smsutil.h"
#include "util.h"
#include "simutil.h"
#define RIL_SMS_ACK_RETRY_MS 1000
#define RIL_SMS_ACK_RETRY_COUNT 10
@@ -242,10 +246,10 @@ static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
/* TPDU:
*
* 'pdu' is a raw hexadecimal string
* ril_encode_hex() turns it into an ASCII/hex buffer (subset of utf8)
* encode_hex() turns it into an ASCII/hex UTF8 buffer
* grilio_request_append_utf8() encodes utf8 -> utf16
*/
tpdu = ril_encode_hex(pdu + smsc_len, tpdu_len);
tpdu = encode_hex(pdu + smsc_len, tpdu_len, 0);
grilio_request_append_utf8(req, tpdu);
DBG("%s", tpdu);
@@ -292,7 +296,7 @@ static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
char *ril_pdu;
int ril_pdu_len;
unsigned int smsc_len;
guint ril_buf_len;
long ril_buf_len;
guchar *ril_data;
ril_pdu = NULL;
@@ -308,7 +312,7 @@ static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
ril_pdu_len = strlen(ril_pdu);
DBG("ril_pdu_len is %d", ril_pdu_len);
ril_data = ril_decode_hex(ril_pdu, ril_pdu_len, &ril_buf_len);
ril_data = decode_hex(ril_pdu, ril_pdu_len, &ril_buf_len, -1);
if (ril_data == NULL)
goto error;
@@ -321,16 +325,14 @@ static void ril_sms_notify(GRilIoChannel *io, guint ril_event,
ofono_info("sms received, smsc_len is %d", smsc_len);
DBG("(%s)", ril_pdu);
if (ril_buf_len >= smsc_len) {
if (ril_event == RIL_UNSOL_RESPONSE_NEW_SMS) {
/* Last parameter is tpdu_len (substract SMSC length) */
ofono_sms_deliver_notify(sd->sms, ril_data, ril_buf_len,
if (ril_event == RIL_UNSOL_RESPONSE_NEW_SMS) {
/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
ofono_sms_deliver_notify(sd->sms, ril_data, ril_buf_len,
ril_buf_len - smsc_len);
} else {
/* RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT */
ofono_sms_status_notify(sd->sms, ril_data, ril_buf_len,
} else {
GASSERT(ril_event == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT);
ofono_sms_status_notify(sd->sms, ril_data, ril_buf_len,
ril_buf_len - smsc_len);
}
}
g_free(ril_pdu);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -17,6 +17,8 @@
#include "ril_util.h"
#include "ril_log.h"
#include "util.h"
#ifndef UI_LANG
# define UI_LANG "/var/lib/environment/nemo/locale.conf"
#endif
@@ -81,7 +83,7 @@ static void ril_stk_envelope(struct ofono_stk *stk, int length,
{
struct ril_stk *sd = ril_stk_get_data(stk);
GRilIoRequest *req = grilio_request_new();
char *hex_envelope = ril_encode_hex(cmd, length);
char *hex_envelope = encode_hex(cmd, length, 0);
DBG("%s", hex_envelope);
grilio_request_append_utf8(req, hex_envelope);
@@ -115,7 +117,7 @@ static void ril_stk_terminal_response(struct ofono_stk *stk, int length,
{
struct ril_stk *sd = ril_stk_get_data(stk);
GRilIoRequest *req = grilio_request_new();
char *hex_tr = ril_encode_hex(resp, length);
char *hex_tr = encode_hex(resp, length, 0);
DBG("rilmodem terminal response: %s", hex_tr);
grilio_request_append_utf8(req, hex_tr);
@@ -148,21 +150,19 @@ static void ril_stk_pcmd_notify(GRilIoChannel *io, guint code,
struct ril_stk *sd = user_data;
GRilIoParser rilp;
char *pcmd;
void *pdu;
guint len;
guchar *pdu;
long len = 0;
GASSERT(code == RIL_UNSOL_STK_PROACTIVE_COMMAND);
grilio_parser_init(&rilp, data, data_len);
pcmd = grilio_parser_get_utf8(&rilp);
pdu = ril_decode_hex(pcmd, -1, &len);
if (pdu) {
DBG("pcmd: %s", pcmd);
ofono_stk_proactive_command_notify(sd->stk, len, pdu);
g_free(pdu);
} else {
ofono_warn("Failed to parse STK command %s", pcmd);
}
DBG("pcmd: %s", pcmd);
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
g_free(pcmd);
ofono_stk_proactive_command_notify(sd->stk, len, pdu);
g_free(pdu);
}
static void ril_stk_event_notify(GRilIoChannel *io, guint code,
@@ -170,23 +170,20 @@ static void ril_stk_event_notify(GRilIoChannel *io, guint code,
{
struct ril_stk *sd = user_data;
GRilIoParser rilp;
char *pcmd;
void *pdu;
guint len;
char *pcmd = NULL;
guchar *pdu = NULL;
long len;
/* Proactive command has been handled by the modem. */
GASSERT(code == RIL_UNSOL_STK_EVENT_NOTIFY);
grilio_parser_init(&rilp, data, data_len);
pcmd = grilio_parser_get_utf8(&rilp);
pdu = ril_decode_hex(pcmd, -1, &len);
if (pdu) {
DBG("pcmd: %s", pcmd);
ofono_stk_proactive_command_handled_notify(sd->stk, len, pdu);
g_free(pdu);
} else {
ofono_warn("Failed to parse STK event %s", pcmd);
}
DBG("pcmd: %s", pcmd);
pdu = decode_hex(pcmd, strlen(pcmd), &len, -1);
g_free(pcmd);
ofono_stk_proactive_command_handled_notify(sd->stk, len, pdu);
g_free(pdu);
}
static void ril_stk_session_end_notify(GRilIoChannel *io, guint code,

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,154 +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
# UMTS network mode.
#
# Default 3 (PREF_NET_TYPE_GSM_WCDMA_AUTO)
#
#umtsNetworkMode=3
# Timeout for RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, in milliseconds.
#
# Default 20000 (20 seconds)
#
#networkModeTimeout=20000
# Timeout for RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC and
# RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, in milliseconds.
#
# Default 100000 (100 seconds)
#
#networkSelectionTimeout=100000
# Comma-separated signal strength range, in dBm.
#
# These values are used for translating dBm values returned by the modem in
# LTE mode into signal strength percentage. If you are getting significantly
# different signal strength readings in GSM and LTE modes, you may need to
# tweak those.
#
# Default -100,-60
#
#signalStrengthRange=-100,-60
# Cycle radio power at startup.
#
# Default true (cycle the power)
#
#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-2021 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,55 +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;
};
/* Some values copied from ofono's internal common.h */
/* 27.007 Section 7.11 */
enum bearer_class {
BEARER_CLASS_VOICE = 1,
BEARER_CLASS_DATA = 2,
BEARER_CLASS_FAX = 4,
BEARER_CLASS_DEFAULT = 7,
BEARER_CLASS_SMS = 8,
BEARER_CLASS_DATA_SYNC = 16,
BEARER_CLASS_DATA_ASYNC = 32,
BEARER_CLASS_SS_DEFAULT = 61,
BEARER_CLASS_PACKET = 64,
BEARER_CLASS_PAD = 128
};
#endif /* RIL_TYPES_H */

View File

@@ -1,8 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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
@@ -18,129 +17,93 @@
#include "ril_util.h"
#include "ril_log.h"
#include <ofono/misc.h>
#define USSD_REQUEST_TIMEOUT_SEC (30)
#define USSD_CANCEL_TIMEOUT_SEC (20)
#include "smsutil.h"
#include "util.h"
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)
{
struct ofono_error error;
enum ofono_sms_charset charset;
enum sms_charset charset;
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];
long written = 0;
if (ofono_decode_cbs_dcs_charset(dcs, &charset) &&
charset == OFONO_SMS_CHARSET_7BIT) {
char unpacked[182];
unsigned int written = ofono_unpack_7bit(pdu, len,
OFONO_UNPACK_7BIT_USSD, unpacked, sizeof(unpacked)-1);
unpack_7bit_own_buf(pdu, len, 0, TRUE,
sizeof(unpacked_buf)-1, &written, 0,
unpacked_buf);
unpacked[written] = 0;
if (written >= 1) {
/*
* When USSD was packed, additional CR
* might have been added (according to
* 23.038 6.1.2.3.1). So if the last
* character is CR, it should be removed
* here.
*
* Over 2 characters long USSD string must
* end with # (checked in valid_ussd_string),
* so it should be safe to remove extra CR.
*/
GRilIoRequest *req = grilio_request_new();
int length = strlen(unpacked);
while (length > 2 && unpacked[length-1] == '\r') {
unpacked[--length] = 0;
unpacked_buf[written] = 0;
if (written >= 1) {
/*
* When USSD was packed, additional CR
* might have been added (according to
* 23.038 6.1.2.3.1). So if the last
* character is CR, it should be removed
* here.
*
* Over 2 characters long USSD string must
* end with # (checked in valid_ussd_string),
* so it should be safe to remove extra CR.
*/
GRilIoRequest *req = grilio_request_new();
int length = strlen((char *)unpacked_buf);
while (length > 2 &&
unpacked_buf[length-1] == '\r') {
unpacked_buf[--length] = 0;
}
grilio_request_append_utf8_chars(req, (char*)
unpacked_buf, length);
grilio_queue_send_request(ud->q, req,
RIL_REQUEST_SEND_USSD);
grilio_request_unref(req);
cb(ril_error_ok(&error), data);
return;
}
grilio_request_append_utf8_chars(req, (char*)
unpacked, 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_request_unref(req);
return;
}
}
@@ -151,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-2021 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,15 +18,13 @@
#include <grilio_channel.h>
#include <gutil_misc.h>
#include <ofono/netreg.h>
#include <ofono/misc.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#define RIL_PROTO_IP_STR "IP"
#define RIL_PROTO_IPV6_STR "IPV6"
#define RIL_PROTO_IPV4V6_STR "IPV4V6"
#include "common.h"
#include "netreg.h"
const char *ril_error_to_string(int error)
{
@@ -237,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:
@@ -335,87 +321,42 @@ 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;
}
enum ofono_access_technology ril_parse_tech(const char *stech, int *ril_tech)
/* 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;
enum ofono_access_technology access_tech =
OFONO_ACCESS_TECHNOLOGY_NONE;
if (gutil_parse_int(stech, 0, &tech)) {
if (ril_parse_int(stech, 0, &tech)) {
switch (tech) {
case RADIO_TECH_GPRS:
case RADIO_TECH_GSM:
access_tech = OFONO_ACCESS_TECHNOLOGY_GSM;
access_tech = ACCESS_TECHNOLOGY_GSM;
break;
case RADIO_TECH_EDGE:
access_tech = OFONO_ACCESS_TECHNOLOGY_GSM_EGPRS;
access_tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
break;
case RADIO_TECH_UMTS:
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN;
access_tech = ACCESS_TECHNOLOGY_UTRAN;
break;
case RADIO_TECH_HSDPA:
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA;
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
break;
case RADIO_TECH_HSUPA:
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSUPA;
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
break;
case RADIO_TECH_HSPA:
case RADIO_TECH_HSPAP:
access_tech = OFONO_ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
access_tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
break;
case RADIO_TECH_LTE:
case RADIO_TECH_LTE_CA:
access_tech = OFONO_ACCESS_TECHNOLOGY_EUTRAN;
access_tech = ACCESS_TECHNOLOGY_EUTRAN;
break;
default:
DBG("Unknown RIL tech %s", stech);
/* no break */
case RADIO_TECH_IWLAN:
case RADIO_TECH_UNKNOWN:
tech = -1;
break;
}
@@ -470,37 +411,24 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
return FALSE;
}
char* ril_encode_hex(const void *in, guint size)
gboolean ril_parse_int(const char *str, int base, int *value)
{
char *out = g_new(char, size * 2 + 1);
gboolean ok = FALSE;
ofono_encode_hex(in, size, out);
return out;
}
if (str && str[0]) {
char *str2 = g_strstrip(g_strdup(str));
char *end = str2;
long l;
void *ril_decode_hex(const char *hex, int len, guint *out_size)
{
void *out = NULL;
guint size = 0;
if (hex) {
if (len < 0) {
len = (int) strlen(hex);
}
if (len > 0 && !(len & 1)) {
size = len/2;
out = g_malloc(size);
if (!gutil_hex2bin(hex, len, out)) {
g_free(out);
out = NULL;
size = 0;
}
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);
}
if (out_size) {
*out_size = size;
}
return out;
return ok;
}
/*

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2021 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);
enum ofono_access_technology ril_parse_tech(const char *stech, int *ril_tech);
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)
@@ -43,9 +39,6 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
#define ril_error_failure(err) (ril_error_init_failure(err), err)
#define ril_error_sim(err,sw1,sw2) (ril_error_init_sim_error(err,sw1,sw2), err)
char *ril_encode_hex(const void *in, guint size);
void *ril_decode_hex(const char *hex, int len, guint *out_size);
#endif /* RIL_UTIL_H */
/*

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