diff --git a/.gitignore b/.gitignore index 2689204f..13f70cdb 100644 --- a/.gitignore +++ b/.gitignore @@ -117,6 +117,7 @@ Makefile.in /docs/reference/libmm-glib/libmm-glib.interfaces /docs/reference/libmm-glib/libmm-glib.prerequisites /docs/reference/libmm-glib/libmm-glib.signals +/docs/reference/libmm-glib/libmm-glib.actions /docs/reference/libmm-glib/libmm-glib.types /docs/reference/libmm-glib/*.stamp /docs/reference/libmm-glib/*.txt @@ -167,8 +168,8 @@ Makefile.in /plugins/test-service-* /plugins/ublox/mm-ublox-enums-types.[ch] - /plugins/telit/mm-telit-enums-types.[ch] +/plugins/huawei/mm-huawei-enums-types.[ch] /plugins/xmm7360/mm-xmm7360-rpc-enums-types.[ch] @@ -178,5 +179,9 @@ Makefile.in /test/mmsmspdu /test/mmsmsmonitor +/tools/tests/services/org.freedesktop.ModemManager1.service +/tools/tests/test-stub +/tools/tests/test-wrapper.sh + /ModemManager-*-coverage.info /ModemManager-*-coverage/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24b9009e..f569cf64 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,101 +1,165 @@ -image: gcc +include: + - project: freedesktop/ci-templates + ref: 290b79e0e78eab67a83766f4e9691be554fc4afd + file: + - templates/ubuntu.yml stages: + - container prep - build -before_script: - - apt update || true - - apt -y install autoconf automake libtool libglib2.0-dev libgudev-1.0-dev libgettextpo-dev autopoint xsltproc dbus autoconf-archive gettext +.common_variables: + variables: + FDO_UPSTREAM_REPO: mobile-broadband/ModemManager + FDO_DISTRIBUTION_VERSION: '20.04' + FDO_DISTRIBUTION_TAG: '2021-04-28.2' + FDO_DISTRIBUTION_PACKAGES: ca-certificates git gcc autoconf automake libtool + libgettextpo-dev libgirepository1.0-dev libglib2.0-dev + libgudev-1.0-dev python3-dbus python3-gi autopoint + xsltproc dbus autoconf-archive gettext gtk-doc-tools + libglib2.0-doc gobject-introspection libsystemd-dev + libpolkit-gobject-1-dev valac + +build container: + extends: + - .fdo.container-build@ubuntu + - .common_variables + stage: container prep + only: + - master + - branches + - merge_requests + - tags + - pushes build-no-qmi: stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables only: - master - merge_requests - tags - schedules script: - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git + - git clone --depth 1 --branch mbim-1-24 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git - pushd libmbim - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection - make - make install - popd - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/tmp/build-no-qmi --disable-gtk-doc --without-qmi + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --without-qmi - make - make check - make install build-no-mbim: stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables only: - master - merge_requests - tags - schedules script: - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + - git clone --depth 1 --branch qmi-1-28 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git - pushd libqmi - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr --disable-mbim-qmux + - ./configure --prefix=/usr --disable-mbim-qmux --enable-collection=basic - make - make install - popd - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/tmp/build-no-mbim --disable-gtk-doc --without-mbim + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --without-mbim - make - make check - make install build-no-qmi-no-mbim: stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables + only: + - master + - merge_requests + - tags + - schedules + script: + - NOCONFIGURE=1 ./autogen.sh + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --without-qmi --without-mbim + - make + - make check + - make install + +build-qmi-newest-commands: + stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables only: - master - merge_requests - tags - schedules script: + - git clone --depth 1 --branch qmi-1-28 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + - pushd libqmi + - NOCONFIGURE=1 ./autogen.sh + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --disable-mbim-qmux --enable-collection=basic + - make + - make install + - popd - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/tmp/build-no-qmi-no-mbim --disable-gtk-doc --without-qmi --without-mbim + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --without-mbim CFLAGS="-DWITH_NEWEST_QMI_COMMANDS" - make - make check - make install build-single-plugins: stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables only: - schedules script: - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git + - git clone --depth 1 --branch mbim-1-24 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git - pushd libmbim - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr + - ./configure --prefix=/usr --disable-gtk-doc --disable-introspection - make - make install - popd - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + - git clone --depth 1 --branch qmi-1-28 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git - pushd libqmi - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr --enable-mbim-qmux + - ./configure --prefix=/usr --enable-mbim-qmux --enable-collection=basic - make - make install - popd - NOCONFIGURE=1 ./autogen.sh - - for plugin in generic altair-lte anydata cinterion dell dlink - fibocom foxconn haier huawei iridium linktop - longcheer mbm motorola mtk nokia nokia-icera + - for plugin in generic altair-lte anydata broadmobi cinterion + dell dlink fibocom foxconn gosuncn haier huawei iridium + linktop longcheer mbm motorola mtk nokia nokia-icera novatel novatel-lte option option-hso pantech - quectel samsung sierra-legacy sierra simtech + qcom-soc quectel samsung sierra-legacy sierra simtech telit thuraya tplink ublox via wavecom x22x zte; do - ./configure --prefix=/usr --disable-gtk-doc --disable-all-plugins --enable-plugin-$plugin; + ./configure --prefix=/usr --disable-gtk-doc --disable-introspection --disable-all-plugins --enable-plugin-$plugin; make; make clean; done build-default: stage: build + extends: + - .fdo.distribution-image@ubuntu + - .common_variables only: - master - branches @@ -104,24 +168,30 @@ build-default: - schedules - pushes script: - - apt -y install gtk-doc-tools libglib2.0-doc gobject-introspection libgirepository1.0-dev libsystemd-dev libpolkit-gobject-1-dev valac - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git + - git clone --depth 1 --branch mbim-1-24 https://gitlab.freedesktop.org/mobile-broadband/libmbim.git - pushd libmbim - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr + - ./configure --prefix=/usr --disable-gtk-doc --enable-introspection - make - make install - popd - - git clone --depth 1 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + - git clone --depth 1 --branch qmi-1-28 https://gitlab.freedesktop.org/mobile-broadband/libqmi.git - pushd libqmi - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr --enable-mbim-qmux + - ./configure --prefix=/usr --enable-mbim-qmux --enable-collection=basic - make - make install - popd - NOCONFIGURE=1 ./autogen.sh - - ./configure --prefix=/usr --enable-gtk-doc --with-polkit=strict --with-suspend-resume=systemd --with-systemdsystemunitdir=/lib/systemd/system + - ./configure --prefix=/usr --enable-gtk-doc --enable-introspection --with-polkit=strict --with-suspend-resume=systemd --with-systemdsystemunitdir=/lib/systemd/system - make - make check - make install - make distcheck + - sha256sum $CI_PROJECT_NAME-*.tar.xz | awk '{print $1;}' > pkg_hash.txt + artifacts: + name: "$CI_PROJECT_NAME-$CI_COMMIT_SHORT_SHA" + paths: + - /builds/$CI_PROJECT_ROOT_NAMESPACE/$CI_PROJECT_NAME/$CI_PROJECT_NAME-*.tar.xz + - /builds/$CI_PROJECT_ROOT_NAMESPACE/$CI_PROJECT_NAME/pkg_hash.txt + expire_in: 2 days diff --git a/AUTHORS b/AUTHORS index 06aeb98d..a7b93cd3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,13 +17,16 @@ Other contributors: Riccardo Vangelisti Alexander Sack Guido Günther + Eric Caruso Eric Shienbrood Elly Jones - Eric Caruso + Bob Ham + Giacinto Cifelli David McCullough Prathmesh Prabhu Thieu Le Thomas Tuttle + Maxim Anisimov Bjørn Mork Marius B. Kotsbak Michael Biebl @@ -33,7 +36,6 @@ Other contributors: Christian Persch Sven Schwermer Thomas Sailer - Bob Ham Colin Walters Franko Fang Jakub Sitnicki @@ -49,6 +51,7 @@ Other contributors: Martyn Russell Thomas Haller Tomas Jura + Amol Lad Colin Helliwell Graham Inggs Javier Viguera @@ -56,15 +59,17 @@ Other contributors: Maksim Salau Martin Pitt Matthew Stanger - Maxim Anisimov + Milo Casagrande Nick Stevens Norbert Frese Piotr Drąg Thomas Bechtold Yegor Yefremov + Yuri Chornoivan Adrian Bunk Alexander Couzens Amit Mendapara + Andika Triwidada Andrew Bird Anton Blanchard Arnd Hannemann @@ -72,6 +77,7 @@ Other contributors: Arun Raghavan Baruch Siach Beniamino Galvani + Brendan Peter Brian Norris Brian, Sam Bryan Duff @@ -80,6 +86,7 @@ Other contributors: David Castellanos David Herrmann David Härdeman + David Khouya Dmitry Ivanyushin Enrico Mioso Eugene Crosser @@ -99,6 +106,7 @@ Other contributors: Krzysztof Kotlenga Lech Perczak LiuQiFeng + Louis-Alexis Eyraud Luis A. Lozano M. I. Spozta Marc Murphy @@ -107,18 +115,20 @@ Other contributors: Mark-Jablonsky Michael Farrell Michał Sroczyński - Milo Casagrande Mohammed Sadiq Moo + Murithi Borona Nathan J. Williams Noel J. Bergman Oskar Enoksson Piotr Figiel Quentin.Li + Rafael Fontenelle Roshan Pius Sam Spilsbury Sławomir Bocheński Tabor Kelly + Teijo Kinnunen Thomas Grenman Thomas Voß Ting-Yuan Huang @@ -131,10 +141,13 @@ Other contributors: Ville Skyttä Vincent Untz Vitaly Gimly - Yuri Chornoivan Amol Lad + emintufan kuonirat + mozzwald + mstanger poma scootergrisen wi24rd yparitcher + Артемий Судаков diff --git a/Makefile.am b/Makefile.am index b70b0625..4dd7ad63 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,6 +13,7 @@ SUBDIRS = \ vapi \ introspection \ test \ + tools \ examples \ docs \ $(NULL) diff --git a/NEWS b/NEWS index b13950fd..7c6945ca 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,397 @@ +ModemManager 1.16.8 +------------------------------------------- + + * MBIM: + ** Fixed wrong session id management when multiple bearers are created. + + * Modem interface: + ** Fixed the enabling operation on multiple plugins that don't have explicit + power up/down operations. + + * libmm-glib: + ** Modem interface: added missing input argument checks. + ** Messaging interface: fixed get_supported_storages() handling when it's + called several consecutive times. + ** 3GPP interface: fixed initial EPS bearer settings property updates. + + * plugins: + ** cinterion: fixed double free when loading initial EPS context. + + * udev: + ** Explicitly ignore "FIREHOSE" WWAN ports. + ** Add support to match WWAN type via sysfs attributes. + + * Several other minor improvements and fixes. + +ModemManager 1.16.6 +------------------------------------------- + + * Build: + ** Require libqmi >= 1.28.6 (for the optional QMI support). + ** Fix error with GCC 11 and -Wincompatible-pointer-types. + ** Fix warning with GCC 11 and -Wmaybe-uninitialized. + + * QMI: + ** Increased device open timeout to 45s. + ** Added support to handle transfer-route messages. + + * Base manager: + ** Added support for Qualcomm based PCI devices in the new WWAN subsystem in + kernel 5.13. + ** Fix segfault on rare conditions when ports reported don't have a proper + subsystem or name. + ** Fix segfault when trying to create device id after device is already gone. + + * plugins: + ** foxconn: added support for the T99W175 module. + ** foxconn: fix segfault when attempting to use parent location support. + ** quectel: ignore QLWURC URCs. + + * Several other minor improvements and fixes. + +ModemManager 1.16.4 +------------------------------------------- + + * Fix build when using libgudev < 232, which is when autoptr support was + introduced in the GUdev* types. We'll keep the 1.16.x branch depending on + libgudev 147, and only bump the requirement in git master. + + * This version comes with an overall rework of the charset encoding handling + inside the ModemManager daemon, which was already available in git master + for some time and has been proved to be very useful. + ** The charset conversion is now strict, except for a few cases where we + would try to do our best (e.g. operator name normalization). + ** The charset methods are cleaned up, with clear distinction between the + ones that allow NUL-finished C strings and the ones that may have valid + embedded NUL bytes. + ** The //TRANSLIT extension is completely avoided, as not all implementations + out there have it (e.g. unavailable in musl libc), and we now use + g_convert_with_fallback() instead where appropriate. + + * Modem interface: + ** Fixed crash triggered when attempting to update lock info on an already + removed DBus skeleton. + + * Time interface: + ** Fixed invalid memory read when loading network timezone fails. + + * Base bearer: + ** Ignored forced disconnections after some time unregistered when PPP is + being used, so that we don't end up hijacking the TTY while pppd is using + it. + + * Kernel device: + ** Fix segfault when processing event for non-existing port. + + * QMI: + ** Fixed allowed modes setup when using the "Acquisition Order Preference" + TLV in the "NAS System Selection Preference" messages. 3GPP+3GPP2 + multimode devices like the MC73xx series were affected. + + * libmm-glib: + ** Fixed comparison of 'allowed auth' and 'rm protocol' settings in bearer + properties. + + * Plugins: + ** cinterion: allow '*' in Prov/Cfg response. + ** cinterion: fixed several FALSE returns without GError set. + ** quectel: ignore +QGPSURC URCs. + + * Several other minor improvements and fixes. + +ModemManager 1.16.2 +------------------------------------------- + + * build: fixed with GLib < 2.54. + * qmi: fixed network regitration cancellation when asserts disabled. + * libmm-glib: fix allow-roaming setting comparison in bearer properties. + +ModemManager 1.16.0 +------------------------------------------- +This is a new stable release of ModemManager. + +The following notes are directed to package maintainers: + + * This version now requires: + ** libqmi >= 1.28.0 (for the optional QMI support) + + * The 1.16.x branch will be the last one supporting the 'LEGACY' and 'PARANOID' + filter modes; standard distributions are advised to use the default 'STRICT' + mode if they aren't using it already (i.e. running the daemon without any + explicit '--filter-policy' option). + + * A new 'qcom-soc' plugin is implemented to be able to use ModemManager in + Qualcomm SoCs like the MSM8916 or MSM8974. This plugin uses a combination of + RPMSG based control ports plus BAM-DMUX based network ports. This plugin is + disabled by default, even when `--enable-all-plugins` is used, and if wanted + it must be explicitly enabled with `--enable-plugin-qcom-soc`. Systems + targeting this kind of SoCs, like postmarketos, should enable it. Standard + distributions may or may not include it, up to the targeted hardware in each + distribution. + + * Gentoo's 'libelogind' library may now be used to detect the systemd + suspend/resume support. + +The API is backwards compatible with the previous releases, the only updates +are the following: + + * Modem interface: + ** Updated the 'Ports' property so that it exposes all ports that are + owned by the modem even if they are explicitly ignored and not used. + ** New 'SimSlots' property that exposes the available SIM slots in the modem, + including the SIM object paths in each of them if the cards are present. + ** New 'PrimarySimSlot' property indicating which of the slots in the + 'SimSlots' array is the one currently active. + ** New 'SetPrimarySimSlot' method to select which SIM slot in the 'SimSlots' + array should be considered active. When the switch happens, the modem will + be fully re-probed. + + * Signal interface: + ** New 'Nr5g' dictionary property including signal information for the 5GNR + access technology. + + * SIM interface: + ** New 'Active' boolean property, indicating whether the SIM object is the + currently active one. + ** New 'Eid' string property, indicating the EID of the card, if any. + + * New udev tags: + ** New 'ID_MM_PORT_TYPE_QMI' tag to explicitly flag a port as being QMI, when + there is no other way to guess the type of port; e.g. this tag is not + needed for ports exposed by the qmi_wwan driver. + ** New 'ID_MM_PORT_TYPE_MBIM' tag to explicitly flag a port as being MBIM, + when there is no other way to guess the type of port; e.g. this tag is not + needed for ports exposed by the cdc_mbim driver. + +The most important features and changes in this release are the following: + + * Implemented support for Multi SIM Single Standby support, for systems that + have multiple SIM slots and they can select which of them (only one) is + active at any given time. Currently implemented for QMI modems only. + + * If the modem enabling phase fails in a fatal way, an implicit disabling + sequence is now run, in order to avoid leaving the modem in an inconsistent + state. + + * If the connection attempt includes user/password information but no explicit + authentication type, CHAP will now be used by default instead of PAP. + + * Full USB device removal events reported via udev are no longer used. The + device removal logic relies exclusively on independent port removal events, + as that logic is supported for all subsystems and kernel device backends + (e.g. also working for non-USB devices and for systems without udev like + OpenWRT). + + * Added support to monitor the 'rpmsg' subsystem, but only in plugins that + explicitly require its use (e.g. the 'qcom-soc' plugin). + + * New options in the ModemManager daemon: + ** Added new '--test-no-suspend-resume' option to disable the runtime + suspend/resume support even if the daemon was built with it. + ** Added new '--test-no-udev' option to disable the runtime udev support even + if the daemon was built with it. + + * Serial: + ** Also match OK or ERROR responses that are not at end of line. + + * SIM: + ** Force reprobing the modem if a new SIM is detected in a modem that + initially started in Failed state without SIM. + ** Force reprobing the modem if the lock status cannot be read after sending + SIM-PUK, so that it transitions to the Failed state. + ** Force reprobing the modem if a PUK lock is discovered after sending + SIM-PIN, so that it transitions to the Failed state. + + * QMI: + ** The logic no longer depends on the service version reported by each + client, the support for each feature is explicitly probed instead. + ** Implemented SIM profile (eUICC) change detection. + ** Support for QMI modems on kernels < 3.6 is dropped. Only kernels where the + QMI control ports are exposed in the 'usbmisc' subsystem are supported. + ** Implemented additional step in the connection logic to allow binding the + WDS client to a given SIO port, required in the BAM-DMUX driver setup. + ** Implemented support for the initial EPS bearer settings logic. + ** Disabled explicit signal and access technology polling if indications have + been correctly enabled. + + * MBIM: + ** Enable SIM hot swap detection logic with QMI over MBIM. + ** Allow plugins to specify explicitly that QMI over MBIM is not supported. + + * libmm-glib: + ** Added missing APIs to get/set RM protocol in the Simple connect settings. + + * Plugins: + ** gosuncn: new plugin, for now just with port type hints for the GM800. + ** quectel: implemented GPS support with +QGPS. + ** quectel: implemented custom time support check to prefer +CTZU=3 instead + of +CTZU=1 so that the modem reports localtime instead of UTC in +CCLK. + ** sierra: added support for XMM-specific features (e.g. EM7345). + ** cinterion: implemented support for the initial EPS bearer settings logic. + ** cinterion: added SIM hot swap support to AT-based modems. + ** huawei: updated to avoid applying multiple port type hint methods. + ** huawei: updated the ^GETPORTMODE logic so that we don't assume the hints + in the response apply to specific USB interfaces. + +The following features which were backported to 1.14.x releases are also present +in ModemManager 1.16.0: + + * location: allow CID only updates. + * sms: allow sending/receiving UTF-16 as if it were UCS-2. + * modem: don't consider charset setup failure as fatal. + * QMI: fix reporting signal strength indications. + * QMI: fix parsing of USSD indications with UTF-16 data. + * QMI: run network registration with NAS Set System Selection Preference. + * QMI: when connection aborted, ensure network handles are released. + * MBIM: don't fail IPv4v6 connection attempt if only IPv4 succeeds. + * cinterion: improve user/password handling in AT^SGAUTH calls. + * cinterion: removed limitation to IPv4 only PDP contexts. + * cinterion: configure the PLAS9 to send URCs correctly. + * quectel: add support for MBIM devices. + * telit: add initial delay for AT ports to become responsive. + + +ModemManager 1.14.0 +------------------------------------------- +This is a new stable release of ModemManager. + +The following notes are directed to package maintainers: + + * This version requires: + ** GLib/GObject/GIO >= 2.48.0 + ** libmbim >= 1.24.0 (for the optional MBIM support) + ** libqmi >= 1.26.0 (for the optional QMI support) + + * Build updated with several improvements: + ** The build has been updated to use by default all warnings enabled by + AX_COMPILER_FLAGS(), and therefore when building the release from a git + checkout, autoconf-archive >= 2017.03.21 is now required. This new build + dependency isn't required when building from the release tarball. + ** Also when building from a git checkout, beware because by default + --enable-compile-warnings=error is enabled, which implies -Werror. If + you'd like to build from git and avoid -Werror, you should explicitly use + --enable-compile-warnings=yes (to keep the warnings but without being + errors), --enable-compile-warnings=no (to disable all the extra warnings + enabled by default) or --disable-Werror (to unconditionally make all + compiler warnings non-fatal). + ** Users can now preselect which plugins to build and install during + configure, with the --enable-plugin-[PLUGIN-NAME] options. The user can + also build and install all except for some, just by using the + --enable-all-plugins option followed by --disable-plugin-[PLUGIN-NAME]. + By default all plugins are enabled, so all of them built and installed. + This new set of options are useful for users building custom systems + where they already know what kind of devices they're going to have, it + isn't recommended for standard distributions. + +The only updates in the public API are the following: + + * Modem interface: + ** Added support for AT-based and/or QMI-based 5G devices, which will report + the new MM_MODEM_CAPABILITY_5GNR capability. + ** Deprecated the MM_MODEM_CAPABILITY_LTE_ADVANCED capability, as it was + never used in any implementation. + + * Bearer interface: + ** Added additional 'attempts', 'failed-attempts', 'total-rx-bytes', + 'total-tx-bytes' and 'total-duration' values in the 'Stats' property + exposed by the Bearer objects. + +The most important features and changes in this release are the following: + + * The daemon switched to 'STRICT' filter mode by default. The old 'DEFAULT' + mode is renamed to 'LEGACY' and is considered now deprecated. Under the + 'STRICT' filter mode, the TTY blacklist and greylist are ignored, and the + port probing mechanism uses its own heuristics to guess whether a given TTY + is owned by a modem or not. + + * Added a new implicit whitelist rules applicable in 'STRICT' filter mode, so + that all devices with a USB vid matching one of the vids allowed by the + different installed plugins are implicitly allowed. + + * Updated daemon logging so that we always prefix the messages with a string + identifying which modem the log refers to, making it easy to grep logs for + one specific device if the system has more than one. + + * Updated the probing logic to make sure we don't attempt a re-probe when the + device is gone. + + * Probing logic now allows new ports detected up to 1500ms since last port + added, useful on OpenWrt setups where ports are notified one by one via + hotplug events. + + * AT: + ** Moved the charset definition logic to the initialization phase instead of + the enabling phase, because the feature support checks may already require + string processing based on the current charset. + ** Updated manual registration operation to attempt using current charset + (e.g. UCS2) if ASCII fails. + + * QMI: + ** Devices using the LOC service for GNSS will now also setup the list of + required NMEA traces before starting the engine. + ** Implemented 3GPP USSD support using the Voice service. + ** Update carrier code if registration changes from one roaming operator to + another. + ** Explicitly disable autoconnect during modem enabling phase, because it + interferes with our connection management logic. + ** Fallback to raw-ip if WDA Get Data Format requests arguments, as in most + new 5G devices. + ** Updated to always use the asynchronous close() operation. + ** Handle disconnection indications during connection attempts. + + * MBIM: + ** Update carrier code if registration changes from one roaming operator to + another. + ** Implement reset in Intel-based and Qualcomm-based devices. + ** Avoid LTE attach config/status if unsupported. + ** Updated to make sure all allocated QMI CIDs are released during shutdown. + + * SIM interface: + ** Don't allow sending PIN/PUK if not required. + + * 3GPP interface: + ** Fixed manual re-registration to the same operator. + + * CDMA interface: + ** Don't allow multiple concurrent activation attempts. + ** Disallow empty carrier code in automatic activation. + + * Bearer interface: + ** Updated to avoid connection checks or stats updates while disconnecting. + + * libmm-glib: + ** New 'mm_location_gps_nmea_get_traces()' method to retrieve a NULL + terminated array of strings with all cached NMEA traces. + ** Deprecated the 'mm_location_gps_nmea_build_full()' method. + + * mmcli: + ** Added a new 'any' lookup keyword for the --modem and --sim options, useful + when the system is only expected to have one single device. + + * Plugins: + ** broadmobi: new plugin, right now just with port type hints for the BM818. + ** foxconn: new plugin to support the T77W968 (both with and without eSIM). + ** dell,dw5821e: added support for the DW5821e with eSIM variant. + ** huawei: don't delay reporting network initiated disconnects. + ** huawei: try to read port type hints from interface descriptions. + ** huawei: avoid using the QCDM port during a voice call. + ** cinterion: skip sim ready check for modules that don't support it. + ** cinterion: implemented radio/band handling for LTE modems. + ** cinterion: added Signal interface support bsaed on AT^SMONI. + ** cinterion: added support for MBIM based devices like the PLS62-W. + ** quectel: updated to detect SIM hot swap via +QUSIM URCs. + ** fibocom: added support for QMI based devices like the FM150. + ** ublox: ignore error when disconnecting last LTE bearer. + ** ublox: implement support to enable and detect +UUDTMF URCs. + ** ublox: added blacklist rules for GPS modules in the plugin itself. + ** sierra: implement manual and automatic CDMA activation. + ** novatel: implement manual and automatic CDMA activation. + +All the features and fixes which were backported to 1.12.x releases are also +present in ModemManager 1.14.0. + + ModemManager 1.12.0 ------------------------------------------- This is a new stable release of ModemManager. diff --git a/README b/README index ade8b77f..d4c60d23 100644 --- a/README +++ b/README @@ -34,3 +34,11 @@ and need to add or change some public method, feel free to suggest it! License. The ModemManager and mmcli binaries are both GPLv2+. The libmm-glib library is LGPLv2+. + +Code of Conduct. +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms, which you can +find in the following link: + https://www.freedesktop.org/wiki/CodeOfConduct +CoC issues may be raised to the project maintainers at the following address: + modemmanager-devel-owner@lists.freedesktop.org diff --git a/RELEASING b/RELEASING new file mode 100644 index 00000000..8ae9a6e1 --- /dev/null +++ b/RELEASING @@ -0,0 +1,37 @@ + + +The ModemManager releases are generated using the GNU autotools. + +1) Configure and build the whole project, making sure gtk-doc is enabled: + + $ NOCONFIGURE=1 ./autogen.sh + $ ./configure --enable-gtk-doc + $ make -j8 + +2) Run distcheck so that the source distribution tarball is generated, and the + project test suite is run on it: + + $ make distcheck + +3) Compute checksum of the tarball so that it can be referenced in the release + email: + + $ sha256sum ModemManager-${VERSION}.tar.xz + +4) Sign release tarball, and verify it (*): + + $ gpg --detach-sign --armor ModemManager-${VERSION}.tar.xz + $ gpg --verify ModemManager-${VERSION}.tar.xz.asc ModemManager-${VERSION}.tar.xz + +5) Upload source tarball (.tar.xz) and signature (.tar.xz.asc) to + freedesktop.org + +TODO: manpages and gtk-doc references + +------------------------------------------------------------------------------- + +*) Verifying the release signature requires the public key of the person who + signed it, e.g.: + + $ curl https://www.freedesktop.org/software/ModemManager/0x3CAD53398973FFFA.asc | gpg --import + diff --git a/autogen.sh b/autogen.sh index df07fc40..7460d254 100755 --- a/autogen.sh +++ b/autogen.sh @@ -14,7 +14,7 @@ PKG_NAME=ModemManager } (cd $srcdir; - autoreconf --force --install --verbose + GTKDOCIZE="true" autoreconf --force --install --verbose ) if test -z "$NOCONFIGURE"; then diff --git a/build-aux/mm-enums-template.c b/build-aux/mm-enums-template.c index 567ce5d5..2a7f264b 100644 --- a/build-aux/mm-enums-template.c +++ b/build-aux/mm-enums-template.c @@ -24,16 +24,16 @@ static const G@Type@Value @enum_name@_values[] = { GType @enum_name@_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), @enum_name@_values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } /** diff --git a/build-aux/mm-errors-template.c b/build-aux/mm-errors-template.c index 3b3127f5..8370adf1 100644 --- a/build-aux/mm-errors-template.c +++ b/build-aux/mm-errors-template.c @@ -12,9 +12,9 @@ GType @enum_name@_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) + if (g_once_init_enter (&g_define_type_id_initialized)) { static const G@Type@Value values[] = { /*** END value-header ***/ @@ -28,10 +28,10 @@ GType }; GType g_define_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } /*** END value-tail ***/ diff --git a/cli/mmcli-bearer.c b/cli/mmcli-bearer.c index cae68ea3..d589e6ed 100644 --- a/cli/mmcli-bearer.c +++ b/cli/mmcli-bearer.c @@ -68,7 +68,7 @@ mmcli_bearer_get_option_group (void) /* Status options */ group = g_option_group_new ("bearer", - "Bearer options", + "Bearer options:", "Show bearer options", NULL, NULL); @@ -159,24 +159,27 @@ print_bearer_info (MMBearer *bearer) const gchar *user = NULL; const gchar *password = NULL; const gchar *rm_protocol = NULL; + gchar *allowed_auth_str = NULL; if (properties) { - apn = mm_bearer_properties_get_apn (properties); - ip_family_str = (properties ? mm_bearer_ip_family_build_string_from_mask (mm_bearer_properties_get_ip_type (properties)) : NULL); - user = mm_bearer_properties_get_user (properties); - password = mm_bearer_properties_get_password (properties); + apn = mm_bearer_properties_get_apn (properties); + ip_family_str = (properties ? mm_bearer_ip_family_build_string_from_mask (mm_bearer_properties_get_ip_type (properties)) : NULL); + allowed_auth_str = (properties ? mm_bearer_allowed_auth_build_string_from_mask (mm_bearer_properties_get_allowed_auth (properties)) : NULL); + user = mm_bearer_properties_get_user (properties); + password = mm_bearer_properties_get_password (properties); if (mm_bearer_get_bearer_type (bearer) != MM_BEARER_TYPE_DEFAULT_ATTACH) { roaming = mm_bearer_properties_get_allow_roaming (properties) ? "allowed" : "forbidden"; rm_protocol = mm_modem_cdma_rm_protocol_get_string (mm_bearer_properties_get_rm_protocol (properties)); } } - mmcli_output_string (MMC_F_BEARER_PROPERTIES_APN, apn); - mmcli_output_string (MMC_F_BEARER_PROPERTIES_ROAMING, roaming); - mmcli_output_string_take (MMC_F_BEARER_PROPERTIES_IP_TYPE, ip_family_str); - mmcli_output_string (MMC_F_BEARER_PROPERTIES_USER, user); - mmcli_output_string (MMC_F_BEARER_PROPERTIES_PASSWORD, password); - mmcli_output_string (MMC_F_BEARER_PROPERTIES_RM_PROTOCOL, rm_protocol); + mmcli_output_string (MMC_F_BEARER_PROPERTIES_APN, apn); + mmcli_output_string (MMC_F_BEARER_PROPERTIES_ROAMING, roaming); + mmcli_output_string_take (MMC_F_BEARER_PROPERTIES_IP_TYPE, ip_family_str); + mmcli_output_string (MMC_F_BEARER_PROPERTIES_USER, user); + mmcli_output_string (MMC_F_BEARER_PROPERTIES_PASSWORD, password); + mmcli_output_string (MMC_F_BEARER_PROPERTIES_RM_PROTOCOL, rm_protocol); + mmcli_output_string_list_take (MMC_F_BEARER_PROPERTIES_ALLOWED_AUTH, allowed_auth_str); } /* IPv4 config */ @@ -248,6 +251,11 @@ print_bearer_info (MMBearer *bearer) gchar *duration = NULL; gchar *bytes_rx = NULL; gchar *bytes_tx = NULL; + gchar *attempts = NULL; + gchar *failed_attempts = NULL; + gchar *total_duration = NULL; + gchar *total_bytes_rx = NULL; + gchar *total_bytes_tx = NULL; if (stats) { guint64 val; @@ -261,11 +269,31 @@ print_bearer_info (MMBearer *bearer) val = mm_bearer_stats_get_tx_bytes (stats); if (val) bytes_tx = g_strdup_printf ("%" G_GUINT64_FORMAT, val); + val = mm_bearer_stats_get_attempts (stats); + if (val) + attempts = g_strdup_printf ("%" G_GUINT64_FORMAT, val); + val = mm_bearer_stats_get_failed_attempts (stats); + if (val) + failed_attempts = g_strdup_printf ("%" G_GUINT64_FORMAT, val); + val = mm_bearer_stats_get_total_duration (stats); + if (val) + total_duration = g_strdup_printf ("%" G_GUINT64_FORMAT, val); + val = mm_bearer_stats_get_total_rx_bytes (stats); + if (val) + total_bytes_rx = g_strdup_printf ("%" G_GUINT64_FORMAT, val); + val = mm_bearer_stats_get_total_tx_bytes (stats); + if (val) + total_bytes_tx = g_strdup_printf ("%" G_GUINT64_FORMAT, val); } - mmcli_output_string_take (MMC_F_BEARER_STATS_DURATION, duration); - mmcli_output_string_take (MMC_F_BEARER_STATS_BYTES_RX, bytes_rx); - mmcli_output_string_take (MMC_F_BEARER_STATS_BYTES_TX, bytes_tx); + mmcli_output_string_take (MMC_F_BEARER_STATS_DURATION, duration); + mmcli_output_string_take (MMC_F_BEARER_STATS_BYTES_RX, bytes_rx); + mmcli_output_string_take (MMC_F_BEARER_STATS_BYTES_TX, bytes_tx); + mmcli_output_string_take (MMC_F_BEARER_STATS_ATTEMPTS, attempts); + mmcli_output_string_take (MMC_F_BEARER_STATS_FAILED_ATTEMPTS, failed_attempts); + mmcli_output_string_take (MMC_F_BEARER_STATS_TOTAL_DURATION, total_duration); + mmcli_output_string_take (MMC_F_BEARER_STATS_TOTAL_BYTES_RX, total_bytes_rx); + mmcli_output_string_take (MMC_F_BEARER_STATS_TOTAL_BYTES_TX, total_bytes_tx); } mmcli_output_dump (); diff --git a/cli/mmcli-call.c b/cli/mmcli-call.c index 7b4f5ecf..ecd1cb77 100644 --- a/cli/mmcli-call.c +++ b/cli/mmcli-call.c @@ -94,7 +94,7 @@ mmcli_call_get_option_group (void) /* Status options */ group = g_option_group_new ("call", - "Call options", + "Call options:", "Show call options", NULL, NULL); diff --git a/cli/mmcli-common.c b/cli/mmcli-common.c index 10a1fb75..4163f42f 100644 --- a/cli/mmcli-common.c +++ b/cli/mmcli-common.c @@ -110,35 +110,108 @@ mmcli_get_manager_sync (GDBusConnection *connection) return manager; } +/******************************************************************************/ +/* Common to all objects */ + +#define ANY_OBJECT_STR "any" + +static void +get_object_lookup_info (const gchar *str, + const gchar *object_type, + const gchar *object_prefix, + gchar **object_path, + gchar **modem_uid, + gboolean *find_any) +{ + gboolean all_numeric; + guint i; + + /* Empty string not allowed */ + if (!str || !str[0]) { + g_printerr ("error: no %s was specified\n", object_type); + exit (EXIT_FAILURE); + } + + /* User string may come in four ways: + * a) full DBus path + * b) object index + * c) modem UID (for modem or SIM lookup only) + * d) "any" string (for modem or SIM lookup only) + */ + + *object_path = NULL; + if (modem_uid) + *modem_uid = NULL; + if (find_any) + *find_any = FALSE; + + /* If match the DBus prefix, we have a DBus object path */ + if (g_str_has_prefix (str, object_prefix)) { + g_debug ("Assuming '%s' is the full %s path", str, object_type); + *object_path = g_strdup (str); + return; + } + + /* If all numeric, we have the object index */ + all_numeric = TRUE; + for (i = 0; str[i]; i++) { + if (!g_ascii_isdigit (str[i])) { + all_numeric = FALSE; + break; + } + } + if (all_numeric) { + g_debug ("Assuming '%s' is the %s index", str, object_type); + *object_path = g_strdup_printf ("%s/%s", object_prefix, str); + return; + } + + /* If it matches the lookup keyword or any of its substrings, we have + * to look for the first available object */ + if ((find_any) && (g_ascii_strncasecmp (str, ANY_OBJECT_STR, strlen (str)) == 0)) { + g_debug ("Will look for first available %s", object_type); + *find_any = TRUE; + return; + } + + /* Otherwise we have the UID */ + if (modem_uid) { + g_debug ("Assuming '%s' is the modem UID", str); + *modem_uid = g_strdup (str); + return; + } + + /* If UID is not a valid input for the object type, error out */ + g_printerr ("error: invalid %s string specified: '%s'\n", object_type, str); + exit (EXIT_FAILURE); +} + /******************************************************************************/ /* Modem */ static MMObject * find_modem (MMManager *manager, const gchar *modem_path, - const gchar *modem_uid) + const gchar *modem_uid, + gboolean modem_any) { GList *modems; GList *l; MMObject *found = NULL; - g_assert (modem_path || modem_uid); - g_assert (!(modem_path && modem_uid)); - modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); for (l = modems; l; l = g_list_next (l)) { MMObject *obj; MMModem *modem; obj = MM_OBJECT (l->data); - modem = MM_MODEM (mm_object_get_modem (obj)); - - if (modem_path && g_str_equal (mm_object_get_path (obj), modem_path)) { - found = g_object_ref (obj); - break; - } + modem = mm_object_get_modem (obj); + if (!modem) + continue; - if (modem_uid && g_str_equal (mm_modem_get_device (modem), modem_uid)) { + if (modem_any || + (modem_path && g_str_equal (mm_object_get_path (obj), modem_path)) || + (modem_uid && g_str_equal (mm_modem_get_device (modem), modem_uid))) { found = g_object_ref (obj); break; } @@ -146,10 +219,7 @@ find_modem (MMManager *manager, g_list_free_full (modems, g_object_unref); if (!found) { - if (modem_path) - g_printerr ("error: couldn't find modem at '%s'\n", modem_path); - else if (modem_uid) - g_printerr ("error: couldn't find modem identified by uid '%s'\n", modem_uid); + g_printerr ("error: couldn't find modem\n"); exit (EXIT_FAILURE); } @@ -159,8 +229,9 @@ find_modem (MMManager *manager, } typedef struct { - gchar *modem_path; - gchar *modem_uid; + gchar *modem_path; + gchar *modem_uid; + gboolean modem_any; } GetModemContext; typedef struct { @@ -212,62 +283,14 @@ get_manager_ready (GDBusConnection *connection, results = g_new (GetModemResults, 1); results->manager = mmcli_get_manager_finish (res); - results->object = find_modem (results->manager, ctx->modem_path, ctx->modem_uid); + results->object = find_modem (results->manager, ctx->modem_path, ctx->modem_uid, ctx->modem_any); g_task_return_pointer (task, results, (GDestroyNotify)get_modem_results_free); g_object_unref (task); } -static void -get_modem_path_or_uid (const gchar *str, - gchar **modem_path, - gchar **modem_uid) -{ - gboolean all_numeric; - guint i; - - /* We must have a given modem specified */ - if (!str || !str[0]) { - g_printerr ("error: no modem was specified\n"); - exit (EXIT_FAILURE); - } - - /* Modem path may come in three ways: - * a) full DBus path - * b) modem index - * c) uid - */ - - *modem_path = NULL; - *modem_uid = NULL; - - /* If we have DBus prefix, we have the modem DBus path */ - if (g_str_has_prefix (str, MM_DBUS_MODEM_PREFIX)) { - g_debug ("Assuming '%s' is the full modem path", str); - *modem_path = g_strdup (str); - return; - } - - /* If all numeric, we have the modem index */ - all_numeric = TRUE; - for (i = 0; str[i]; i++) { - if (!g_ascii_isdigit (str[i])) { - all_numeric = FALSE; - break; - } - } - if (all_numeric) { - g_debug ("Assuming '%s' is the modem index", str); - *modem_path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%s", str); - return; - } - - /* Otherwise we have the UID */ - *modem_uid = g_strdup (str); -} - void mmcli_get_modem (GDBusConnection *connection, - const gchar *modem_str, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -278,8 +301,9 @@ mmcli_get_modem (GDBusConnection *connection, task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetModemContext, 1); - get_modem_path_or_uid (modem_str, &ctx->modem_path, &ctx->modem_uid); - g_assert (ctx->modem_path || ctx->modem_uid); + get_object_lookup_info (str, "modem", MM_DBUS_MODEM_PREFIX, + &ctx->modem_path, &ctx->modem_uid, &ctx->modem_any); + g_assert (!!ctx->modem_path + !!ctx->modem_uid + ctx->modem_any == 1); g_task_set_task_data (task, ctx, (GDestroyNotify) get_modem_context_free); mmcli_get_manager (connection, @@ -290,18 +314,20 @@ mmcli_get_modem (GDBusConnection *connection, MMObject * mmcli_get_modem_sync (GDBusConnection *connection, - const gchar *modem_str, + const gchar *str, MMManager **o_manager) { MMManager *manager; MMObject *found; gchar *modem_path = NULL; gchar *modem_uid = NULL; + gboolean modem_any = FALSE; manager = mmcli_get_manager_sync (connection); - get_modem_path_or_uid (modem_str, &modem_path, &modem_uid); - g_assert (modem_path || modem_uid); - found = find_modem (manager, modem_path, modem_uid); + get_object_lookup_info (str, "modem", MM_DBUS_MODEM_PREFIX, + &modem_path, &modem_uid, &modem_any); + g_assert (!!modem_path + !!modem_uid + modem_any == 1); + found = find_modem (manager, modem_path, modem_uid, modem_any); if (o_manager) *o_manager = manager; @@ -552,37 +578,9 @@ get_bearer_manager_ready (GDBusConnection *connection, look_for_bearer_in_modem (task); } -static gchar * -get_bearer_path (const gchar *path_or_index) -{ - gchar *bearer_path; - - /* We must have a given bearer specified */ - if (!path_or_index) { - g_printerr ("error: no bearer was specified\n"); - exit (EXIT_FAILURE); - } - - /* Bearer path may come in two ways: full DBus path or just bearer index. - * If it is a bearer index, we'll need to generate the DBus path ourselves */ - if (g_str_has_prefix (path_or_index, MM_DBUS_BEARER_PREFIX)) { - g_debug ("Assuming '%s' is the full bearer path", path_or_index); - bearer_path = g_strdup (path_or_index); - } else if (g_ascii_isdigit (path_or_index[0])) { - g_debug ("Assuming '%s' is the bearer index", path_or_index); - bearer_path = g_strdup_printf (MM_DBUS_BEARER_PREFIX "/%s", path_or_index); - } else { - g_printerr ("error: invalid path or index string specified: '%s'\n", - path_or_index); - exit (EXIT_FAILURE); - } - - return bearer_path; -} - void mmcli_get_bearer (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -593,7 +591,9 @@ mmcli_get_bearer (GDBusConnection *connection, task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetBearerContext, 1); - ctx->bearer_path = get_bearer_path (path_or_index); + get_object_lookup_info (str, "bearer", MM_DBUS_BEARER_PREFIX, + &ctx->bearer_path, NULL, NULL); + g_assert (ctx->bearer_path); g_task_set_task_data (task, ctx, (GDestroyNotify) get_bearer_context_free); mmcli_get_manager (connection, @@ -604,7 +604,7 @@ mmcli_get_bearer (GDBusConnection *connection, MMBearer * mmcli_get_bearer_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **o_manager, MMObject **o_object) { @@ -612,9 +612,11 @@ mmcli_get_bearer_sync (GDBusConnection *connection, GList *modems; GList *l; MMBearer *found = NULL; - gchar *bearer_path; + gchar *bearer_path = NULL; - bearer_path = get_bearer_path (path_or_index); + get_object_lookup_info (str, "bearer", MM_DBUS_BEARER_PREFIX, + &bearer_path, NULL, NULL); + g_assert (bearer_path); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); @@ -695,7 +697,8 @@ mmcli_get_bearer_sync (GDBusConnection *connection, typedef struct { gchar *sim_path; - gchar *sim_maybe_uid; + gchar *modem_uid; + gboolean sim_any; MMManager *manager; MMObject *current; } GetSimContext; @@ -722,7 +725,7 @@ get_sim_context_free (GetSimContext *ctx) g_object_unref (ctx->current); if (ctx->manager) g_object_unref (ctx->manager); - g_free (ctx->sim_maybe_uid); + g_free (ctx->modem_uid); g_free (ctx->sim_path); g_free (ctx); } @@ -746,6 +749,53 @@ mmcli_get_sim_finish (GAsyncResult *res, return obj; } +static void +list_sim_slots_ready (MMModem *modem, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(GPtrArray) sim_slots = NULL; + GetSimContext *ctx; + GetSimResults *results = NULL; + guint i; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + sim_slots = mm_modem_list_sim_slots_finish (modem, res, &error); + if (error) { + g_printerr ("error: couldn't list SIM slots at '%s': '%s'\n", + mm_modem_get_path (modem), + error->message); + exit (EXIT_FAILURE); + } + + for (i = 0; i < sim_slots->len; i++) { + MMSim *sim; + + sim = MM_SIM (g_ptr_array_index (sim_slots, i)); + if (sim && g_str_equal (mm_sim_get_path (sim), ctx->sim_path)) { + /* Found! */ + results = g_new (GetSimResults, 1); + results->manager = g_object_ref (ctx->manager); + results->object = g_object_ref (ctx->current); + results->sim = g_object_ref (sim); + break; + } + } + + if (results) { + g_task_return_pointer (task, results, (GDestroyNotify) get_sim_results_free); + g_object_unref (task); + return; + } + + g_printerr ("error: couldn't get additional SIM '%s' at '%s'\n", + ctx->sim_path, + mm_modem_get_path (modem)); + exit (EXIT_FAILURE); +} + static void get_sim_ready (MMModem *modem, GAsyncResult *res, @@ -760,7 +810,7 @@ get_sim_ready (MMModem *modem, sim = mm_modem_get_sim_finish (modem, res, &error); if (error) { - g_printerr ("error: couldn't get sim '%s' at '%s': '%s'\n", + g_printerr ("error: couldn't get SIM '%s' at '%s': '%s'\n", ctx->sim_path, mm_modem_get_path (modem), error->message); @@ -791,76 +841,69 @@ get_sim_manager_ready (GDBusConnection *connection, modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (ctx->manager)); if (!modems) { - g_printerr ("error: couldn't find sim at '%s': 'no modems found'\n", + g_printerr ("error: couldn't find SIM at '%s': 'no modems found'\n", ctx->sim_path); exit (EXIT_FAILURE); } for (l = modems; l && !ctx->current; l = g_list_next (l)) { - MMObject *object; - MMModem *modem; + MMObject *object; + MMModem *modem; + const gchar *const *sim_slot_paths; object = MM_OBJECT (l->data); modem = mm_object_get_modem (object); - if (!ctx->sim_path) { - if (g_str_equal (ctx->sim_maybe_uid, mm_modem_get_device (modem))) + sim_slot_paths = mm_modem_get_sim_slot_paths (modem); + + /* check if we can match the first object found */ + if (ctx->sim_any) { + g_assert (!ctx->sim_path); + ctx->sim_path = g_strdup (mm_modem_get_sim_path (modem)); + } + /* check if modem UID matches */ + else if (ctx->modem_uid) { + if (g_str_equal (ctx->modem_uid, mm_modem_get_device (modem))) { + g_assert (!ctx->sim_path); ctx->sim_path = g_strdup (mm_modem_get_sim_path (modem)); - else { + } else { g_object_unref (modem); continue; } } + if (g_str_equal (ctx->sim_path, mm_modem_get_sim_path (modem))) { ctx->current = g_object_ref (object); mm_modem_get_sim (modem, g_task_get_cancellable (task), (GAsyncReadyCallback)get_sim_ready, task); + } else if (sim_slot_paths) { + guint i; + + for (i = 0; sim_slot_paths[i]; i++) { + if (g_str_equal (ctx->sim_path, sim_slot_paths[i])) { + ctx->current = g_object_ref (object); + mm_modem_list_sim_slots (modem, + g_task_get_cancellable (task), + (GAsyncReadyCallback)list_sim_slots_ready, + task); + break; + } + } } g_object_unref (modem); } g_list_free_full (modems, g_object_unref); - if (!ctx->sim_path) { - g_printerr ("error: invalid index string specified: '%s'\n", - ctx->sim_maybe_uid); - exit (EXIT_FAILURE); - } - if (!ctx->current) { - g_printerr ("error: couldn't find sim at '%s'\n", - ctx->sim_path); - exit (EXIT_FAILURE); - } -} - -static gchar * -get_sim_path (const gchar *path_or_index) -{ - gchar *sim_path = NULL; - - /* We must have a given sim specified */ - if (!path_or_index) { - g_printerr ("error: no sim was specified\n"); + g_printerr ("error: couldn't find SIM\n"); exit (EXIT_FAILURE); } - - /* Sim path may come in two ways: full DBus path or just sim index. - * If it is a sim index, we'll need to generate the DBus path ourselves */ - if (g_str_has_prefix (path_or_index, MM_DBUS_SIM_PREFIX)) { - g_debug ("Assuming '%s' is the full SIM path", path_or_index); - sim_path = g_strdup (path_or_index); - } else if (g_ascii_isdigit (path_or_index[0])) { - g_debug ("Assuming '%s' is the SIM index", path_or_index); - sim_path = g_strdup_printf (MM_DBUS_SIM_PREFIX "/%s", path_or_index); - } - - return sim_path; } void mmcli_get_sim (GDBusConnection *connection, - const gchar *path_or_index_or_uid, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -871,8 +914,9 @@ mmcli_get_sim (GDBusConnection *connection, task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetSimContext, 1); - ctx->sim_path = get_sim_path (path_or_index_or_uid); - ctx->sim_maybe_uid = g_strdup (path_or_index_or_uid); + get_object_lookup_info (str, "SIM", MM_DBUS_SIM_PREFIX, + &ctx->sim_path, &ctx->modem_uid, &ctx->sim_any); + g_assert (!!ctx->sim_path + !!ctx->modem_uid + ctx->sim_any == 1); g_task_set_task_data (task, ctx, (GDestroyNotify) get_sim_context_free); mmcli_get_manager (connection, @@ -883,7 +927,7 @@ mmcli_get_sim (GDBusConnection *connection, MMSim * mmcli_get_sim_sync (GDBusConnection *connection, - const gchar *path_or_index_or_uid, + const gchar *str, MMManager **o_manager, MMObject **o_object) { @@ -891,30 +935,43 @@ mmcli_get_sim_sync (GDBusConnection *connection, GList *modems; GList *l; MMSim *found = NULL; - gchar *sim_path; + gchar *sim_path = NULL; + gchar *modem_uid = NULL; + gboolean sim_any = FALSE; - sim_path = get_sim_path (path_or_index_or_uid); + get_object_lookup_info (str, "SIM", MM_DBUS_SIM_PREFIX, + &sim_path, &modem_uid, &sim_any); + g_assert (!!sim_path + !!modem_uid + sim_any == 1); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { - g_printerr ("error: couldn't find sim at '%s': 'no modems found'\n", + g_printerr ("error: couldn't find SIM at '%s': 'no modems found'\n", sim_path); exit (EXIT_FAILURE); } for (l = modems; !found && l; l = g_list_next (l)) { - GError *error = NULL; - MMObject *object; - MMModem *modem; + GError *error = NULL; + MMObject *object; + MMModem *modem; + const gchar *const *sim_slot_paths; object = MM_OBJECT (l->data); modem = mm_object_get_modem (object); + sim_slot_paths = mm_modem_get_sim_slot_paths (modem); - if (!sim_path) { - if (g_str_equal (path_or_index_or_uid, mm_modem_get_device (modem))) + /* check if we can match the first object found */ + if (sim_any) { + g_assert (!sim_path); + sim_path = g_strdup (mm_modem_get_sim_path (modem)); + } + /* check if modem UID matches */ + else if (modem_uid) { + if (g_str_equal (modem_uid, mm_modem_get_device (modem))) { + g_assert (!sim_path); sim_path = g_strdup (mm_modem_get_sim_path (modem)); - else { + } else { g_object_unref (modem); continue; } @@ -923,7 +980,7 @@ mmcli_get_sim_sync (GDBusConnection *connection, if (g_str_equal (sim_path, mm_modem_get_sim_path (modem))) { found = mm_modem_get_sim_sync (modem, NULL, &error); if (error) { - g_printerr ("error: couldn't get sim '%s' in modem '%s': '%s'\n", + g_printerr ("error: couldn't get SIM '%s' in modem '%s': '%s'\n", sim_path, mm_modem_get_path (modem), error->message); @@ -932,19 +989,41 @@ mmcli_get_sim_sync (GDBusConnection *connection, if (found && o_object) *o_object = g_object_ref (object); + } else if (sim_slot_paths) { + guint i; + + for (i = 0; !found && sim_slot_paths[i]; i++) { + if (g_str_equal (sim_path, sim_slot_paths[i])) { + g_autoptr(GPtrArray) sim_slots = NULL; + guint j; + + sim_slots = mm_modem_list_sim_slots_sync (modem, NULL, &error); + if (error) { + g_printerr ("error: couldn't get SIM slots in modem '%s': '%s'\n", + mm_modem_get_path (modem), + error->message); + exit (EXIT_FAILURE); + } + + for (j = 0; j < sim_slots->len; j++) { + MMSim *sim; + + sim = MM_SIM (g_ptr_array_index (sim_slots, j)); + if (sim && g_str_equal (sim_path, mm_sim_get_path (sim))) { + found = g_object_ref (sim); + if (o_object) + *o_object = g_object_ref (object); + } + } + } + } } g_object_unref (modem); } - if (!sim_path) { - g_printerr ("error: invalid index string specified: '%s'\n", - path_or_index_or_uid); - exit (EXIT_FAILURE); - } - if (!found) { - g_printerr ("error: couldn't find sim at '%s'\n", sim_path); + g_printerr ("error: couldn't find SIM\n"); exit (EXIT_FAILURE); } @@ -1027,7 +1106,7 @@ find_sms_in_list (GList *list, MMSms *sms = MM_SMS (l->data); if (g_str_equal (mm_sms_get_path (sms), sms_path)) { - g_debug ("Sms found at '%s'\n", sms_path); + g_debug ("SMS found at '%s'\n", sms_path); return g_object_ref (sms); } } @@ -1129,37 +1208,9 @@ get_sms_manager_ready (GDBusConnection *connection, look_for_sms_in_modem (task); } -static gchar * -get_sms_path (const gchar *path_or_index) -{ - gchar *sms_path; - - /* We must have a given sms specified */ - if (!path_or_index) { - g_printerr ("error: no SMS was specified\n"); - exit (EXIT_FAILURE); - } - - /* Sms path may come in two ways: full DBus path or just sms index. - * If it is a sms index, we'll need to generate the DBus path ourselves */ - if (g_str_has_prefix (path_or_index, MM_DBUS_SMS_PREFIX)) { - g_debug ("Assuming '%s' is the full SMS path", path_or_index); - sms_path = g_strdup (path_or_index); - } else if (g_ascii_isdigit (path_or_index[0])) { - g_debug ("Assuming '%s' is the SMS index", path_or_index); - sms_path = g_strdup_printf (MM_DBUS_SMS_PREFIX "/%s", path_or_index); - } else { - g_printerr ("error: invalid path or index string specified: '%s'\n", - path_or_index); - exit (EXIT_FAILURE); - } - - return sms_path; -} - void mmcli_get_sms (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -1170,7 +1221,8 @@ mmcli_get_sms (GDBusConnection *connection, task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetSmsContext, 1); - ctx->sms_path = get_sms_path (path_or_index); + get_object_lookup_info (str, "SMS", MM_DBUS_SMS_PREFIX, + &ctx->sms_path, NULL, NULL); g_task_set_task_data (task, ctx, (GDestroyNotify) get_sms_context_free); mmcli_get_manager (connection, @@ -1181,7 +1233,7 @@ mmcli_get_sms (GDBusConnection *connection, MMSms * mmcli_get_sms_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **o_manager, MMObject **o_object) { @@ -1189,14 +1241,15 @@ mmcli_get_sms_sync (GDBusConnection *connection, GList *modems; GList *l; MMSms *found = NULL; - gchar *sms_path; + gchar *sms_path = NULL; - sms_path = get_sms_path (path_or_index); + get_object_lookup_info (str, "SMS", MM_DBUS_SMS_PREFIX, + &sms_path, NULL, NULL); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); if (!modems) { - g_printerr ("error: couldn't find sms at '%s': 'no modems found'\n", + g_printerr ("error: couldn't find SMS at '%s': 'no modems found'\n", sms_path); exit (EXIT_FAILURE); } @@ -1418,37 +1471,9 @@ get_call_manager_ready (GDBusConnection *connection, look_for_call_in_modem (task); } -static gchar * -get_call_path (const gchar *path_or_index) -{ - gchar *call_path; - - /* We must have a given call specified */ - if (!path_or_index) { - g_printerr ("error: no call was specified\n"); - exit (EXIT_FAILURE); - } - - /* Call path may come in two ways: full DBus path or just call index. - * If it is a call index, we'll need to generate the DBus path ourselves */ - if (g_str_has_prefix (path_or_index, MM_DBUS_CALL_PREFIX)) { - g_debug ("Assuming '%s' is the full call path", path_or_index); - call_path = g_strdup (path_or_index); - } else if (g_ascii_isdigit (path_or_index[0])) { - g_debug ("Assuming '%s' is the call index", path_or_index); - call_path = g_strdup_printf (MM_DBUS_CALL_PREFIX "/%s", path_or_index); - } else { - g_printerr ("error: invalid path or index string specified: '%s'\n", - path_or_index); - exit (EXIT_FAILURE); - } - - return call_path; -} - void mmcli_get_call (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -1459,7 +1484,8 @@ mmcli_get_call (GDBusConnection *connection, task = g_task_new (connection, cancellable, callback, user_data); ctx = g_new0 (GetCallContext, 1); - ctx->call_path = get_call_path (path_or_index); + get_object_lookup_info (str, "call", MM_DBUS_CALL_PREFIX, + &ctx->call_path, NULL, NULL); g_task_set_task_data (task, ctx, (GDestroyNotify) get_call_context_free); mmcli_get_manager (connection, @@ -1470,7 +1496,7 @@ mmcli_get_call (GDBusConnection *connection, MMCall * mmcli_get_call_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **o_manager, MMObject **o_object) { @@ -1478,9 +1504,10 @@ mmcli_get_call_sync (GDBusConnection *connection, GList *modems; GList *l; MMCall *found = NULL; - gchar *call_path; + gchar *call_path = NULL; - call_path = get_call_path (path_or_index); + get_object_lookup_info (str, "call", MM_DBUS_CALL_PREFIX, + &call_path, NULL, NULL); manager = mmcli_get_manager_sync (connection); modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager)); @@ -1565,16 +1592,16 @@ static gchar *call_str; static GOptionEntry entries[] = { { "modem", 'm', 0, G_OPTION_ARG_STRING, &modem_str, - "Specify modem by path or index. Shows modem information if no action specified.", - "[PATH|INDEX]" + "Specify modem by path, index, UID or 'any'. Shows modem information if no action specified.", + "[PATH|INDEX|UID|any]" }, { "bearer", 'b', 0, G_OPTION_ARG_STRING, &bearer_str, "Specify bearer by path or index. Shows bearer information if no action specified.", "[PATH|INDEX]" }, { "sim", 'i', 0, G_OPTION_ARG_STRING, &sim_str, - "Specify SIM card by path or index. Shows SIM card information if no action specified.", - "[PATH|INDEX]" + "Specify SIM card by path, index, UID or 'any'. Shows SIM card information if no action specified.", + "[PATH|INDEX|UID|any]" }, { "sms", 's', 0, G_OPTION_ARG_STRING, &sms_str, "Specify SMS by path or index. Shows SMS information if no action specified.", diff --git a/cli/mmcli-common.h b/cli/mmcli-common.h index e3d96c0c..237ebb55 100644 --- a/cli/mmcli-common.h +++ b/cli/mmcli-common.h @@ -34,18 +34,18 @@ MMManager *mmcli_get_manager_finish (GAsyncResult *res); MMManager *mmcli_get_manager_sync (GDBusConnection *connection); void mmcli_get_modem (GDBusConnection *connection, - const gchar *modem_str, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); MMObject *mmcli_get_modem_finish (GAsyncResult *res, MMManager **o_manager); MMObject *mmcli_get_modem_sync (GDBusConnection *connection, - const gchar *modem_str, + const gchar *str, MMManager **o_manager); void mmcli_get_bearer (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -53,12 +53,12 @@ MMBearer *mmcli_get_bearer_finish (GAsyncResult *res, MMManager **manager, MMObject **object); MMBearer *mmcli_get_bearer_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **manager, MMObject **object); void mmcli_get_sim (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -66,12 +66,12 @@ MMSim *mmcli_get_sim_finish (GAsyncResult *res, MMManager **manager, MMObject **object); MMSim *mmcli_get_sim_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **manager, MMObject **object); void mmcli_get_sms (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -79,12 +79,12 @@ MMSms *mmcli_get_sms_finish (GAsyncResult *res, MMManager **manager, MMObject **object); MMSms *mmcli_get_sms_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **manager, MMObject **object); void mmcli_get_call (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -92,7 +92,7 @@ MMCall *mmcli_get_call_finish (GAsyncResult *res, MMManager **manager, MMObject **object); MMCall *mmcli_get_call_sync (GDBusConnection *connection, - const gchar *path_or_index, + const gchar *str, MMManager **manager, MMObject **object); diff --git a/cli/mmcli-manager.c b/cli/mmcli-manager.c index e1e3c36c..011c8c11 100644 --- a/cli/mmcli-manager.c +++ b/cli/mmcli-manager.c @@ -108,7 +108,7 @@ mmcli_manager_get_option_group (void) /* Status options */ group = g_option_group_new ("manager", - "Manager options", + "Manager options:", "Show manager options", NULL, NULL); @@ -332,9 +332,14 @@ output_modem_info (MMObject *obj, gchar *extra; const gchar *manufacturer; const gchar *model; + MMModem *modem; - manufacturer = mm_modem_get_manufacturer (mm_object_peek_modem (obj)); - model = mm_modem_get_model (mm_object_peek_modem (obj)); + modem = mm_object_peek_modem (obj); + if (!modem) + return; + + manufacturer = mm_modem_get_manufacturer (modem); + model = mm_modem_get_model (modem); extra = g_strdup_printf ("[%s] %s", manufacturer ? manufacturer : "manufacturer unknown", model ? model : "model unknown"); @@ -444,7 +449,7 @@ get_manager_ready (GObject *source, #if defined WITH_UDEV if (report_kernel_event_auto_scan) { - const gchar *subsys[] = { "tty", "usbmisc", "net", NULL }; + const gchar *subsys[] = { "tty", "usbmisc", "net", "rpmsg", NULL }; guint i; ctx->udev = g_udev_client_new (subsys); diff --git a/cli/mmcli-modem-3gpp.c b/cli/mmcli-modem-3gpp.c index 21031d66..5136e3f9 100644 --- a/cli/mmcli-modem-3gpp.c +++ b/cli/mmcli-modem-3gpp.c @@ -103,7 +103,7 @@ mmcli_modem_3gpp_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("3gpp", - "3GPP options", + "3GPP options:", "Show 3GPP related options", NULL, NULL); diff --git a/cli/mmcli-modem-cdma.c b/cli/mmcli-modem-cdma.c index 58651b69..cba33a1d 100644 --- a/cli/mmcli-modem-cdma.c +++ b/cli/mmcli-modem-cdma.c @@ -70,7 +70,7 @@ mmcli_modem_cdma_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("cdma", - "CDMA options", + "CDMA options:", "Show CDMA related options", NULL, NULL); diff --git a/cli/mmcli-modem-firmware.c b/cli/mmcli-modem-firmware.c index 20dce4fe..34ceb420 100644 --- a/cli/mmcli-modem-firmware.c +++ b/cli/mmcli-modem-firmware.c @@ -71,7 +71,7 @@ mmcli_modem_firmware_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("firmware", - "Firmware options", + "Firmware options:", "Show Firmware options", NULL, NULL); diff --git a/cli/mmcli-modem-location.c b/cli/mmcli-modem-location.c index 6ef42b7a..cec3220a 100644 --- a/cli/mmcli-modem-location.c +++ b/cli/mmcli-modem-location.c @@ -163,7 +163,7 @@ mmcli_modem_location_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("location", - "Location options", + "Location options:", "Show Location options", NULL, NULL); diff --git a/cli/mmcli-modem-messaging.c b/cli/mmcli-modem-messaging.c index 681929a4..513c6975 100644 --- a/cli/mmcli-modem-messaging.c +++ b/cli/mmcli-modem-messaging.c @@ -82,7 +82,7 @@ mmcli_modem_messaging_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("messaging", - "Messaging options", + "Messaging options:", "Show Messaging options", NULL, NULL); @@ -215,6 +215,7 @@ print_messaging_status (void) mm_modem_messaging_get_supported_storages (ctx->modem_messaging, &supported, &supported_len); if (supported) supported_str = mm_common_build_sms_storages_string (supported, supported_len); + g_free (supported); mmcli_output_string_take (MMC_F_MESSAGING_SUPPORTED_STORAGES, supported_str); mmcli_output_string (MMC_F_MESSAGING_DEFAULT_STORAGES, mm_sms_storage_get_string ( diff --git a/cli/mmcli-modem-oma.c b/cli/mmcli-modem-oma.c index 13fdc5ab..e1a41ada 100644 --- a/cli/mmcli-modem-oma.c +++ b/cli/mmcli-modem-oma.c @@ -87,7 +87,7 @@ mmcli_modem_oma_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("oma", - "OMA options", + "OMA options:", "Show OMA options", NULL, NULL); diff --git a/cli/mmcli-modem-signal.c b/cli/mmcli-modem-signal.c index c5bf435e..7fa476c1 100644 --- a/cli/mmcli-modem-signal.c +++ b/cli/mmcli-modem-signal.c @@ -66,7 +66,7 @@ mmcli_modem_signal_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("signal", - "Signal options", + "Signal options:", "Show Signal options", NULL, NULL); @@ -153,6 +153,9 @@ print_signal_info (void) gchar *lte_rsrp = NULL; gchar *lte_rsrq = NULL; gchar *lte_snr = NULL; + gchar *nr5g_rsrp = NULL; + gchar *nr5g_rsrq = NULL; + gchar *nr5g_snr = NULL; refresh_rate = g_strdup_printf ("%u", mm_modem_signal_get_rate (ctx->modem_signal)); @@ -204,6 +207,16 @@ print_signal_info (void) lte_snr = g_strdup_printf ("%.2lf", value); } + signal = mm_modem_signal_peek_nr5g (ctx->modem_signal); + if (signal) { + if ((value = mm_signal_get_rsrq (signal)) != MM_SIGNAL_UNKNOWN) + nr5g_rsrq = g_strdup_printf ("%.2lf", value); + if ((value = mm_signal_get_rsrp (signal)) != MM_SIGNAL_UNKNOWN) + nr5g_rsrp = g_strdup_printf ("%.2lf", value); + if ((value = mm_signal_get_snr (signal)) != MM_SIGNAL_UNKNOWN) + nr5g_snr = g_strdup_printf ("%.2lf", value); + } + mmcli_output_string_take_typed (MMC_F_SIGNAL_REFRESH_RATE, refresh_rate, "seconds"); mmcli_output_string_take_typed (MMC_F_SIGNAL_CDMA1X_RSSI, cdma1x_rssi, "dBm"); mmcli_output_string_take_typed (MMC_F_SIGNAL_CDMA1X_ECIO, cdma1x_ecio, "dBm"); @@ -219,6 +232,9 @@ print_signal_info (void) mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_RSRQ, lte_rsrq, "dB"); mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_RSRP, lte_rsrp, "dBm"); mmcli_output_string_take_typed (MMC_F_SIGNAL_LTE_SNR, lte_snr, "dB"); + mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_RSRQ, nr5g_rsrq, "dB"); + mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_RSRP, nr5g_rsrp, "dBm"); + mmcli_output_string_take_typed (MMC_F_SIGNAL_5G_SNR, nr5g_snr, "dB"); mmcli_output_dump (); } diff --git a/cli/mmcli-modem-simple.c b/cli/mmcli-modem-simple.c index 35c85a8a..174f144b 100644 --- a/cli/mmcli-modem-simple.c +++ b/cli/mmcli-modem-simple.c @@ -65,7 +65,7 @@ mmcli_modem_simple_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("simple", - "Simple options", + "Simple options:", "Show Simple options", NULL, NULL); diff --git a/cli/mmcli-modem-time.c b/cli/mmcli-modem-time.c index 79f2a80c..98fa06e0 100644 --- a/cli/mmcli-modem-time.c +++ b/cli/mmcli-modem-time.c @@ -61,7 +61,7 @@ mmcli_modem_time_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("time", - "Time options", + "Time options:", "Show Time options", NULL, NULL); diff --git a/cli/mmcli-modem-voice.c b/cli/mmcli-modem-voice.c index 0f066b3f..ab216ea7 100644 --- a/cli/mmcli-modem-voice.c +++ b/cli/mmcli-modem-voice.c @@ -113,7 +113,7 @@ mmcli_modem_voice_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("voice", - "Voice options", + "Voice options:", "Show Voice options", NULL, NULL); diff --git a/cli/mmcli-modem.c b/cli/mmcli-modem.c index e74c7936..9d82fa33 100644 --- a/cli/mmcli-modem.c +++ b/cli/mmcli-modem.c @@ -63,6 +63,7 @@ static gchar *set_current_capabilities_str; static gchar *set_allowed_modes_str; static gchar *set_preferred_mode_str; static gchar *set_current_bands_str; +static gint set_primary_sim_slot_int; static gboolean inhibit_flag; static GOptionEntry entries[] = { @@ -126,6 +127,10 @@ static GOptionEntry entries[] = { "Set bands to be used by a given modem.", "[BAND1|BAND2...]" }, + { "set-primary-sim-slot", 0, 0, G_OPTION_ARG_INT, &set_primary_sim_slot_int, + "Switch to the selected SIM slot", + "[SLOT NUMBER]" + }, { "inhibit", 0, 0, G_OPTION_ARG_NONE, &inhibit_flag, "Inhibit the modem", NULL @@ -140,7 +145,7 @@ mmcli_modem_get_option_group (void) /* Status options */ group = g_option_group_new ("modem", - "Modem options", + "Modem options:", "Show modem options", NULL, NULL); @@ -173,6 +178,7 @@ mmcli_modem_options_enabled (void) !!set_allowed_modes_str + !!set_preferred_mode_str + !!set_current_bands_str + + (set_primary_sim_slot_int > 0) + inhibit_flag); if (n_actions == 0 && mmcli_get_common_modem_string ()) { @@ -407,7 +413,7 @@ print_modem_info (void) pco_list = mm_modem_3gpp_get_pco (ctx->modem_3gpp); initial_eps_bearer_path = mm_modem_3gpp_get_initial_eps_bearer_path (ctx->modem_3gpp); - if (mm_modem_get_current_capabilities (ctx->modem) & (MM_MODEM_CAPABILITY_LTE | MM_MODEM_CAPABILITY_LTE_ADVANCED)) { + if (mm_modem_get_current_capabilities (ctx->modem) & (MM_MODEM_CAPABILITY_LTE)) { MMBearerProperties *initial_eps_bearer_properties; initial_eps_bearer_properties = mm_modem_3gpp_peek_initial_eps_bearer_settings (ctx->modem_3gpp); @@ -475,6 +481,8 @@ print_modem_info (void) sim_path = mm_modem_get_sim_path (ctx->modem); mmcli_output_string (MMC_F_SIM_PATH, g_strcmp0 (sim_path, "/") != 0 ? sim_path : NULL); + mmcli_output_sim_slots (mm_modem_dup_sim_slot_paths (ctx->modem), + mm_modem_get_primary_sim_slot (ctx->modem)); bearer_paths = (const gchar **) mm_modem_get_bearer_paths (ctx->modem); mmcli_output_string_array (MMC_F_BEARER_PATHS, (bearer_paths && bearer_paths[0]) ? bearer_paths : NULL, TRUE); @@ -888,6 +896,32 @@ parse_current_bands (MMModemBand **bands, } } +static void +set_primary_sim_slot_process_reply (gboolean result, + const GError *error) +{ + if (!result) { + g_printerr ("error: couldn't request primary SIM switch: '%s'\n", + error ? error->message : "unknown error"); + exit (EXIT_FAILURE); + } + + g_print ("successfully requested primary SIM switch in modem\n"); +} + +static void +set_primary_sim_slot_ready (MMModem *modem, + GAsyncResult *result) +{ + gboolean operation_result; + g_autoptr(GError) error = NULL; + + operation_result = mm_modem_set_primary_sim_slot_finish (modem, result, &error); + set_primary_sim_slot_process_reply (operation_result, error); + + mmcli_async_operation_done (); +} + static void state_changed (MMModem *modem, MMModemState old_state, @@ -1130,6 +1164,16 @@ get_modem_ready (GObject *source, return; } + /* Request to switch SIM? */ + if (set_primary_sim_slot_int > 0) { + mm_modem_set_primary_sim_slot (ctx->modem, + set_primary_sim_slot_int, + ctx->cancellable, + (GAsyncReadyCallback)set_primary_sim_slot_ready, + NULL); + return; + } + /* Request to inhibit the modem? */ if (inhibit_flag) { gchar *uid; @@ -1389,5 +1433,14 @@ mmcli_modem_run_synchronous (GDBusConnection *connection) return; } + /* Request to switch current SIM? */ + if (set_primary_sim_slot_int > 0) { + gboolean result; + + result = mm_modem_set_primary_sim_slot_sync (ctx->modem, set_primary_sim_slot_int, NULL, &error); + set_primary_sim_slot_process_reply (result, error); + return; + } + g_warn_if_reached (); } diff --git a/cli/mmcli-output.c b/cli/mmcli-output.c index 25877b0b..275e7066 100644 --- a/cli/mmcli-output.c +++ b/cli/mmcli-output.c @@ -57,6 +57,7 @@ static SectionInfo section_infos[] = { [MMC_S_MODEM_SIGNAL_GSM] = { "GSM" }, [MMC_S_MODEM_SIGNAL_UMTS] = { "UMTS" }, [MMC_S_MODEM_SIGNAL_LTE] = { "LTE" }, + [MMC_S_MODEM_SIGNAL_5G] = { "5G" }, [MMC_S_MODEM_OMA] = { "OMA" }, [MMC_S_MODEM_OMA_CURRENT] = { "Current session" }, [MMC_S_MODEM_OMA_PENDING] = { "Pending sessions" }, @@ -93,7 +94,7 @@ typedef struct { } FieldInfo; static FieldInfo field_infos[] = { - [MMC_F_GENERAL_DBUS_PATH] = { "modem.dbus-path", "dbus path", MMC_S_MODEM_GENERAL, }, + [MMC_F_GENERAL_DBUS_PATH] = { "modem.dbus-path", "path", MMC_S_MODEM_GENERAL, }, [MMC_F_GENERAL_DEVICE_ID] = { "modem.generic.device-identifier", "device id", MMC_S_MODEM_GENERAL, }, [MMC_F_HARDWARE_MANUFACTURER] = { "modem.generic.manufacturer", "manufacturer", MMC_S_MODEM_HARDWARE, }, [MMC_F_HARDWARE_MODEL] = { "modem.generic.model", "model", MMC_S_MODEM_HARDWARE, }, @@ -130,7 +131,7 @@ static FieldInfo field_infos[] = { [MMC_F_3GPP_REGISTRATION] = { "modem.3gpp.registration-state", "registration", MMC_S_MODEM_3GPP, }, [MMC_F_3GPP_PCO] = { "modem.3gpp.pco", "pco", MMC_S_MODEM_3GPP, }, [MMC_F_3GPP_EPS_UE_MODE] = { "modem.3gpp.eps.ue-mode-operation", "ue mode of operation", MMC_S_MODEM_3GPP_EPS, }, - [MMC_F_3GPP_EPS_INITIAL_BEARER_PATH] = { "modem.3gpp.eps.initial-bearer.dbus-path", "initial bearer dbus path", MMC_S_MODEM_3GPP_EPS, }, + [MMC_F_3GPP_EPS_INITIAL_BEARER_PATH] = { "modem.3gpp.eps.initial-bearer.dbus-path", "initial bearer path", MMC_S_MODEM_3GPP_EPS, }, [MMC_F_3GPP_EPS_BEARER_SETTINGS_APN] = { "modem.3gpp.eps.initial-bearer.settings.apn", "initial bearer apn", MMC_S_MODEM_3GPP_EPS, }, [MMC_F_3GPP_EPS_BEARER_SETTINGS_IP_TYPE] = { "modem.3gpp.eps.initial-bearer.settings.ip-type", "initial bearer ip type", MMC_S_MODEM_3GPP_EPS, }, [MMC_F_3GPP_EPS_BEARER_SETTINGS_USER] = { "modem.3gpp.eps.initial-bearer.settings.user", "initial bearer user", MMC_S_MODEM_3GPP_EPS, }, @@ -146,8 +147,10 @@ static FieldInfo field_infos[] = { [MMC_F_CDMA_REGISTRATION_CDMA1X] = { "modem.cdma.cdma1x-registration-state", "registration cdma1x", MMC_S_MODEM_CDMA, }, [MMC_F_CDMA_REGISTRATION_EVDO] = { "modem.cdma.evdo-registration-state", "registration evdo", MMC_S_MODEM_CDMA, }, [MMC_F_CDMA_ACTIVATION] = { "modem.cdma.activation-state", "activation", MMC_S_MODEM_CDMA, }, - [MMC_F_SIM_PATH] = { "modem.generic.sim", "dbus path", MMC_S_MODEM_SIM, }, - [MMC_F_BEARER_PATHS] = { "modem.generic.bearers", "dbus path", MMC_S_MODEM_BEARER, }, + [MMC_F_SIM_PATH] = { "modem.generic.sim", "primary sim path", MMC_S_MODEM_SIM, }, + [MMC_F_SIM_PRIMARY_SLOT] = { "modem.generic.primary-sim-slot", NULL, MMC_S_MODEM_SIM, }, + [MMC_F_SIM_SLOT_PATHS] = { "modem.generic.sim-slots", "sim slot paths", MMC_S_MODEM_SIM, }, + [MMC_F_BEARER_PATHS] = { "modem.generic.bearers", "paths", MMC_S_MODEM_BEARER, }, [MMC_F_TIME_CURRENT] = { "modem.time.current", "current", MMC_S_MODEM_TIME, }, [MMC_F_TIMEZONE_CURRENT] = { "modem.timezone.current", "current", MMC_S_MODEM_TIMEZONE, }, [MMC_F_TIMEZONE_DST_OFFSET] = { "modem.time.dst-offset", "dst offset", MMC_S_MODEM_TIMEZONE, }, @@ -169,6 +172,9 @@ static FieldInfo field_infos[] = { [MMC_F_SIGNAL_LTE_RSRQ] = { "modem.signal.lte.rsrq", "rsrq", MMC_S_MODEM_SIGNAL_LTE, }, [MMC_F_SIGNAL_LTE_RSRP] = { "modem.signal.lte.rsrp", "rsrp", MMC_S_MODEM_SIGNAL_LTE, }, [MMC_F_SIGNAL_LTE_SNR] = { "modem.signal.lte.snr", "s/n", MMC_S_MODEM_SIGNAL_LTE, }, + [MMC_F_SIGNAL_5G_RSRQ] = { "modem.signal.5g.rsrq", "rsrq", MMC_S_MODEM_SIGNAL_5G, }, + [MMC_F_SIGNAL_5G_RSRP] = { "modem.signal.5g.rsrp", "rsrp", MMC_S_MODEM_SIGNAL_5G, }, + [MMC_F_SIGNAL_5G_SNR] = { "modem.signal.5g.snr", "s/n", MMC_S_MODEM_SIGNAL_5G, }, [MMC_F_OMA_FEATURES] = { "modem.oma.features", "features", MMC_S_MODEM_OMA, }, [MMC_F_OMA_CURRENT_TYPE] = { "modem.oma.current.type", "type", MMC_S_MODEM_OMA_CURRENT, }, [MMC_F_OMA_CURRENT_STATE] = { "modem.oma.current.state", "state", MMC_S_MODEM_OMA_CURRENT, }, @@ -198,7 +204,7 @@ static FieldInfo field_infos[] = { [MMC_F_FIRMWARE_VERSION] = { "modem.firmware.version", "version", MMC_S_MODEM_FIRMWARE, }, [MMC_F_FIRMWARE_FASTBOOT_AT] = { "modem.firmware.fastboot.at", "at command", MMC_S_MODEM_FIRMWARE_FASTBOOT, }, [MMC_F_VOICE_EMERGENCY_ONLY] = { "modem.voice.emergency-only", "emergency only", MMC_S_MODEM_VOICE, }, - [MMC_F_BEARER_GENERAL_DBUS_PATH] = { "bearer.dbus-path", "dbus path", MMC_S_BEARER_GENERAL, }, + [MMC_F_BEARER_GENERAL_DBUS_PATH] = { "bearer.dbus-path", "path", MMC_S_BEARER_GENERAL, }, [MMC_F_BEARER_GENERAL_TYPE] = { "bearer.type", "type", MMC_S_BEARER_GENERAL, }, [MMC_F_BEARER_STATUS_CONNECTED] = { "bearer.status.connected", "connected", MMC_S_BEARER_STATUS, }, [MMC_F_BEARER_STATUS_SUSPENDED] = { "bearer.status.suspended", "suspended", MMC_S_BEARER_STATUS, }, @@ -207,6 +213,7 @@ static FieldInfo field_infos[] = { [MMC_F_BEARER_PROPERTIES_APN] = { "bearer.properties.apn", "apn", MMC_S_BEARER_PROPERTIES, }, [MMC_F_BEARER_PROPERTIES_ROAMING] = { "bearer.properties.roaming", "roaming", MMC_S_BEARER_PROPERTIES, }, [MMC_F_BEARER_PROPERTIES_IP_TYPE] = { "bearer.properties.ip-type", "ip type", MMC_S_BEARER_PROPERTIES, }, + [MMC_F_BEARER_PROPERTIES_ALLOWED_AUTH] = { "bearer.properties.allowed-auth", "allowed-auth", MMC_S_BEARER_PROPERTIES, }, [MMC_F_BEARER_PROPERTIES_USER] = { "bearer.properties.user", "user", MMC_S_BEARER_PROPERTIES, }, [MMC_F_BEARER_PROPERTIES_PASSWORD] = { "bearer.properties.password", "password", MMC_S_BEARER_PROPERTIES, }, [MMC_F_BEARER_PROPERTIES_NUMBER] = { "bearer.properties.number", "number", MMC_S_BEARER_PROPERTIES, }, @@ -226,7 +233,12 @@ static FieldInfo field_infos[] = { [MMC_F_BEARER_STATS_DURATION] = { "bearer.stats.duration", "duration", MMC_S_BEARER_STATS, }, [MMC_F_BEARER_STATS_BYTES_RX] = { "bearer.stats.bytes-rx", "bytes rx", MMC_S_BEARER_STATS, }, [MMC_F_BEARER_STATS_BYTES_TX] = { "bearer.stats.bytes-tx", "bytes tx", MMC_S_BEARER_STATS, }, - [MMC_F_CALL_GENERAL_DBUS_PATH] = { "call.dbus-path", "dbus path", MMC_S_CALL_GENERAL, }, + [MMC_F_BEARER_STATS_ATTEMPTS] = { "bearer.stats.attempts", "attempts", MMC_S_BEARER_STATS, }, + [MMC_F_BEARER_STATS_FAILED_ATTEMPTS] = { "bearer.stats.failed-attempts", "attempts", MMC_S_BEARER_STATS, }, + [MMC_F_BEARER_STATS_TOTAL_DURATION] = { "bearer.stats.total-duration", "total-duration", MMC_S_BEARER_STATS, }, + [MMC_F_BEARER_STATS_TOTAL_BYTES_RX] = { "bearer.stats.total-bytes-rx", "total-bytes rx", MMC_S_BEARER_STATS, }, + [MMC_F_BEARER_STATS_TOTAL_BYTES_TX] = { "bearer.stats.total-bytes-tx", "total-bytes tx", MMC_S_BEARER_STATS, }, + [MMC_F_CALL_GENERAL_DBUS_PATH] = { "call.dbus-path", "path", MMC_S_CALL_GENERAL, }, [MMC_F_CALL_PROPERTIES_NUMBER] = { "call.properties.number", "number", MMC_S_CALL_PROPERTIES, }, [MMC_F_CALL_PROPERTIES_DIRECTION] = { "call.properties.direction", "direction", MMC_S_CALL_PROPERTIES, }, [MMC_F_CALL_PROPERTIES_MULTIPARTY] = { "call.properties.multiparty", "multiparty", MMC_S_CALL_PROPERTIES, }, @@ -236,7 +248,7 @@ static FieldInfo field_infos[] = { [MMC_F_CALL_AUDIO_FORMAT_ENCODING] = { "call.audio-format.encoding", "encoding", MMC_S_CALL_AUDIO_FORMAT, }, [MMC_F_CALL_AUDIO_FORMAT_RESOLUTION] = { "call.audio-format.resolution", "resolution", MMC_S_CALL_AUDIO_FORMAT, }, [MMC_F_CALL_AUDIO_FORMAT_RATE] = { "call.audio-format.rate", "rate", MMC_S_CALL_AUDIO_FORMAT, }, - [MMC_F_SMS_GENERAL_DBUS_PATH] = { "sms.dbus-path", "dbus path", MMC_S_SMS_GENERAL, }, + [MMC_F_SMS_GENERAL_DBUS_PATH] = { "sms.dbus-path", "path", MMC_S_SMS_GENERAL, }, [MMC_F_SMS_CONTENT_NUMBER] = { "sms.content.number", "number", MMC_S_SMS_CONTENT, }, [MMC_F_SMS_CONTENT_TEXT] = { "sms.content.text", "text", MMC_S_SMS_CONTENT, }, [MMC_F_SMS_CONTENT_DATA] = { "sms.content.data", "data", MMC_S_SMS_CONTENT, }, @@ -253,9 +265,11 @@ static FieldInfo field_infos[] = { [MMC_F_SMS_PROPERTIES_TIMESTAMP] = { "sms.properties.timestamp", "timestamp", MMC_S_SMS_PROPERTIES, }, [MMC_F_SMS_PROPERTIES_DELIVERY_STATE] = { "sms.properties.delivery-state", "delivery state", MMC_S_SMS_PROPERTIES, }, [MMC_F_SMS_PROPERTIES_DISCH_TIMESTAMP] = { "sms.properties.discharge-timestamp", "discharge timestamp", MMC_S_SMS_PROPERTIES, }, - [MMC_F_SIM_GENERAL_DBUS_PATH] = { "sim.dbus-path", "dbus path", MMC_S_SIM_GENERAL, }, + [MMC_F_SIM_GENERAL_DBUS_PATH] = { "sim.dbus-path", "path", MMC_S_SIM_GENERAL, }, + [MMC_F_SIM_PROPERTIES_ACTIVE] = { "sim.properties.active", "active", MMC_S_SIM_PROPERTIES, }, [MMC_F_SIM_PROPERTIES_IMSI] = { "sim.properties.imsi", "imsi", MMC_S_SIM_PROPERTIES, }, [MMC_F_SIM_PROPERTIES_ICCID] = { "sim.properties.iccid", "iccid", MMC_S_SIM_PROPERTIES, }, + [MMC_F_SIM_PROPERTIES_EID] = { "sim.properties.eid", "eid", MMC_S_SIM_PROPERTIES, }, [MMC_F_SIM_PROPERTIES_OPERATOR_ID] = { "sim.properties.operator-code", "operator id", MMC_S_SIM_PROPERTIES, }, [MMC_F_SIM_PROPERTIES_OPERATOR_NAME] = { "sim.properties.operator-name", "operator name", MMC_S_SIM_PROPERTIES, }, [MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS] = { "sim.properties.emergency-numbers", "emergency numbers", MMC_S_SIM_PROPERTIES, }, @@ -558,6 +572,37 @@ mmcli_output_state (MMModemState state, NULL); } +/******************************************************************************/ +/* (Custom) SIM slots output */ + +void +mmcli_output_sim_slots (gchar **sim_slot_paths, + guint primary_sim_slot) +{ + guint i; + + if (selected_type != MMC_OUTPUT_TYPE_HUMAN || !sim_slot_paths) { + mmcli_output_string_take (MMC_F_SIM_PRIMARY_SLOT, primary_sim_slot ? g_strdup_printf ("%u", primary_sim_slot) : NULL); + mmcli_output_string_array_take (MMC_F_SIM_SLOT_PATHS, sim_slot_paths ? sim_slot_paths : NULL, TRUE); + return; + } + + /* Include SIM slot number in each item */ + for (i = 0; sim_slot_paths[i]; i++) { + gchar *aux; + guint slot_number = i + 1; + + aux = g_strdup_printf ("slot %u: %s%s", + slot_number, + g_str_equal (sim_slot_paths[i], "/") ? "none" : sim_slot_paths[i], + (primary_sim_slot == slot_number) ? " (active)" : ""); + g_free (sim_slot_paths[i]); + sim_slot_paths[i] = aux; + } + + mmcli_output_string_array_take (MMC_F_SIM_SLOT_PATHS, sim_slot_paths, TRUE); +} + /******************************************************************************/ /* (Custom) Network scan output */ @@ -1081,6 +1126,49 @@ dump_output_list_keyvalue (MmcF field) /******************************************************************************/ /* JSON-friendly output */ +static gchar * +json_strescape (const gchar *str) +{ + const gchar *p; + const gchar *end; + GString *output; + gsize len; + + len = strlen (str); + end = str + len; + output = g_string_sized_new (len); + + for (p = str; p < end; p++) { + if (*p == '\\' || *p == '"') { + g_string_append_c (output, '\\'); + g_string_append_c (output, *p); + } else if ((*p > 0 && *p < 0x1f) || *p == 0x7f) { + switch (*p) { + case '\b': + g_string_append (output, "\\b"); + break; + case '\f': + g_string_append (output, "\\f"); + break; + case '\n': + g_string_append (output, "\\n"); + break; + case '\r': + g_string_append (output, "\\r"); + break; + case '\t': + g_string_append (output, "\\t"); + break; + default: + g_string_append_printf (output, "\\u00%02x", (guint)*p); + break; + } + } else + g_string_append_c (output, *p); + } + return g_string_free (output, FALSE); +} + static gint list_sort_by_keys (const OutputItem *item_a, const OutputItem *item_b) @@ -1140,7 +1228,7 @@ dump_output_json (void) gchar *escaped = NULL; if (single->value) - escaped = g_strescape (single->value, "\v"); + escaped = json_strescape (single->value); g_print ("\"%s\":\"%s\"", current_path[cur_dlen], escaped ? escaped : "--"); g_free (escaped); @@ -1154,7 +1242,7 @@ dump_output_json (void) for (i = 0; i < n; i++) { gchar *escaped; - escaped = g_strescape (multiple->values[i], "\v"); + escaped = json_strescape (multiple->values[i]); g_print("\"%s\"", escaped); if (i < n - 1) g_print(","); diff --git a/cli/mmcli-output.h b/cli/mmcli-output.h index bd7b317a..928bcd38 100644 --- a/cli/mmcli-output.h +++ b/cli/mmcli-output.h @@ -54,6 +54,7 @@ typedef enum { MMC_S_MODEM_SIGNAL_GSM, MMC_S_MODEM_SIGNAL_UMTS, MMC_S_MODEM_SIGNAL_LTE, + MMC_S_MODEM_SIGNAL_5G, MMC_S_MODEM_OMA, MMC_S_MODEM_OMA_CURRENT, MMC_S_MODEM_OMA_PENDING, @@ -153,6 +154,8 @@ typedef enum { MMC_F_CDMA_ACTIVATION, /* SIM section */ MMC_F_SIM_PATH, + MMC_F_SIM_PRIMARY_SLOT, + MMC_F_SIM_SLOT_PATHS, /* Bearer section */ MMC_F_BEARER_PATHS, /* Time section */ @@ -179,6 +182,9 @@ typedef enum { MMC_F_SIGNAL_LTE_RSRQ, MMC_F_SIGNAL_LTE_RSRP, MMC_F_SIGNAL_LTE_SNR, + MMC_F_SIGNAL_5G_RSRQ, + MMC_F_SIGNAL_5G_RSRP, + MMC_F_SIGNAL_5G_SNR, /* OMA section */ MMC_F_OMA_FEATURES, MMC_F_OMA_CURRENT_TYPE, @@ -224,6 +230,7 @@ typedef enum { MMC_F_BEARER_PROPERTIES_APN, MMC_F_BEARER_PROPERTIES_ROAMING, MMC_F_BEARER_PROPERTIES_IP_TYPE, + MMC_F_BEARER_PROPERTIES_ALLOWED_AUTH, MMC_F_BEARER_PROPERTIES_USER, MMC_F_BEARER_PROPERTIES_PASSWORD, MMC_F_BEARER_PROPERTIES_NUMBER, @@ -243,6 +250,11 @@ typedef enum { MMC_F_BEARER_STATS_DURATION, MMC_F_BEARER_STATS_BYTES_RX, MMC_F_BEARER_STATS_BYTES_TX, + MMC_F_BEARER_STATS_ATTEMPTS, + MMC_F_BEARER_STATS_FAILED_ATTEMPTS, + MMC_F_BEARER_STATS_TOTAL_DURATION, + MMC_F_BEARER_STATS_TOTAL_BYTES_RX, + MMC_F_BEARER_STATS_TOTAL_BYTES_TX, MMC_F_CALL_GENERAL_DBUS_PATH, MMC_F_CALL_PROPERTIES_NUMBER, MMC_F_CALL_PROPERTIES_DIRECTION, @@ -271,8 +283,10 @@ typedef enum { MMC_F_SMS_PROPERTIES_DELIVERY_STATE, MMC_F_SMS_PROPERTIES_DISCH_TIMESTAMP, MMC_F_SIM_GENERAL_DBUS_PATH, + MMC_F_SIM_PROPERTIES_ACTIVE, MMC_F_SIM_PROPERTIES_IMSI, MMC_F_SIM_PROPERTIES_ICCID, + MMC_F_SIM_PROPERTIES_EID, MMC_F_SIM_PROPERTIES_OPERATOR_ID, MMC_F_SIM_PROPERTIES_OPERATOR_NAME, MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS, @@ -327,14 +341,16 @@ void mmcli_output_listitem (MmcF field, /******************************************************************************/ /* Custom output management */ -void mmcli_output_signal_quality (guint value, - gboolean recent); -void mmcli_output_state (MMModemState state, - MMModemStateFailedReason reason); -void mmcli_output_scan_networks (GList *network_list); -void mmcli_output_firmware_list (GList *firmware_list, - MMFirmwareProperties *selected); -void mmcli_output_pco_list (GList *pco_list); +void mmcli_output_signal_quality (guint value, + gboolean recent); +void mmcli_output_state (MMModemState state, + MMModemStateFailedReason reason); +void mmcli_output_sim_slots (gchar **sim_slot_paths, + guint primary_sim_slot); +void mmcli_output_scan_networks (GList *network_list); +void mmcli_output_firmware_list (GList *firmware_list, + MMFirmwareProperties *selected); +void mmcli_output_pco_list (GList *pco_list); /******************************************************************************/ /* Dump output */ diff --git a/cli/mmcli-sim.c b/cli/mmcli-sim.c index 75d3d075..2a1fed3a 100644 --- a/cli/mmcli-sim.c +++ b/cli/mmcli-sim.c @@ -83,7 +83,7 @@ mmcli_sim_get_option_group (void) /* Status options */ group = g_option_group_new ("sim", - "SIM options", + "SIM options:", "Show SIM options", NULL, NULL); @@ -159,8 +159,10 @@ static void print_sim_info (MMSim *sim) { mmcli_output_string (MMC_F_SIM_GENERAL_DBUS_PATH, mm_sim_get_path (sim)); + mmcli_output_string (MMC_F_SIM_PROPERTIES_ACTIVE, mm_sim_get_active (sim) ? "yes" : "no"); mmcli_output_string (MMC_F_SIM_PROPERTIES_IMSI, mm_sim_get_imsi (sim)); mmcli_output_string (MMC_F_SIM_PROPERTIES_ICCID, mm_sim_get_identifier (sim)); + mmcli_output_string (MMC_F_SIM_PROPERTIES_EID, mm_sim_get_eid (sim)); mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_ID, mm_sim_get_operator_identifier (sim)); mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_NAME, mm_sim_get_operator_name (sim)); mmcli_output_string_array (MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS, (const gchar **) mm_sim_get_emergency_numbers (sim), FALSE); diff --git a/cli/mmcli-sms.c b/cli/mmcli-sms.c index a5fa45bf..c468ed60 100644 --- a/cli/mmcli-sms.c +++ b/cli/mmcli-sms.c @@ -78,7 +78,7 @@ mmcli_sms_get_option_group (void) /* Status options */ group = g_option_group_new ("sms", - "SMS options", + "SMS options:", "Show SMS options", NULL, NULL); diff --git a/cli/mmcli.c b/cli/mmcli.c index 64a2c697..2e1cc727 100644 --- a/cli/mmcli.c +++ b/cli/mmcli.c @@ -147,9 +147,8 @@ log_handler (const gchar *log_domain, static void print_version_and_exit (void) { - g_print ("\n" - PROGRAM_NAME " " PROGRAM_VERSION "\n" - "Copyright (2011 - 2020) Aleksander Morgado\n" + g_print (PROGRAM_NAME " " PROGRAM_VERSION "\n" + "Copyright (2011 - 2021) Aleksander Morgado\n" "License GPLv2+: GNU GPL version 2 or later \n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" @@ -189,7 +188,8 @@ mmcli_force_sync_operation (void) void mmcli_force_operation_timeout (GDBusProxy *proxy) { - g_dbus_proxy_set_default_timeout (proxy, timeout * 1000); + if (proxy) + g_dbus_proxy_set_default_timeout (proxy, timeout * 1000); } gint diff --git a/configure.ac b/configure.ac index 7ef20717..92e9a09a 100644 --- a/configure.ac +++ b/configure.ac @@ -5,8 +5,8 @@ dnl Package and library versioning support dnl m4_define([mm_major_version], [1]) -m4_define([mm_minor_version], [13]) -m4_define([mm_micro_version], [0]) +m4_define([mm_minor_version], [16]) +m4_define([mm_micro_version], [8]) m4_define([mm_version], [mm_major_version.mm_minor_version.mm_micro_version]) @@ -18,14 +18,17 @@ dnl If the interface has grown (that is, the new library is compatible dnl with old code), increment a. dnl If the interface has changed in an incompatible way (that is, dnl functions have changed or been removed), then zero a. -m4_define([mm_glib_lt_current], [5]) +m4_define([mm_glib_lt_current], [7]) m4_define([mm_glib_lt_revision], [0]) -m4_define([mm_glib_lt_age], [5]) +m4_define([mm_glib_lt_age], [7]) dnl----------------------------------------------------------------------------- dnl autoconf, automake, libtool initialization dnl -AC_INIT([ModemManager],[mm_version],[modemmanager-devel@lists.freedesktop.org],[ModemManager]) +AC_INIT([ModemManager], + [mm_version], + [https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues], + [ModemManager]) AM_INIT_AUTOMAKE([1.11.2 subdir-objects tar-ustar no-dist-gzip dist-xz -Wno-portability]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -159,6 +162,12 @@ AC_SUBST(GLIB_MKENUMS) GDBUS_CODEGEN=`$PKG_CONFIG --variable=gdbus_codegen gio-2.0` AC_SUBST(GDBUS_CODEGEN) +dnl xsltproc required in git builds only +AC_CHECK_PROG(XSLTPROC_CHECK,xsltproc,yes) +if test "x$ax_is_release" != "xyes" -a "x$XSLTPROC_CHECK" != "xyes"; then + AC_MSG_ERROR([Please install xsltproc before configuring.]) +fi + dnl----------------------------------------------------------------------------- dnl Testing support dnl @@ -239,13 +248,14 @@ dnl PKG_CHECK_MODULES(LIBSYSTEMD, [libsystemd >= 209],[have_libsystemd=yes],[have_libsystemd=no]) PKG_CHECK_MODULES(LIBSYSTEMD_LOGIN, [libsystemd-login >= 183],[have_libsystemd_login=yes],[have_libsystemd_login=no]) +PKG_CHECK_MODULES(LIBELOGIND, [libelogind >= 209], [have_elogind=yes], [have_elogind=no]) AC_ARG_WITH(systemd-suspend-resume, AS_HELP_STRING([--with-systemd-suspend-resume=no|yes], [Enable systemd suspend/resume support [[default=auto]]]),, [with_systemd_suspend_resume=auto]) if test "x$with_systemd_suspend_resume" = "xauto"; then - if test "x$have_libsystemd" = "xyes" || test "x$have_libsystemd_login" = "xyes"; then + if test "x$have_libsystemd" = "xyes" || test "x$have_libsystemd_login" = "xyes" || test "x$have_elogind" = "xyes"; then with_systemd_suspend_resume=yes else with_systemd_suspend_resume=no @@ -254,8 +264,8 @@ fi case $with_systemd_suspend_resume in yes) - if test "x$have_libsystemd" = "xno" && test "x$have_libsystemd_login" = "xno"; then - AC_MSG_ERROR(libsystemd or libsystemd-login development headers are required) + if test "x$have_libsystemd" = "xno" && test "x$have_libsystemd_login" = "xno" && test "x$have_elogind" = "xno"; then + AC_MSG_WARN(libsystemd, libsystemd-login or elogind must be available at runtime for suspend/resume support) fi AC_DEFINE(WITH_SYSTEMD_SUSPEND_RESUME, 1, [Define if you have systemd suspend-resume support]) ;; @@ -367,7 +377,7 @@ dnl----------------------------------------------------------------------------- dnl MBIM support (enabled by default) dnl -LIBMBIM_VERSION=1.18.0 +LIBMBIM_VERSION=1.24.0 AC_ARG_WITH(mbim, AS_HELP_STRING([--without-mbim], [Build without MBIM support]), [], [with_mbim=yes]) AM_CONDITIONAL(WITH_MBIM, test "x$with_mbim" = "xyes") @@ -391,7 +401,7 @@ dnl----------------------------------------------------------------------------- dnl QMI support (enabled by default) dnl -LIBQMI_VERSION=1.25.1 +LIBQMI_VERSION=1.28.6 AC_ARG_WITH(qmi, AS_HELP_STRING([--without-qmi], [Build without QMI support]), [], [with_qmi=yes]) AM_CONDITIONAL(WITH_QMI, test "x$with_qmi" = "xyes") @@ -448,6 +458,7 @@ MM_ENABLE_ALL_PLUGINS MM_ENABLE_PLUGIN([generic]) MM_ENABLE_PLUGIN([altair-lte]) MM_ENABLE_PLUGIN([anydata]) +MM_ENABLE_PLUGIN([broadmobi]) MM_ENABLE_PLUGIN([cinterion]) MM_ENABLE_PLUGIN([dell], [with_shared_sierra, @@ -460,6 +471,7 @@ MM_ENABLE_PLUGIN([fibocom], [with_shared_xmm]) MM_ENABLE_PLUGIN([foxconn], [with_shared_foxconn]) +MM_ENABLE_PLUGIN([gosuncn]) MM_ENABLE_PLUGIN([haier]) MM_ENABLE_PLUGIN([huawei]) MM_ENABLE_PLUGIN([iridium]) @@ -479,13 +491,15 @@ MM_ENABLE_PLUGIN([option], MM_ENABLE_PLUGIN([option-hso], [with_shared_option]) MM_ENABLE_PLUGIN([pantech]) +MM_ENABLE_PLUGIN_DISABLED([qcom-soc]) MM_ENABLE_PLUGIN([quectel]) MM_ENABLE_PLUGIN([samsung], [with_shared_icera]) MM_ENABLE_PLUGIN([sierra-legacy], [with_shared_icera, with_shared_sierra]) -MM_ENABLE_PLUGIN([sierra]) +MM_ENABLE_PLUGIN([sierra], + [with_shared_xmm]) MM_ENABLE_PLUGIN([simtech]) MM_ENABLE_PLUGIN([telit], [with_shared_telit]) @@ -528,6 +542,9 @@ src/Makefile src/tests/Makefile plugins/Makefile test/Makefile +tools/Makefile +tools/tests/Makefile +tools/tests/services/org.freedesktop.ModemManager1.service introspection/Makefile introspection/tests/Makefile po/Makefile.in @@ -593,11 +610,13 @@ echo " generic: ${enable_plugin_generic} altair lte: ${enable_plugin_altair_lte} anydata: ${enable_plugin_anydata} + broadmobi: ${enable_plugin_broadmobi} cinterion: ${enable_plugin_cinterion} dell: ${enable_plugin_dell} dlink: ${enable_plugin_dlink} fibocom: ${enable_plugin_fibocom} foxconn: ${enable_plugin_foxconn} + gosuncn: ${enable_plugin_gosuncn} haier: ${enable_plugin_haier} huawei: ${enable_plugin_huawei} iridium: ${enable_plugin_iridium} @@ -613,6 +632,7 @@ echo " option: ${enable_plugin_option} option hso: ${enable_plugin_option_hso} pantech: ${enable_plugin_pantech} + qcom-soc: ${enable_plugin_qcom_soc} quectel: ${enable_plugin_quectel} samsung: ${enable_plugin_samsung} sierra legacy: ${enable_plugin_sierra_legacy} diff --git a/docs/man/mmcli.1 b/docs/man/mmcli.1 index 4a087925..3e86931c 100644 --- a/docs/man/mmcli.1 +++ b/docs/man/mmcli.1 @@ -229,9 +229,6 @@ Send an AT \fBCOMMAND\fR to the given modem. For example, \fBCOMMAND\fR could be 'AT+GMM' to probe for phone model information. This operation is only available when ModemManager is run in debug mode. .TP -.B \-\-list\-bearers -List packet data bearers that are available for the given modem. -.TP .B \-\-create\-bearer=['KEY1=VALUE1,KEY2=VALUE2,...'] Create a new packet data bearer for a given modem. The \fBKEY\fRs and some \fBVALUE\fRs are listed below: @@ -284,6 +281,12 @@ MMModemBand documentation. An example would be: 'egsm|dcs|pcs|g850' to select all the GSM frequency bands. .TP +.B \-\-set\-primary\-sim\-slot=[SLOT] +Request to switch the primary SIM slot. + +The given \fBSLOT\fR must be a valid slot number in the [1,N] range, where +N is the amount of SIM slots available in the system. +.TP .B \-\-inhibit Inhibit the specific modem from being used by ModemManager. This method is completely equivalent to \fB\-\-inhibit\-device\fR, with the only diff --git a/docs/reference/api/ModemManager-docs.xml b/docs/reference/api/ModemManager-docs.xml index 42dbf1f6..bbcab97a 100644 --- a/docs/reference/api/ModemManager-docs.xml +++ b/docs/reference/api/ModemManager-docs.xml @@ -15,6 +15,8 @@ For ModemManager version &version; + The latest version of this documentation can be found on-line at + https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/. @@ -52,6 +54,7 @@ 2018 2019 2020 + 2021 The ModemManager Authors @@ -139,4 +142,8 @@ Index of new symbols in 1.12 + + Index of new symbols in 1.16 + + diff --git a/docs/reference/api/ModemManager-overview.xml b/docs/reference/api/ModemManager-overview.xml index 80c18050..1094950b 100644 --- a/docs/reference/api/ModemManager-overview.xml +++ b/docs/reference/api/ModemManager-overview.xml @@ -159,10 +159,10 @@ $ sudo udevadm trigger - MM_FILTER_RULE_CDC_WDM + MM_FILTER_RULE_USBMISC - This filter will automatically flag as allowed all cdc-wdm ports exposed by - devices. Unless there is a will to explicitly forbid the cdc-wdm ports exposed + This filter will automatically flag as allowed all cdc-wdm ports exposed in the + usbmisc subsystem. Unless there is a will to explicitly forbid the cdc-wdm ports exposed by qmi_wwan, cdc_mbim or huawei-cdc-ncm kernel drivers, this filter should always be enabled. @@ -254,7 +254,7 @@ $ sudo udevadm trigger MM_FILTER_RULE_EXPLICIT_BLACKLIST MM_FILTER_RULE_VIRTUAL MM_FILTER_RULE_NET - MM_FILTER_RULE_CDC_WDM + MM_FILTER_RULE_USBMISC MM_FILTER_RULE_TTY MM_FILTER_RULE_TTY_BLACKLIST MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY @@ -280,7 +280,7 @@ $ sudo udevadm trigger MM_FILTER_RULE_EXPLICIT_BLACKLIST MM_FILTER_RULE_VIRTUAL MM_FILTER_RULE_NET - MM_FILTER_RULE_CDC_WDM + MM_FILTER_RULE_USBMISC MM_FILTER_RULE_TTY MM_FILTER_RULE_TTY_PLATFORM_DRIVER MM_FILTER_RULE_TTY_DRIVER @@ -307,7 +307,7 @@ $ sudo udevadm trigger MM_FILTER_RULE_EXPLICIT_BLACKLIST MM_FILTER_RULE_VIRTUAL MM_FILTER_RULE_NET - MM_FILTER_RULE_CDC_WDM + MM_FILTER_RULE_USBMISC MM_FILTER_RULE_TTY MM_FILTER_RULE_TTY_BLACKLIST MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY @@ -339,7 +339,7 @@ $ sudo udevadm trigger net and cdc-wdm ports forbidden completely: # MM_FILTER_RULE_NET=0 \ - MM_FILTER_RULE_CDC_WDM=0 \ + MM_FILTER_RULE_USBMISC=0 \ /usr/sbin/ModemManager --filter-policy=DEFAULT @@ -348,7 +348,7 @@ $ sudo udevadm trigger net ports (e.g. 'lo') are also being allowed. # MM_FILTER_RULE_NET=1 \ - MM_FILTER_RULE_CDC_WDM=1 \ + MM_FILTER_RULE_USBMISC=1 \ /usr/sbin/ModemManager --filter-policy=WHITELIST-ONLY diff --git a/docs/reference/api/ModemManager-sections.txt b/docs/reference/api/ModemManager-sections.txt index f1d6b270..478f4793 100644 --- a/docs/reference/api/ModemManager-sections.txt +++ b/docs/reference/api/ModemManager-sections.txt @@ -140,9 +140,11 @@ MM_MODEM_BAND_CDMA_BC17_US_FLO_2500 MM_MODEM_BAND_CDMA_BC18_US_PS_700 MM_MODEM_BAND_CDMA_BC19_US_LOWER_700 MM_MODEM_LOCATION_SOURCE_AGPS +MM_MODEM_CAPABILITY_LTE_ADVANCED MMModemBandDeprecated MMModemLocationSourceDeprecated +MMModemCapabilityDeprecated MM_DEPRECATED @@ -162,6 +164,8 @@ ID_MM_PORT_TYPE_AT_SECONDARY ID_MM_PORT_TYPE_GPS ID_MM_PORT_TYPE_QCDM ID_MM_PORT_TYPE_AUDIO +ID_MM_PORT_TYPE_QMI +ID_MM_PORT_TYPE_MBIM ID_MM_TTY_BAUDRATE ID_MM_TTY_FLOW_CONTROL diff --git a/docs/reference/libmm-glib/Makefile.am b/docs/reference/libmm-glib/Makefile.am index 3d636cd4..db8c12b5 100644 --- a/docs/reference/libmm-glib/Makefile.am +++ b/docs/reference/libmm-glib/Makefile.am @@ -86,6 +86,7 @@ CLEANFILES += \ $(DOC_MODULE).interfaces \ $(DOC_MODULE).prerequisites \ $(DOC_MODULE).signals \ + $(DOC_MODULE).actions \ *.stamp \ -rf xml html tmpl \ $(NULL) diff --git a/docs/reference/libmm-glib/libmm-glib-docs.xml b/docs/reference/libmm-glib/libmm-glib-docs.xml index 106651be..71e74405 100644 --- a/docs/reference/libmm-glib/libmm-glib-docs.xml +++ b/docs/reference/libmm-glib/libmm-glib-docs.xml @@ -15,6 +15,8 @@ For libmm-glib version &version; + The latest version of this documentation can be found on-line at + https://www.freedesktop.org/software/ModemManager/doc/latest/libmm-glib/. @@ -40,6 +42,7 @@ 2018 2019 2020 + 2021 The ModemManager Authors @@ -287,6 +290,14 @@ Index of new symbols in 1.12 + + Index of new symbols in 1.14 + + + + Index of new symbols in 1.16 + + diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 64bd2e02..0a72befa 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -182,6 +182,15 @@ mm_modem_dup_sim_path mm_modem_get_sim mm_modem_get_sim_finish mm_modem_get_sim_sync +mm_modem_get_sim_slot_paths +mm_modem_dup_sim_slot_paths +mm_modem_get_primary_sim_slot +mm_modem_list_sim_slots +mm_modem_list_sim_slots_finish +mm_modem_list_sim_slots_sync +mm_modem_set_primary_sim_slot +mm_modem_set_primary_sim_slot_finish +mm_modem_set_primary_sim_slot_sync mm_modem_enable mm_modem_enable_finish @@ -861,6 +870,8 @@ mm_simple_connect_properties_get_ip_type mm_simple_connect_properties_set_ip_type mm_simple_connect_properties_get_allow_roaming mm_simple_connect_properties_set_allow_roaming +mm_simple_connect_properties_get_rm_protocol +mm_simple_connect_properties_set_rm_protocol mm_simple_connect_properties_get_number mm_simple_connect_properties_set_number @@ -943,6 +954,8 @@ mm_modem_signal_peek_umts mm_modem_signal_get_umts mm_modem_signal_peek_lte mm_modem_signal_get_lte +mm_modem_signal_peek_nr5g +mm_modem_signal_get_nr5g mm_modem_signal_setup mm_modem_signal_setup_finish @@ -1128,6 +1141,11 @@ MMBearerStats mm_bearer_stats_get_duration mm_bearer_stats_get_rx_bytes mm_bearer_stats_get_tx_bytes +mm_bearer_stats_get_attempts +mm_bearer_stats_get_failed_attempts +mm_bearer_stats_get_total_duration +mm_bearer_stats_get_total_rx_bytes +mm_bearer_stats_get_total_tx_bytes mm_bearer_stats_get_dictionary mm_bearer_stats_new @@ -1135,6 +1153,11 @@ mm_bearer_stats_new_from_dictionary mm_bearer_stats_set_duration mm_bearer_stats_set_rx_bytes mm_bearer_stats_set_tx_bytes +mm_bearer_stats_set_attempts +mm_bearer_stats_set_failed_attempts +mm_bearer_stats_set_total_duration +mm_bearer_stats_set_total_rx_bytes +mm_bearer_stats_set_total_tx_bytes MMBearerStatsClass MMBearerStatsPrivate @@ -1173,6 +1196,7 @@ mm_bearer_properties_set_rm_protocol mm_bearer_properties_new_from_dictionary mm_bearer_properties_new_from_string +MMBearerPropertiesCmpFlags mm_bearer_properties_cmp mm_bearer_properties_consume_string mm_bearer_properties_consume_variant @@ -1197,10 +1221,13 @@ MMSim mm_sim_get_path mm_sim_dup_path +mm_sim_get_active mm_sim_get_identifier mm_sim_dup_identifier mm_sim_get_imsi mm_sim_dup_imsi +mm_sim_get_eid +mm_sim_dup_eid mm_sim_get_operator_identifier mm_sim_dup_operator_identifier mm_sim_get_operator_name @@ -2070,6 +2097,9 @@ mm_gdbus_modem_get_signal_quality mm_gdbus_modem_dup_signal_quality mm_gdbus_modem_get_sim mm_gdbus_modem_dup_sim +mm_gdbus_modem_dup_sim_slots +mm_gdbus_modem_get_sim_slots +mm_gdbus_modem_get_primary_sim_slot mm_gdbus_modem_get_supported_capabilities mm_gdbus_modem_dup_supported_capabilities mm_gdbus_modem_get_state @@ -2113,6 +2143,9 @@ mm_gdbus_modem_call_set_current_bands_sync mm_gdbus_modem_call_set_current_capabilities mm_gdbus_modem_call_set_current_capabilities_finish mm_gdbus_modem_call_set_current_capabilities_sync +mm_gdbus_modem_call_set_primary_sim_slot +mm_gdbus_modem_call_set_primary_sim_slot_finish +mm_gdbus_modem_call_set_primary_sim_slot_sync mm_gdbus_modem_call_command mm_gdbus_modem_call_command_finish mm_gdbus_modem_call_command_sync @@ -2140,6 +2173,8 @@ mm_gdbus_modem_set_carrier_configuration_revision mm_gdbus_modem_set_hardware_revision mm_gdbus_modem_set_signal_quality mm_gdbus_modem_set_sim +mm_gdbus_modem_set_sim_slots +mm_gdbus_modem_set_primary_sim_slot mm_gdbus_modem_set_supported_capabilities mm_gdbus_modem_set_state mm_gdbus_modem_set_state_failed_reason @@ -2161,6 +2196,7 @@ mm_gdbus_modem_complete_reset mm_gdbus_modem_complete_set_current_modes mm_gdbus_modem_complete_set_current_bands mm_gdbus_modem_complete_set_current_capabilities +mm_gdbus_modem_complete_set_primary_sim_slot mm_gdbus_modem_interface_info mm_gdbus_modem_override_properties @@ -2783,11 +2819,13 @@ mm_gdbus_modem_signal_get_evdo mm_gdbus_modem_signal_get_gsm mm_gdbus_modem_signal_get_umts mm_gdbus_modem_signal_get_lte +mm_gdbus_modem_signal_get_nr5g mm_gdbus_modem_signal_dup_cdma mm_gdbus_modem_signal_dup_evdo mm_gdbus_modem_signal_dup_gsm mm_gdbus_modem_signal_dup_umts mm_gdbus_modem_signal_dup_lte +mm_gdbus_modem_signal_dup_nr5g mm_gdbus_modem_signal_call_setup mm_gdbus_modem_signal_call_setup_finish @@ -2797,6 +2835,7 @@ mm_gdbus_modem_signal_set_cdma mm_gdbus_modem_signal_set_evdo mm_gdbus_modem_signal_set_gsm mm_gdbus_modem_signal_set_lte +mm_gdbus_modem_signal_set_nr5g mm_gdbus_modem_signal_set_rate mm_gdbus_modem_signal_set_umts mm_gdbus_modem_signal_complete_setup @@ -3073,8 +3112,11 @@ mm_gdbus_object_manager_client_get_type MmGdbusSim MmGdbusSimIface +mm_gdbus_sim_get_active mm_gdbus_sim_get_imsi mm_gdbus_sim_dup_imsi +mm_gdbus_sim_get_eid +mm_gdbus_sim_dup_eid mm_gdbus_sim_get_sim_identifier mm_gdbus_sim_dup_sim_identifier mm_gdbus_sim_get_operator_identifier @@ -3097,7 +3139,9 @@ mm_gdbus_sim_call_change_pin mm_gdbus_sim_call_change_pin_finish mm_gdbus_sim_call_change_pin_sync +mm_gdbus_sim_set_active mm_gdbus_sim_set_imsi +mm_gdbus_sim_set_eid mm_gdbus_sim_set_operator_identifier mm_gdbus_sim_set_operator_name mm_gdbus_sim_set_sim_identifier diff --git a/examples/modem-watcher-python/ModemWatcher.py b/examples/modem-watcher-python/ModemWatcher.py index a18725b1..7ee8939b 100644 --- a/examples/modem-watcher-python/ModemWatcher.py +++ b/examples/modem-watcher-python/ModemWatcher.py @@ -18,27 +18,25 @@ # Copyright (C) 2014 Aleksander Morgado # -import os, sys, gi - +import gi gi.require_version('ModemManager', '1.0') -from gi.repository import GLib, GObject, Gio, ModemManager +from gi.repository import Gio, GLib, GObject, ModemManager -""" -The ModemWatcher class is responsible for monitoring ModemManager -""" -class ModemWatcher: +class ModemWatcher: """ - Constructor + The ModemWatcher class is responsible for monitoring ModemManager. """ + def __init__(self): # Flag for initial logs self.initializing = True # Setup DBus monitoring - self.connection = Gio.bus_get_sync (Gio.BusType.SYSTEM, None) - self.manager = ModemManager.Manager.new_sync (self.connection, - Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, - None) + self.connection = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) + self.manager = ModemManager.Manager.new_sync( + self.connection, + Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, + None) # IDs for added/removed signals self.object_added_id = 0 self.object_removed_id = 0 @@ -49,25 +47,25 @@ def __init__(self): # Finish initialization self.initializing = False - """ - ModemManager is now available - """ def set_available(self): - if self.available == False or self.initializing == True: + """ + ModemManager is now available. + """ + if not self.available or self.initializing: print('[ModemWatcher] ModemManager %s service is available in bus' % self.manager.get_version()) self.object_added_id = self.manager.connect('object-added', self.on_object_added) self.object_removed_id = self.manager.connect('object-removed', self.on_object_removed) self.available = True # Initial scan - if self.initializing == True: + if self.initializing: for obj in self.manager.get_objects(): self.on_object_added(self.manager, obj) - """ - ModemManager is now unavailable - """ def set_unavailable(self): - if self.available == True or self.initializing == True: + """ + ModemManager is now unavailable. + """ + if self.available or self.initializing: print('[ModemWatcher] ModemManager service not available in bus') if self.object_added_id: self.manager.disconnect(self.object_added_id) @@ -77,19 +75,19 @@ def set_unavailable(self): self.object_removed_id = 0 self.available = False - """ - Name owner updates - """ def on_name_owner(self, manager, prop): + """ + Name owner updates. + """ if self.manager.get_name_owner(): self.set_available() else: self.set_unavailable() - """ - Object added - """ def on_object_added(self, manager, obj): + """ + Object added. + """ modem = obj.get_modem() print('[ModemWatcher] %s (%s) modem managed by ModemManager [%s]: %s' % (modem.get_manufacturer(), @@ -97,12 +95,12 @@ def on_object_added(self, manager, obj): modem.get_equipment_identifier(), obj.get_object_path())) if modem.get_state() == ModemManager.ModemState.FAILED: - print('[ModemWatcher,%s] ignoring failed modem' % - modem_index(obj.get_object_path())) + print('[ModemWatcher] ignoring failed modem: %s' % + obj.get_object_path()) - """ - Object removed - """ def on_object_removed(self, manager, obj): + """ + Object removed. + """ print('[ModemWatcher] modem unmanaged by ModemManager: %s' % obj.get_object_path()) diff --git a/examples/modem-watcher-python/modem-watcher-python b/examples/modem-watcher-python/modem-watcher-python index 40998588..f7dd1fc6 100755 --- a/examples/modem-watcher-python/modem-watcher-python +++ b/examples/modem-watcher-python/modem-watcher-python @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # # This program is free software; you can redistribute it and/or modify it under @@ -18,25 +18,34 @@ # Copyright (C) 2014 Aleksander Morgado # -import sys, signal -import ModemWatcher +import signal + from gi.repository import GLib -main_loop = None -watcher = None +import ModemWatcher -def signal_handler(data): - main_loop.quit() -if __name__ == "__main__": +def signal_handler(loop): + """SIGHUP and SIGINT handler.""" + loop.quit() + + +def main(): + """Main routine.""" # Create modem watcher - watcher = ModemWatcher.ModemWatcher() + ModemWatcher.ModemWatcher() # Main loop main_loop = GLib.MainLoop() - GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, signal_handler, None) - GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, signal_handler, None) + GLib.unix_signal_add( + GLib.PRIORITY_HIGH, signal.SIGHUP, signal_handler, main_loop) + GLib.unix_signal_add( + GLib.PRIORITY_HIGH, signal.SIGTERM, signal_handler, main_loop) try: main_loop.run() except KeyboardInterrupt: pass + + +if __name__ == "__main__": + main() diff --git a/examples/network-scan-python/network-scan-python b/examples/network-scan-python/network-scan-python index ad377091..12ee02f7 100755 --- a/examples/network-scan-python/network-scan-python +++ b/examples/network-scan-python/network-scan-python @@ -18,10 +18,13 @@ # Copyright (C) 2019 Aleksander Morgado # -import sys, signal, gi +import sys +import time +import gi gi.require_version('ModemManager', '1.0') -from gi.repository import GLib, GObject, Gio, ModemManager +from gi.repository import Gio, GLib, GObject, ModemManager + if __name__ == "__main__": @@ -32,25 +35,35 @@ if __name__ == "__main__": sys.exit(1) # Connection to ModemManager - connection = Gio.bus_get_sync (Gio.BusType.SYSTEM, None) - manager = ModemManager.Manager.new_sync (connection, Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, None) - if manager.get_name_owner() is None: - sys.stderr.write('ModemManager not found in bus') + connection = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) + manager = ModemManager.Manager.new_sync( + connection, Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, None) + if not manager.get_name_owner(): + sys.stderr.write('ModemManager not found in bus\n') sys.exit(2) # Iterate modems and scan network with each one by one for obj in manager.get_objects(): + modem = obj.get_modem() + modem.enable() + time.sleep(1) modem3gpp = obj.get_modem_3gpp() + if not modem3gpp: + sys.stderr.write('%s: skipping unusable modem...\n' % + obj.get_object_path()) + continue modem3gpp.set_default_timeout(300000) print('%s: starting network scan...' % modem3gpp.get_object_path()) networks = modem3gpp.scan_sync() if networks: for network in networks: print('%s: %s - %s (%s, %s)' % ( - network.get_operator_code(), - network.get_operator_short(), - network.get_operator_short(), - ModemManager.modem_access_technology_build_string_from_mask (network.get_access_technology()), - ModemManager.Modem3gppNetworkAvailability.get_string(network.get_availability()))) + network.get_operator_code(), + network.get_operator_short(), + network.get_operator_short(), + ModemManager.modem_access_technology_build_string_from_mask( + network.get_access_technology()), + ModemManager.Modem3gppNetworkAvailability.get_string( + network.get_availability()))) else: print('no networks found') diff --git a/examples/sms-python/sms-python b/examples/sms-python/sms-python index 2d572f18..569db376 100755 --- a/examples/sms-python/sms-python +++ b/examples/sms-python/sms-python @@ -18,10 +18,12 @@ # Copyright (C) 2016 Aleksander Morgado # -import sys, signal, gi +import sys +import gi gi.require_version('ModemManager', '1.0') -from gi.repository import GLib, GObject, Gio, ModemManager +from gi.repository import Gio, GLib, GObject, ModemManager + if __name__ == "__main__": diff --git a/gtk-doc.make b/gtk-doc.make index e4a12a5b..913aa4f7 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -1,4 +1,22 @@ # -*- mode: makefile -*- +# +# gtk-doc.make - make rules for gtk-doc +# Copyright (C) 2003 James Henstridge +# 2004-2007 Damon Chaplin +# 2007-2017 Stefan Sauer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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, see . #################################### # Everything below here is generic # @@ -81,55 +99,54 @@ $(REPORT_FILES): sgml-build.stamp #### setup #### -GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_$(V)) -GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_@AM_V@) +GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_@AM_DEFAULT_V@) GTK_DOC_V_SETUP_0=@echo " DOC Preparing build"; setup-build.stamp: -$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ - files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \ - if test "x$$files" != "x" ; then \ - for file in $$files ; do \ - destdir=`dirname $(abs_builddir)/$$file`; \ - test -d "$$destdir" || mkdir -p "$$destdir"; \ - test -f $(abs_srcdir)/$$file && \ - cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \ - done; \ - fi; \ + files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \ + if test "x$$files" != "x" ; then \ + for file in $$files ; do \ + destdir=`dirname $(abs_builddir)/$$file`; \ + test -d "$$destdir" || mkdir -p "$$destdir"; \ + test -f $(abs_srcdir)/$$file && \ + cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \ + done; \ + fi; \ fi $(AM_V_at)touch setup-build.stamp - #### scan #### -GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_$(V)) -GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_@AM_V@) +GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_@AM_DEFAULT_V@) GTK_DOC_V_SCAN_0=@echo " DOC Scanning header files"; -GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_$(V)) -GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_@AM_V@) +GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_@AM_DEFAULT_V@) GTK_DOC_V_INTROSPECT_0=@echo " DOC Introspecting gobjects"; scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB) $(GTK_DOC_V_SCAN)_source_dir='' ; \ for i in $(DOC_SOURCE_DIR) ; do \ - _source_dir="$${_source_dir} --source-dir=$$i" ; \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ done ; \ gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES) $(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \ - scanobj_options=""; \ - gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ - if test "$$?" = "0"; then \ - if test "x$(V)" = "x1"; then \ - scanobj_options="--verbose"; \ - fi; \ + scanobj_options=""; \ + gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + scanobj_options="--verbose"; \ fi; \ - CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ - gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ + fi; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ + gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ else \ - for i in $(SCANOBJ_FILES) ; do \ - test -f $$i || touch $$i ; \ - done \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ fi $(AM_V_at)touch scan-build.stamp @@ -138,14 +155,14 @@ $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE) #### xml #### -GTK_DOC_V_XML=$(GTK_DOC_V_XML_$(V)) -GTK_DOC_V_XML_=$(GTK_DOC_V_XML_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_XML=$(GTK_DOC_V_XML_@AM_V@) +GTK_DOC_V_XML_=$(GTK_DOC_V_XML_@AM_DEFAULT_V@) GTK_DOC_V_XML_0=@echo " DOC Building XML"; sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) xml/gtkdocentities.ent $(GTK_DOC_V_XML)_source_dir='' ; \ for i in $(DOC_SOURCE_DIR) ; do \ - _source_dir="$${_source_dir} --source-dir=$$i" ; \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ done ; \ gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) $(AM_V_at)touch sgml-build.stamp @@ -153,6 +170,9 @@ sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(HF sgml.stamp: sgml-build.stamp @true +$(DOC_MAIN_SGML_FILE): sgml-build.stamp + @true + xml/gtkdocentities.ent: Makefile $(GTK_DOC_V_XML)$(MKDIR_P) $(@D) && ( \ echo ""; \ @@ -166,12 +186,12 @@ xml/gtkdocentities.ent: Makefile #### html #### -GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_$(V)) -GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_@AM_V@) +GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_@AM_DEFAULT_V@) GTK_DOC_V_HTML_0=@echo " DOC Building HTML"; -GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_$(V)) -GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_@AM_V@) +GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_@AM_DEFAULT_V@) GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references"; html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) @@ -190,20 +210,17 @@ html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_con cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) -@test "x$(HTML_IMAGES)" = "x" || \ for file in $(HTML_IMAGES) ; do \ - if test -f $(abs_srcdir)/$$file ; then \ - cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ - fi; \ - if test -f $(abs_builddir)/$$file ; then \ - cp $(abs_builddir)/$$file $(abs_builddir)/html; \ - fi; \ + test -f $(abs_srcdir)/$$file && cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ + test -f $(abs_builddir)/$$file && cp $(abs_builddir)/$$file $(abs_builddir)/html; \ + test -f $$file && cp $$file $(abs_builddir)/html; \ done; $(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) $(AM_V_at)touch html-build.stamp #### pdf #### -GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_$(V)) -GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_$(AM_DEFAULT_VERBOSITY)) +GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_@AM_V@) +GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_@AM_DEFAULT_V@) GTK_DOC_V_PDF_0=@echo " DOC Building PDF"; pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) @@ -268,7 +285,6 @@ install-data-local: mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ fi; \ - $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \ fi uninstall-local: diff --git a/include/Makefile.am b/include/Makefile.am index c0f3117c..cd44da5f 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -15,7 +15,7 @@ include_HEADERS = \ ModemManager-names.h: $(XMLS) $(top_srcdir)/build-aux/header-generator.xsl $(AM_V_GEN) $(XSLTPROC) $(top_srcdir)/build-aux/header-generator.xsl $(top_srcdir)/introspection/all.xml > $@ -CLEANFILES = \ +MAINTAINERCLEANFILES = \ ModemManager-names.h EXTRA_DIST = \ diff --git a/include/ModemManager-compat.h b/include/ModemManager-compat.h index e1458400..5aaaddf9 100644 --- a/include/ModemManager-compat.h +++ b/include/ModemManager-compat.h @@ -709,6 +709,23 @@ typedef int MMModemLocationSourceDeprecated; */ #define MM_MODEM_LOCATION_SOURCE_AGPS ((MMModemLocationSourceDeprecated)MM_MODEM_LOCATION_SOURCE_AGPS_MSA) +/* The following type exists just so that we can get deprecation warnings */ +MM_DEPRECATED +typedef int MMModemCapabilityDeprecated; + +/** + * MM_MODEM_CAPABILITY_LTE_ADVANCED: + * + * Modem has LTE Advanced data capability. + * + * This value is deprecated because it is not used anywhere. LTE Advanced + * capable devices are reported as LTE capable. + * + * Since: 1.0 + * Deprecated: 1.14.0. + */ +#define MM_MODEM_CAPABILITY_LTE_ADVANCED ((MMModemCapabilityDeprecated)(1 << 4)) + #endif /* MM_DISABLE_DEPRECATED */ #endif /* _MODEMMANAGER_COMPAT_H_ */ diff --git a/include/ModemManager-enums.h b/include/ModemManager-enums.h index bf068bdc..7f1be95a 100644 --- a/include/ModemManager-enums.h +++ b/include/ModemManager-enums.h @@ -36,8 +36,8 @@ * @MM_MODEM_CAPABILITY_CDMA_EVDO: Modem supports at least one of CDMA 1xRTT, EVDO revision 0, EVDO revision A, or EVDO revision B. * @MM_MODEM_CAPABILITY_GSM_UMTS: Modem supports at least one of GSM, GPRS, EDGE, UMTS, HSDPA, HSUPA, or HSPA+ packet switched data capability. * @MM_MODEM_CAPABILITY_LTE: Modem has LTE data capability. - * @MM_MODEM_CAPABILITY_LTE_ADVANCED: Modem has LTE Advanced data capability. * @MM_MODEM_CAPABILITY_IRIDIUM: Modem has Iridium capabilities. + * @MM_MODEM_CAPABILITY_5GNR: Modem has 5GNR capabilities. Since 1.14. * @MM_MODEM_CAPABILITY_ANY: Mask specifying all capabilities. * * Flags describing one or more of the general access technology families that a @@ -51,8 +51,9 @@ typedef enum { /*< underscore_name=mm_modem_capability >*/ MM_MODEM_CAPABILITY_CDMA_EVDO = 1 << 1, MM_MODEM_CAPABILITY_GSM_UMTS = 1 << 2, MM_MODEM_CAPABILITY_LTE = 1 << 3, - MM_MODEM_CAPABILITY_LTE_ADVANCED = 1 << 4, + /* MM_MODEM_CAPABILITY_LTE_ADVANCED deprecated */ MM_MODEM_CAPABILITY_IRIDIUM = 1 << 5, + MM_MODEM_CAPABILITY_5GNR = 1 << 6, MM_MODEM_CAPABILITY_ANY = 0xFFFFFFFF } MMModemCapability; @@ -208,6 +209,7 @@ typedef enum { /*< underscore_name=mm_modem_state_change_reason >*/ * @MM_MODEM_ACCESS_TECHNOLOGY_EVDOA: CDMA2000 EVDO revision A. * @MM_MODEM_ACCESS_TECHNOLOGY_EVDOB: CDMA2000 EVDO revision B. * @MM_MODEM_ACCESS_TECHNOLOGY_LTE: LTE (ETSI 27.007: "E-UTRAN") + * @MM_MODEM_ACCESS_TECHNOLOGY_5GNR: 5GNR (ETSI 27.007: "NG-RAN"). Since 1.14. * @MM_MODEM_ACCESS_TECHNOLOGY_ANY: Mask specifying all access technologies. * * Describes various access technologies that a device uses when registered with @@ -232,6 +234,7 @@ typedef enum { /*< underscore_name=mm_modem_access_technology >*/ MM_MODEM_ACCESS_TECHNOLOGY_EVDOA = 1 << 12, MM_MODEM_ACCESS_TECHNOLOGY_EVDOB = 1 << 13, MM_MODEM_ACCESS_TECHNOLOGY_LTE = 1 << 14, + MM_MODEM_ACCESS_TECHNOLOGY_5GNR = 1 << 15, MM_MODEM_ACCESS_TECHNOLOGY_ANY = 0xFFFFFFFF, } MMModemAccessTechnology; @@ -242,6 +245,7 @@ typedef enum { /*< underscore_name=mm_modem_access_technology >*/ * @MM_MODEM_MODE_2G: GPRS, EDGE. * @MM_MODEM_MODE_3G: UMTS, HSxPA. * @MM_MODEM_MODE_4G: LTE. + * @MM_MODEM_MODE_5G: 5GNR. Since 1.14. * @MM_MODEM_MODE_ANY: Any mode can be used (only this value allowed for POTS modems). * * Bitfield to indicate which access modes are supported, allowed or @@ -255,6 +259,7 @@ typedef enum { /*< underscore_name=mm_modem_mode >*/ MM_MODEM_MODE_2G = 1 << 1, MM_MODEM_MODE_3G = 1 << 2, MM_MODEM_MODE_4G = 1 << 3, + MM_MODEM_MODE_5G = 1 << 4, MM_MODEM_MODE_ANY = 0xFFFFFFFF } MMModemMode; @@ -533,6 +538,7 @@ typedef enum { /*< underscore_name=mm_modem_band >*/ * @MM_MODEM_PORT_TYPE_QMI: QMI port. * @MM_MODEM_PORT_TYPE_MBIM: MBIM port. * @MM_MODEM_PORT_TYPE_AUDIO: Audio port. Since 1.12. + * @MM_MODEM_PORT_TYPE_IGNORED: Ignored port. Since 1.16. * * Type of modem port. * @@ -547,6 +553,7 @@ typedef enum { /*< underscore_name=mm_modem_port_type >*/ MM_MODEM_PORT_TYPE_QMI = 6, MM_MODEM_PORT_TYPE_MBIM = 7, MM_MODEM_PORT_TYPE_AUDIO = 8, + MM_MODEM_PORT_TYPE_IGNORED = 9, } MMModemPortType; /** @@ -1188,6 +1195,7 @@ typedef enum { /*< underscore_name=mm_modem_cdma_rm_protocol >*/ * @MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY: Emergency services only. Since 1.8. * @MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED: Registered for "CSFB not preferred", home network (applicable only when on LTE). Since 1.8. * @MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED: Registered for "CSFB not preferred", roaming network (applicable only when on LTE). Since 1.8. + * @MM_MODEM_3GPP_REGISTRATION_STATE_ATTACHED_RLOS: Attached for access to Restricted Local Operator Services (applicable only when on LTE). Since 1.14. * * GSM registration code as defined in 3GPP TS 27.007. * @@ -1205,6 +1213,7 @@ typedef enum { /*< underscore_name=mm_modem_3gpp_registration_state >*/ MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY = 8, MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED = 9, MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED = 10, + MM_MODEM_3GPP_REGISTRATION_STATE_ATTACHED_RLOS = 11, } MMModem3gppRegistrationState; /** diff --git a/include/ModemManager-tags.h b/include/ModemManager-tags.h index 633060b7..2566cebb 100644 --- a/include/ModemManager-tags.h +++ b/include/ModemManager-tags.h @@ -213,6 +213,36 @@ */ #define ID_MM_PORT_TYPE_AUDIO "ID_MM_PORT_TYPE_AUDIO" +/** + * ID_MM_PORT_TYPE_QMI: + * + * This is a port-specific tag applied to generic ports that we know in advance + * are QMI ports. + * + * This tag will also prevent other types of probing (e.g. AT, MBIM) on the + * port. + * + * This tag is not required for QMI ports exposed by the qmi_wwan driver. + * + * Since: 1.16 + */ +#define ID_MM_PORT_TYPE_QMI "ID_MM_PORT_TYPE_QMI" + +/** + * ID_MM_PORT_TYPE_MBIM: + * + * This is a port-specific tag applied to generic ports that we know in advance + * are MBIM ports. + * + * This tag will also prevent other types of probing (e.g. AT, QMI) on the + * port. + * + * This tag is not required for MBIM ports exposed by the cdc_mbim driver. + * + * Since: 1.16 + */ +#define ID_MM_PORT_TYPE_MBIM "ID_MM_PORT_TYPE_MBIM" + /** * ID_MM_TTY_BAUDRATE: * diff --git a/introspection/org.freedesktop.ModemManager1.Bearer.xml b/introspection/org.freedesktop.ModemManager1.Bearer.xml index e86ef00d..fb008797 100644 --- a/introspection/org.freedesktop.ModemManager1.Bearer.xml +++ b/introspection/org.freedesktop.ModemManager1.Bearer.xml @@ -120,7 +120,7 @@ If the bearer specifies configuration via PPP or DHCP, only the - "method" item will be present. + "method" item is guaranteed to be present. Additional items which are only applicable when using the MM_BEARER_IP_METHOD_STATIC @@ -244,28 +244,71 @@ @@ -168,9 +182,16 @@ gathering is enabled. If the modem supports multiple location types it may return more than one here. - Note that if the device was told not to emit updated location - information when location information gathering was initially enabled, - this property may not return any location information for security reasons. + For security reasons, the location information updates via this + property are disabled by default. Users can use this property to monitor + location updates only if the location signals are enabled with + Setup(), + but considering that enabling the location signals would allow all users + to receive property updates as well, not just the process that enabled them. + For a finer grained access control, the user can use the + GetLocation() + method instead, which may require the client to authenticate itself on every + call. This dictionary is composed of a MMModemLocationSource diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml b/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml index b9e9b19d..e741ae91 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml @@ -200,7 +200,25 @@ @@ -219,8 +237,9 @@ The network may decide to use different settings during the actual device attach procedure, e.g. if the device is roaming or no explicit settings were requested, - so the properties shown in the #org.freedesktop.ModemManager1.Modem.Modem3gpp.InitialEpsBearer:InitialEpsBearer - may be totally different. + so the values shown in the + #org.freedesktop.ModemManager1.Modem.Modem3gpp:InitialEpsBearer + bearer object may be totally different. This is a read-only property, updating these settings should be done using the SetInitialEpsBearerSettings() diff --git a/introspection/org.freedesktop.ModemManager1.Modem.ModemCdma.xml b/introspection/org.freedesktop.ModemManager1.Modem.ModemCdma.xml index 6000f41a..5c27f3f9 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.ModemCdma.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.ModemCdma.xml @@ -112,7 +112,7 @@ ActivationStateChanged: @activation_state: Current activation state, given as a MMModemCdmaActivationState. @activation_error: Carrier-specific error code, given as a MMCdmaActivationError. - @status_changes: Properties that have changed as a result of this activation state chage, including "mdn" and "min". The dictionary may be empty if the changed properties are unknown. + @status_changes: Properties that have changed as a result of this activation state change, including "mdn" and "min". The dictionary may be empty if the changed properties are unknown. The device activation state changed. --> diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Signal.xml b/introspection/org.freedesktop.ModemManager1.Modem.Signal.xml index 38c79578..610c6db9 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.Signal.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.Signal.xml @@ -221,5 +221,43 @@ --> + + + diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Simple.xml b/introspection/org.freedesktop.ModemManager1.Modem.Simple.xml index 91501c5a..082e63d8 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.Simple.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.Simple.xml @@ -91,8 +91,9 @@ "number" - For POTS devices the number to dial,, + Number to dial for the data connection, given as a string value (signature "s"). + Deprecated since version 1.10.0. "allow-roaming" @@ -156,7 +157,7 @@ unsigned integer values (signature "au"). - "access-technology" + "access-technologies" A MMModemAccessTechnology value, given only when registered, as an unsigned integer value diff --git a/introspection/org.freedesktop.ModemManager1.Modem.xml b/introspection/org.freedesktop.ModemManager1.Modem.xml index eb4debd8..529b26bd 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.xml @@ -55,7 +55,7 @@ @@ -178,15 +183,34 @@ + + + + + @@ -211,10 +235,55 @@ + + + + + + @@ -243,8 +316,11 @@ CurrentCapabilities: Bitmask of MMModemCapability - values, specifying the generic family of access technologies the modem - currently supports without a firmware reload or reinitialization. + values, specifying the currently used generic family of access + technologies. + + This bitmask will be one of the ones listed in + #org.freedesktop.ModemManager1.Modem:SupportedCapabilities. --> diff --git a/introspection/org.freedesktop.ModemManager1.Sim.xml b/introspection/org.freedesktop.ModemManager1.Sim.xml index ceba2629..87891e31 100644 --- a/introspection/org.freedesktop.ModemManager1.Sim.xml +++ b/introspection/org.freedesktop.ModemManager1.Sim.xml @@ -65,6 +65,19 @@ + + + + + + - + %u%%", rssi, quality); + mm_obj_dbg (self, "signal state indication: %u --> %u%%", rssi, quality); mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); } } @@ -2943,6 +2884,7 @@ update_registration_info (MMBroadbandModemMbim *self, gchar *operator_name_take) { MMModem3gppRegistrationState reg_state; + gboolean operator_updated = FALSE; reg_state = mm_modem_3gpp_registration_state_from_mbim_register_state (state); @@ -2952,6 +2894,7 @@ update_registration_info (MMBroadbandModemMbim *self, g_str_equal (self->priv->current_operator_id, operator_id_take)) { g_free (operator_id_take); } else { + operator_updated = TRUE; g_free (self->priv->current_operator_id); self->priv->current_operator_id = operator_id_take; } @@ -2960,10 +2903,13 @@ update_registration_info (MMBroadbandModemMbim *self, g_str_equal (self->priv->current_operator_name, operator_name_take)) { g_free (operator_name_take); } else { + operator_updated = TRUE; g_free (self->priv->current_operator_name); self->priv->current_operator_name = operator_name_take; } } else { + if (self->priv->current_operator_id || self->priv->current_operator_name) + operator_updated = TRUE; g_clear_pointer (&self->priv->current_operator_id, g_free); g_clear_pointer (&self->priv->current_operator_name, g_free); g_free (operator_id_take); @@ -2976,6 +2922,11 @@ update_registration_info (MMBroadbandModemMbim *self, self->priv->available_data_classes = available_data_classes; update_access_technologies (self); + + /* request to reload operator info explicitly, so that the new + * operator name and code is propagated to the DBus interface */ + if (operator_updated) + mm_iface_modem_3gpp_reload_current_registration_info (MM_IFACE_MODEM_3GPP (self), NULL, NULL); } static void @@ -3008,7 +2959,8 @@ basic_connect_notification_register_state (MMBroadbandModemMbim *self, } typedef struct { - guint32 session_id; + MMBroadbandModemMbim *self; + guint32 session_id; } ReportDisconnectedStatusContext; static void @@ -3019,7 +2971,7 @@ bearer_list_report_disconnected_status (MMBaseBearer *bearer, if (MM_IS_BEARER_MBIM (bearer) && mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (bearer)) == ctx->session_id) { - mm_dbg ("Bearer '%s' was disconnected.", mm_base_bearer_get_path (bearer)); + mm_obj_dbg (ctx->self, "bearer '%s' was disconnected.", mm_base_bearer_get_path (bearer)); mm_base_bearer_report_connection_status (bearer, MM_BEARER_CONNECTION_STATUS_DISCONNECTED); } } @@ -3056,7 +3008,8 @@ basic_connect_notification_connect (MMBroadbandModemMbim *self, activation_state == MBIM_ACTIVATION_STATE_DEACTIVATED) { ReportDisconnectedStatusContext ctx; - mm_dbg ("Session ID '%u' was deactivated.", session_id); + mm_obj_dbg (self, "session ID '%u' was deactivated.", session_id); + ctx.self = self; ctx.session_id = session_id; mm_bearer_list_foreach (bearer_list, (MMBearerListForeachFunc)bearer_list_report_disconnected_status, @@ -3093,8 +3046,8 @@ basic_connect_notification_subscriber_ready_status (MMBroadbandModemMbim *self, (self->priv->last_ready_state == MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED && ready_state != MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED)) { /* SIM has been removed or reinserted, re-probe to ensure correct interfaces are exposed */ - mm_dbg ("SIM hot swap detected"); - mm_broadband_modem_update_sim_hot_swap_detected (MM_BROADBAND_MODEM (self)); + mm_obj_dbg (self, "SIM hot swap detected"); + mm_broadband_modem_sim_hot_swap_detected (MM_BROADBAND_MODEM (self)); } self->priv->last_ready_state = ready_state; @@ -3121,8 +3074,8 @@ basic_connect_notification_packet_service (MMBroadbandModemMbim *self, } str = mbim_data_class_build_string_from_mask (highest_available_data_class); - mm_dbg ("Packet service state: '%s', data class: '%s'", - mbim_packet_service_state_get_string (packet_service_state), str); + mm_obj_dbg (self, "packet service state: '%s', data class: '%s'", + mbim_packet_service_state_get_string (packet_service_state), str); g_free (str); if (packet_service_state == MBIM_PACKET_SERVICE_STATE_ATTACHED) { @@ -3223,7 +3176,7 @@ alert_sms_read_query_ready (MbimDevice *device, } if (error) { - mm_dbg ("Flash message reading failed: %s", error->message); + mm_obj_dbg (self, "flash message reading failed: %s", error->message); g_error_free (error); } @@ -3241,14 +3194,14 @@ sms_notification_read_stored_sms (MMBroadbandModemMbim *self, MbimDevice *device; MbimMessage *message; - port = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self)); + port = mm_broadband_modem_mbim_peek_port_mbim (self); if (!port) return; device = mm_port_mbim_peek_device (port); if (!device) return; - mm_dbg ("Reading new SMS at index '%u'", index); + mm_obj_dbg (self, "reading new SMS at index '%u'", index); message = mbim_message_sms_read_query_new (MBIM_SMS_FORMAT_PDU, MBIM_SMS_FLAG_INDEX, index, @@ -3283,7 +3236,7 @@ sms_notification (MMBroadbandModemMbim *self, &flag, &index, NULL)) { - mm_dbg ("Received SMS store status update: '%s'", mbim_sms_status_flag_get_string (flag)); + mm_obj_dbg (self, "received SMS store status update: '%s'", mbim_sms_status_flag_get_string (flag)); if (flag == MBIM_SMS_STATUS_FLAG_NEW_MESSAGE) sms_notification_read_stored_sms (self, index); } @@ -3309,18 +3262,18 @@ ms_basic_connect_extensions_notification_pco (MMBroadbandModemMbim *self, notification, &pco_value, &error)) { - mm_warn ("Couldn't parse PCO notification: %s", error->message); + mm_obj_warn (self, "couldn't parse PCO notification: %s", error->message); g_error_free (error); return; } pco_data_hex = mm_utils_bin2hexstr (pco_value->pco_data_buffer, pco_value->pco_data_size); - mm_dbg ("Received PCO: session ID=%u type=%s size=%u data=%s", - pco_value->session_id, - mbim_pco_type_get_string (pco_value->pco_data_type), - pco_value->pco_data_size, - pco_data_hex); + mm_obj_dbg (self, "received PCO: session ID=%u type=%s size=%u data=%s", + pco_value->session_id, + mbim_pco_type_get_string (pco_value->pco_data_type), + pco_value->pco_data_size, + pco_data_hex); g_free (pco_data_hex); pco = mm_pco_new (); @@ -3350,7 +3303,7 @@ ms_basic_connect_extensions_notification_lte_attach_status (MMBroadbandModemMbim notification, &status, &error)) { - mm_warn ("Couldn't parse LTE attach status notification: %s", error->message); + mm_obj_warn (self, "couldn't parse LTE attach status notification: %s", error->message); g_error_free (error); return; } @@ -3390,7 +3343,7 @@ ussd_notification (MMBroadbandModemMbim *self, MbimMessage *notification) { if (mbim_message_indicate_status_get_cid (notification) != MBIM_CID_USSD) { - mm_warn ("unexpected USSD notification (cid %u)", mbim_message_indicate_status_get_cid (notification)); + mm_obj_warn (self, "unexpected USSD notification (cid %u)", mbim_message_indicate_status_get_cid (notification)); return; } @@ -3408,39 +3361,19 @@ device_notification_cb (MbimDevice *device, MbimService service; service = mbim_message_indicate_status_get_service (notification); - mm_dbg ("Received notification (service '%s', command '%s')", - mbim_service_get_string (service), - mbim_cid_get_printable (service, - mbim_message_indicate_status_get_cid (notification))); + mm_obj_dbg (self, "received notification (service '%s', command '%s')", + mbim_service_get_string (service), + mbim_cid_get_printable (service, + mbim_message_indicate_status_get_cid (notification))); - switch (service) { - case MBIM_SERVICE_BASIC_CONNECT: + if (service == MBIM_SERVICE_BASIC_CONNECT) basic_connect_notification (self, notification); - break; - case MBIM_SERVICE_MS_BASIC_CONNECT_EXTENSIONS: + else if (service == MBIM_SERVICE_MS_BASIC_CONNECT_EXTENSIONS) ms_basic_connect_extensions_notification (self, notification); - break; - case MBIM_SERVICE_SMS: + else if (service == MBIM_SERVICE_SMS) sms_notification (self, notification); - break; - case MBIM_SERVICE_USSD: + else if (service == MBIM_SERVICE_USSD) ussd_notification (self, notification); - break; - case MBIM_SERVICE_INVALID: - case MBIM_SERVICE_PHONEBOOK: - case MBIM_SERVICE_STK: - case MBIM_SERVICE_AUTH: - case MBIM_SERVICE_DSS: - case MBIM_SERVICE_MS_FIRMWARE_ID: - case MBIM_SERVICE_MS_HOST_SHUTDOWN: - case MBIM_SERVICE_PROXY_CONTROL: - case MBIM_SERVICE_QMI: - case MBIM_SERVICE_ATDS: - case MBIM_SERVICE_INTEL_FIRMWARE_UPDATE: - default: - /* Ignore */ - break; - } } static void @@ -3451,16 +3384,16 @@ common_setup_cleanup_unsolicited_events_sync (MMBroadbandModemMbim *self, if (!device) return; - mm_dbg ("Supported notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s), lte attach status (%s)", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no", - self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_LTE_ATTACH_STATUS ? "yes" : "no"); + mm_obj_dbg (self, "supported notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s), lte attach status (%s)", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no", + self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_LTE_ATTACH_STATUS ? "yes" : "no"); if (setup) { /* Don't re-enable it if already there */ @@ -3525,16 +3458,9 @@ cleanup_unsolicited_events_3gpp (MMIfaceModem3gpp *_self, gpointer user_data) { MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); - gboolean is_sim_hot_swap_configured = FALSE; - - g_object_get (self, - MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, &is_sim_hot_swap_configured, - NULL); self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY; self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_CONNECT; - if (is_sim_hot_swap_configured) - self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO; self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE; if (self->priv->is_pco_supported) self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_PCO; @@ -3632,16 +3558,16 @@ common_enable_disable_unsolicited_events (MMBroadbandModemMbim *self, if (!peek_device (self, &device, callback, user_data)) return; - mm_dbg ("Enabled notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s), lte attach status (%s)", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no", - self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_LTE_ATTACH_STATUS ? "yes" : "no"); + mm_obj_dbg (self, "enabled notifications: signal (%s), registration (%s), sms (%s), connect (%s), subscriber (%s), packet (%s), pco (%s), ussd (%s), lte attach status (%s)", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SIGNAL_QUALITY ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_REGISTRATION_UPDATES ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SMS_READ ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_CONNECT ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no", + self->priv->enable_flags & PROCESS_NOTIFICATION_FLAG_LTE_ATTACH_STATUS ? "yes" : "no"); entries = g_new0 (MbimEventEntry *, 5); @@ -3762,67 +3688,124 @@ modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *_self, /*****************************************************************************/ /* Setup SIM hot swap */ +typedef struct { + MbimDevice *device; + GError *subscriber_info_error; +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + GError *qmi_error; +#endif +} SetupSimHotSwapContext; + +static void +setup_sim_hot_swap_context_free (SetupSimHotSwapContext *ctx) +{ +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + g_clear_error (&ctx->qmi_error); +#endif + g_clear_error (&ctx->subscriber_info_error); + g_clear_object (&ctx->device); + g_slice_free (SetupSimHotSwapContext, ctx); +} + static gboolean -modem_setup_sim_hot_swap_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) +modem_setup_sim_hot_swap_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void -enable_subscriber_info_unsolicited_events_ready (MMBroadbandModemMbim *self, - GAsyncResult *res, - GTask *task) +sim_hot_swap_complete (GTask *task) { - GError *error = NULL; + SetupSimHotSwapContext *ctx; - if (!common_enable_disable_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Failed to enable subscriber info events: %s", error->message); - g_task_return_error (task, error); - g_object_unref (task); - return; - } + ctx = g_task_get_task_data (task); - g_task_return_boolean (task, TRUE); + /* If MBIM based logic worked, success */ + if (!ctx->subscriber_info_error) + g_task_return_boolean (task, TRUE); +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + /* Otherwise, If QMI-over-MBIM based logic worked, success */ + else if (!ctx->qmi_error) + g_task_return_boolean (task, TRUE); +#endif + /* Otherwise, prefer MBIM specific error */ + else + g_task_return_error (task, g_steal_pointer (&ctx->subscriber_info_error)); g_object_unref (task); } +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + static void -setup_subscriber_info_unsolicited_events_ready (MMBroadbandModemMbim *self, - GAsyncResult *res, - GTask *task) +qmi_setup_sim_hot_swap_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) { - GError *error = NULL; + SetupSimHotSwapContext *ctx; - if (!common_setup_cleanup_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Failed to set up subscriber info events: %s", error->message); - g_task_return_error (task, error); - g_object_unref (task); - return; + ctx = g_task_get_task_data (task); + if (!mm_shared_qmi_setup_sim_hot_swap_finish (self, res, &ctx->qmi_error)) + mm_obj_dbg (self, "couldn't setup SIM hot swap using QMI over MBIM: %s", ctx->qmi_error->message); + + sim_hot_swap_complete (task); +} + +#endif + +static void +enable_subscriber_info_unsolicited_events_ready (MMBroadbandModemMbim *self, + GAsyncResult *res, + GTask *task) +{ + SetupSimHotSwapContext *ctx; + + ctx = g_task_get_task_data (task); + + if (!common_enable_disable_unsolicited_events_finish (self, res, &ctx->subscriber_info_error)) { + mm_obj_dbg (self, "failed to enable subscriber info events: %s", ctx->subscriber_info_error->message); + /* reset setup flags if enabling failed */ + self->priv->setup_flags &= ~PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO; + common_setup_cleanup_unsolicited_events_sync (self, ctx->device, FALSE); } - self->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO; - common_enable_disable_unsolicited_events (self, - (GAsyncReadyCallback)enable_subscriber_info_unsolicited_events_ready, - task); +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + mm_shared_qmi_setup_sim_hot_swap (MM_IFACE_MODEM (self), + (GAsyncReadyCallback)qmi_setup_sim_hot_swap_ready, + task); +#else + sim_hot_swap_complete (task); +#endif } static void -modem_setup_sim_hot_swap (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) +modem_setup_sim_hot_swap (MMIfaceModem *_self, + GAsyncReadyCallback callback, + gpointer user_data) { - MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); - GTask *task; + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self); + MbimDevice *device; + GTask *task; + SetupSimHotSwapContext *ctx; + + if (!peek_device (self, &device, callback, user_data)) + return; task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (SetupSimHotSwapContext); + ctx->device = g_object_ref (device); + g_task_set_task_data (task, ctx, (GDestroyNotify)setup_sim_hot_swap_context_free); + /* Setup flags synchronously, which never fails */ self->priv->setup_flags |= PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO; - common_setup_cleanup_unsolicited_events (self, - TRUE, - (GAsyncReadyCallback)setup_subscriber_info_unsolicited_events_ready, - task); + common_setup_cleanup_unsolicited_events_sync (self, ctx->device, TRUE); + + /* Enable flags asynchronously, which may fail */ + self->priv->enable_flags |= PROCESS_NOTIFICATION_FLAG_SUBSCRIBER_INFO; + common_enable_disable_unsolicited_events (self, + (GAsyncReadyCallback)enable_subscriber_info_unsolicited_events_ready, + task); } /*****************************************************************************/ @@ -4047,9 +4030,10 @@ register_state_query_ready (MbimDevice *device, static void modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, + gboolean is_cs_supported, + gboolean is_ps_supported, + gboolean is_eps_supported, + gboolean is_5gs_supported, GAsyncReadyCallback callback, gpointer user_data) { @@ -4248,7 +4232,7 @@ modem_3gpp_scan_networks (MMIfaceModem3gpp *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("scanning networks..."); + mm_obj_dbg (self, "scanning networks..."); message = mbim_message_visible_providers_query_new (MBIM_VISIBLE_PROVIDERS_ACTION_FULL_SCAN, NULL); mbim_device_command (device, message, @@ -4312,6 +4296,7 @@ typedef struct { MMSignal *gsm; MMSignal *umts; MMSignal *lte; + MMSignal *nr5g; } SignalLoadValuesResult; static void @@ -4320,6 +4305,7 @@ signal_load_values_result_free (SignalLoadValuesResult *result) g_clear_object (&result->gsm); g_clear_object (&result->umts); g_clear_object (&result->lte); + g_clear_object (&result->nr5g); g_slice_free (SignalLoadValuesResult, result); } @@ -4331,6 +4317,7 @@ modem_signal_load_values_finish (MMIfaceModemSignal *self, MMSignal **gsm, MMSignal **umts, MMSignal **lte, + MMSignal **nr5g, GError **error) { SignalLoadValuesResult *result; @@ -4339,20 +4326,14 @@ modem_signal_load_values_finish (MMIfaceModemSignal *self, if (!result) return FALSE; - if (gsm && result->gsm) { - *gsm = result->gsm; - result->gsm = NULL; - } - - if (umts && result->umts) { - *umts = result->umts; - result->umts = NULL; - } - - if (lte && result->lte) { - *lte = result->lte; - result->lte = NULL; - } + if (gsm) + *gsm = g_steal_pointer (&result->gsm); + if (umts) + *umts = g_steal_pointer (&result->umts); + if (lte) + *lte = g_steal_pointer (&result->lte); + if (nr5g) + *nr5g = g_steal_pointer (&result->nr5g); signal_load_values_result_free (result); @@ -4459,7 +4440,7 @@ parent_signal_load_values_ready (MMIfaceModemSignal *self, result = g_slice_new0 (SignalLoadValuesResult); if (!iface_modem_signal_parent->load_values_finish (self, res, NULL, NULL, - &result->gsm, &result->umts, &result->lte, + &result->gsm, &result->umts, &result->lte, &result->nr5g, &error)) { signal_load_values_result_free (result); g_task_return_error (task, error); @@ -4542,32 +4523,26 @@ ussd_encode (const gchar *command, guint32 *scheme, GError **error) { - GByteArray *array; + g_autoptr(GByteArray) array = NULL; if (mm_charset_can_convert_to (command, MM_MODEM_CHARSET_GSM)) { - guint8 *gsm; - guint8 *packed; - guint32 len = 0; - guint32 packed_len = 0; + g_autoptr(GByteArray) gsm = NULL; + guint8 *packed; + guint32 packed_len = 0; *scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT; - gsm = mm_charset_utf8_to_unpacked_gsm (command, &len); + gsm = mm_modem_charset_bytearray_from_utf8 (command, MM_MODEM_CHARSET_GSM, FALSE, error); if (!gsm) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Failed to encode USSD command in GSM7 charset"); + g_prefix_error (error, "Failed to encode USSD command in GSM7 charset: "); return NULL; } - packed = mm_charset_gsm_pack (gsm, len, 0, &packed_len); - g_free (gsm); - + packed = mm_charset_gsm_pack (gsm->data, gsm->len, 0, &packed_len); array = g_byte_array_new_take (packed, packed_len); } else { *scheme = MM_MODEM_GSM_USSD_SCHEME_UCS2; - array = g_byte_array_sized_new (strlen (command) * 2); - if (!mm_modem_charset_byte_array_append (array, command, FALSE, MM_MODEM_CHARSET_UCS2)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Failed to encode USSD command in UCS2 charset"); - g_byte_array_unref (array); + array = mm_modem_charset_bytearray_from_utf8 (command, MM_MODEM_CHARSET_UCS2, FALSE, error); + if (!array) { + g_prefix_error (error, "Failed to encode USSD command in UCS2 charset: "); return NULL; } } @@ -4575,11 +4550,10 @@ ussd_encode (const gchar *command, if (array->len > 160) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Failed to encode USSD command: encoded data too long (%u > 160)", array->len); - g_byte_array_unref (array); return NULL; } - return array; + return g_steal_pointer (&array); } static gchar * @@ -4590,21 +4564,20 @@ ussd_decode (guint32 scheme, gchar *decoded = NULL; if (scheme == MM_MODEM_GSM_USSD_SCHEME_7BIT) { - guint8 *unpacked; - guint32 unpacked_len; + g_autoptr(GByteArray) unpacked_array = NULL; + guint8 *unpacked = NULL; + guint32 unpacked_len; unpacked = mm_charset_gsm_unpack ((const guint8 *)data->data, (data->len * 8) / 7, 0, &unpacked_len); - decoded = (gchar *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); + unpacked_array = g_byte_array_new_take (unpacked, unpacked_len); + + decoded = mm_modem_charset_bytearray_to_utf8 (unpacked_array, MM_MODEM_CHARSET_GSM, FALSE, error); if (!decoded) - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Error decoding USSD command in 0x%04x scheme (GSM7 charset)", - scheme); + g_prefix_error (error, "Error decoding USSD command in 0x%04x scheme (GSM7 charset): ", scheme); } else if (scheme == MM_MODEM_GSM_USSD_SCHEME_UCS2) { - decoded = mm_modem_charset_byte_array_to_utf8 (data, MM_MODEM_CHARSET_UCS2); + decoded = mm_modem_charset_bytearray_to_utf8 (data, MM_MODEM_CHARSET_UCS2, FALSE, error); if (!decoded) - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Error decoding USSD command in 0x%04x scheme (UCS2 charset)", - scheme); + g_prefix_error (error, "Error decoding USSD command in 0x%04x scheme (UCS2 charset): ", scheme); } else g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Failed to decode USSD command in unsupported 0x%04x scheme", scheme); @@ -4710,7 +4683,7 @@ process_ussd_message (MMBroadbandModemMbim *self, /* If no pending task, just report the error */ if (error) { - mm_dbg ("Network reported USSD message: %s", error->message); + mm_obj_dbg (self, "network reported USSD message: %s", error->message); g_error_free (error); } @@ -4734,11 +4707,11 @@ process_ussd_notification (MMBroadbandModemMbim *self, &data_size, &data, NULL)) { - mm_dbg ("Received USSD indication: %s, session state: %s, scheme: 0x%x, data size: %u bytes", - mbim_ussd_response_get_string (ussd_response), - mbim_ussd_session_state_get_string (ussd_session_state), - scheme, - data_size); + mm_obj_dbg (self, "received USSD indication: %s, session state: %s, scheme: 0x%x, data size: %u bytes", + mbim_ussd_response_get_string (ussd_response), + mbim_ussd_session_state_get_string (ussd_session_state), + scheme, + data_size); process_ussd_message (self, ussd_response, ussd_session_state, scheme, data_size, data); } } @@ -4874,11 +4847,11 @@ ussd_send_ready (MbimDevice *device, &data_size, &data, &error)) { - mm_dbg ("Received USSD response: %s, session state: %s, scheme: 0x%x, data size: %u bytes", - mbim_ussd_response_get_string (ussd_response), - mbim_ussd_session_state_get_string (ussd_session_state), - scheme, - data_size); + mm_obj_dbg (self, "received USSD response: %s, session state: %s, scheme: 0x%x, data size: %u bytes", + mbim_ussd_response_get_string (ussd_response), + mbim_ussd_session_state_get_string (ussd_session_state), + scheme, + data_size); process_ussd_message (self, ussd_response, ussd_session_state, scheme, data_size, data); } else { /* Report error in the cached task, if any */ @@ -4890,7 +4863,7 @@ ussd_send_ready (MbimDevice *device, g_task_return_error (task, error); g_object_unref (task); } else { - mm_dbg ("Failed to parse USSD response: %s", error->message); + mm_obj_dbg (self, "failed to parse USSD response: %s", error->message); g_clear_error (&error); } } @@ -5079,10 +5052,10 @@ messaging_check_support (MMIfaceModemMessaging *_self, /* We only handle 3GPP messaging (PDU based) currently */ if (self->priv->caps_sms & MBIM_SMS_CAPS_PDU_RECEIVE && self->priv->caps_sms & MBIM_SMS_CAPS_PDU_SEND) { - mm_dbg ("Messaging capabilities supported"); + mm_obj_dbg (self, "messaging capabilities supported"); g_task_return_boolean (task, TRUE); } else { - mm_dbg ("Messaging capabilities not supported by this modem"); + mm_obj_dbg (self, "messaging capabilities not supported by this modem"); g_task_return_boolean (task, FALSE); } g_object_unref (task); @@ -5142,18 +5115,20 @@ add_sms_part (MMBroadbandModemMbim *self, part = mm_sms_part_3gpp_new_from_binary_pdu (pdu->message_index, pdu->pdu_data, pdu->pdu_data_size, + self, + FALSE, &error); if (part) { - mm_dbg ("Correctly parsed PDU (%d)", pdu->message_index); + mm_obj_dbg (self, "correctly parsed PDU (%d)", pdu->message_index); mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), part, mm_sms_state_from_mbim_message_status (pdu->message_status), MM_SMS_STORAGE_MT); } else { /* Don't treat the error as critical */ - mm_dbg ("Error parsing PDU (%d): %s", - pdu->message_index, - error->message); + mm_obj_dbg (self, "error parsing PDU (%d): %s", + pdu->message_index, + error->message); g_error_free (error); } } @@ -5213,7 +5188,7 @@ load_initial_sms_parts (MMIfaceModemMessaging *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading SMS parts..."); + mm_obj_dbg (self, "loading SMS parts..."); message = mbim_message_sms_read_query_new (MBIM_SMS_FORMAT_PDU, MBIM_SMS_FLAG_ALL, 0, /* message index, unused */ @@ -5304,6 +5279,44 @@ messaging_create_sms (MMIfaceModemMessaging *self) /*****************************************************************************/ +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (object); + + switch (prop_id) { + case PROP_QMI_UNSUPPORTED: + self->priv->qmi_unsupported = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (object); + + switch (prop_id) { + case PROP_QMI_UNSUPPORTED: + g_value_set_boolean (value, self->priv->qmi_unsupported); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +#endif + MMBroadbandModemMbim * mm_broadband_modem_mbim_new (const gchar *device, const gchar **drivers, @@ -5341,7 +5354,7 @@ dispose (GObject *object) /* If any port cleanup is needed, it must be done during dispose(), as * the modem object will be affected by an explciit g_object_run_dispose() * that will remove all port references right away */ - mbim = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self)); + mbim = mm_broadband_modem_mbim_peek_port_mbim (self); if (mbim) { /* Explicitly remove notification handler */ self->priv->setup_flags = PROCESS_NOTIFICATION_FLAG_NONE; @@ -5361,6 +5374,7 @@ finalize (GObject *object) { MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (object); + g_free (self->priv->caps_custom_data_class); g_free (self->priv->caps_device_id); g_free (self->priv->caps_firmware_info); g_free (self->priv->caps_hardware_info); @@ -5427,6 +5441,8 @@ iface_modem_init (MMIfaceModem *iface) iface->load_current_bands_finish = mm_shared_qmi_load_current_bands_finish; iface->set_current_bands = mm_shared_qmi_set_current_bands; iface->set_current_bands_finish = mm_shared_qmi_set_current_bands_finish; + iface->fcc_unlock = mm_shared_qmi_fcc_unlock; + iface->fcc_unlock_finish = mm_shared_qmi_fcc_unlock_finish; #endif /* Additional actions */ @@ -5448,6 +5464,12 @@ iface_modem_init (MMIfaceModem *iface) /* Create MBIM-specific SIM */ iface->create_sim = create_sim; iface->create_sim_finish = create_sim_finish; +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + iface->load_sim_slots = mm_shared_qmi_load_sim_slots; + iface->load_sim_slots_finish = mm_shared_qmi_load_sim_slots_finish; + iface->set_primary_sim_slot = mm_shared_qmi_set_primary_sim_slot; + iface->set_primary_sim_slot_finish = mm_shared_qmi_set_primary_sim_slot_finish; +#endif /* Create MBIM-specific bearer */ iface->create_bearer = modem_create_bearer; @@ -5625,6 +5647,12 @@ mm_broadband_modem_mbim_class_init (MMBroadbandModemMbimClass *klass) g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbimPrivate)); + klass->peek_port_mbim_for_data = peek_port_mbim_for_data; + +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + object_class->set_property = set_property; + object_class->get_property = get_property; +#endif object_class->dispose = dispose; object_class->finalize = finalize; @@ -5635,4 +5663,13 @@ mm_broadband_modem_mbim_class_init (MMBroadbandModemMbimClass *klass) /* Do not initialize the MBIM modem through AT commands */ broadband_modem_class->enabling_modem_init = NULL; broadband_modem_class->enabling_modem_init_finish = NULL; + +#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED + g_object_class_install_property (object_class, PROP_QMI_UNSUPPORTED, + g_param_spec_boolean (MM_BROADBAND_MODEM_MBIM_QMI_UNSUPPORTED, + "QMI over MBIM unsupported", + "TRUE when QMI over MBIM should not be considered.", + FALSE, + G_PARAM_READWRITE)); +#endif } diff --git a/src/mm-broadband-modem-mbim.h b/src/mm-broadband-modem-mbim.h index b8cf748c..66a12f2a 100644 --- a/src/mm-broadband-modem-mbim.h +++ b/src/mm-broadband-modem-mbim.h @@ -29,6 +29,8 @@ typedef struct _MMBroadbandModemMbim MMBroadbandModemMbim; typedef struct _MMBroadbandModemMbimClass MMBroadbandModemMbimClass; typedef struct _MMBroadbandModemMbimPrivate MMBroadbandModemMbimPrivate; +#define MM_BROADBAND_MODEM_MBIM_QMI_UNSUPPORTED "broadband-modem-mbim-qmi-unsupported" + struct _MMBroadbandModemMbim { MMBroadbandModem parent; MMBroadbandModemMbimPrivate *priv; @@ -36,14 +38,28 @@ struct _MMBroadbandModemMbim { struct _MMBroadbandModemMbimClass{ MMBroadbandModemClass parent; + + MMPortMbim * (* peek_port_mbim_for_data) (MMBroadbandModemMbim *self, + MMPort *data, + GError **error); }; GType mm_broadband_modem_mbim_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBroadbandModemMbim, g_object_unref) -MMBroadbandModemMbim *mm_broadband_modem_mbim_new (const gchar *device, +MMBroadbandModemMbim *mm_broadband_modem_mbim_new (const gchar *device, const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id); + const gchar *plugin, + guint16 vendor_id, + guint16 product_id); + +MMPortMbim *mm_broadband_modem_mbim_peek_port_mbim (MMBroadbandModemMbim *self); +MMPortMbim *mm_broadband_modem_mbim_peek_port_mbim_for_data (MMBroadbandModemMbim *self, + MMPort *data, + GError **error); +MMPortMbim *mm_broadband_modem_mbim_get_port_mbim (MMBroadbandModemMbim *self); +MMPortMbim *mm_broadband_modem_mbim_get_port_mbim_for_data (MMBroadbandModemMbim *self, + MMPort *data, + GError **error); #endif /* MM_BROADBAND_MODEM_MBIM_H */ diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c index 7c6f4eb5..bc61461d 100644 --- a/src/mm-broadband-modem-qmi.c +++ b/src/mm-broadband-modem-qmi.c @@ -85,14 +85,22 @@ struct _MMBroadbandModemQmiPrivate { /* 3GPP and CDMA share unsolicited events setup/enable/disable/cleanup */ gboolean unsolicited_events_enabled; gboolean unsolicited_events_setup; - guint event_report_indication_id; + guint nas_event_report_indication_id; + guint wds_event_report_indication_id; #if defined WITH_NEWEST_QMI_COMMANDS - guint signal_info_indication_id; + guint nas_signal_info_indication_id; #endif /* WITH_NEWEST_QMI_COMMANDS */ /* New devices may not support the legacy DMS UIM commands */ gboolean dms_uim_deprecated; + /* Whether autoconnect disabling needs to be checked up during + * the device enabling */ + gboolean autoconnect_checked; + + /* Index of the WDS profile used as initial EPS bearer */ + guint16 default_attach_pdn; + /* 3GPP/CDMA registration helpers */ gchar *current_operator_id; gchar *current_operator_description; @@ -122,6 +130,13 @@ struct _MMBroadbandModemQmiPrivate { gboolean oma_unsolicited_events_setup; guint oma_event_report_indication_id; + /* 3GPP USSD helpers */ + guint ussd_indication_id; + guint ussd_release_indication_id; + gboolean ussd_unsolicited_events_enabled; + gboolean ussd_unsolicited_events_setup; + GTask *pending_ussd_action; + /* Firmware helpers */ gboolean firmware_list_preloaded; GList *firmware_list; @@ -142,7 +157,7 @@ shared_qmi_peek_client (MMSharedQmi *self, MMPortQmi *port; QmiClient *client; - port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self)); + port = mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self)); if (!port) { g_set_error (error, MM_CORE_ERROR, @@ -162,6 +177,137 @@ shared_qmi_peek_client (MMSharedQmi *self, return client; } +/*****************************************************************************/ + +MMPortQmi * +mm_broadband_modem_qmi_get_port_qmi (MMBroadbandModemQmi *self) +{ + MMPortQmi *primary_qmi_port; + + g_assert (MM_IS_BROADBAND_MODEM_QMI (self)); + + primary_qmi_port = mm_broadband_modem_qmi_peek_port_qmi (self); + return (primary_qmi_port ? + MM_PORT_QMI (g_object_ref (primary_qmi_port)) : + NULL); +} + +MMPortQmi * +mm_broadband_modem_qmi_peek_port_qmi (MMBroadbandModemQmi *self) +{ + MMPortQmi *primary_qmi_port = NULL; + GList *qmi_ports; + + g_assert (MM_IS_BROADBAND_MODEM_QMI (self)); + + qmi_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self), + MM_PORT_SUBSYS_UNKNOWN, + MM_PORT_TYPE_QMI, + NULL); + + /* First QMI port in the list is the primary one always */ + if (qmi_ports) + primary_qmi_port = MM_PORT_QMI (qmi_ports->data); + + g_list_free_full (qmi_ports, g_object_unref); + + return primary_qmi_port; +} + +MMPortQmi * +mm_broadband_modem_qmi_get_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error) +{ + MMPortQmi *qmi_port; + + g_assert (MM_IS_BROADBAND_MODEM_QMI (self)); + + qmi_port = mm_broadband_modem_qmi_peek_port_qmi_for_data (self, data, out_sio_port, error); + return (qmi_port ? + MM_PORT_QMI (g_object_ref (qmi_port)) : + NULL); +} + +static MMPortQmi * +peek_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error) +{ + GList *cdc_wdm_qmi_ports; + GList *l; + const gchar *net_port_parent_path; + MMPortQmi *found = NULL; + const gchar *net_port_driver; + + g_assert (MM_IS_BROADBAND_MODEM_QMI (self)); + g_assert (mm_port_get_subsys (data) == MM_PORT_SUBSYS_NET); + + net_port_driver = mm_kernel_device_get_driver (mm_port_peek_kernel_device (data)); + if (g_strcmp0 (net_port_driver, "qmi_wwan") != 0 && g_strcmp0 (net_port_driver, "mhi_net")) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unsupported QMI kernel driver for 'net/%s': %s", + mm_port_get_device (data), + net_port_driver); + return NULL; + } + + if (!g_strcmp0 (net_port_driver, "mhi_net")) + return mm_broadband_modem_qmi_peek_port_qmi (self); + + net_port_parent_path = mm_kernel_device_get_interface_sysfs_path (mm_port_peek_kernel_device (data)); + if (!net_port_parent_path) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "No parent path for 'net/%s'", + mm_port_get_device (data)); + return NULL; + } + + /* Find the CDC-WDM port on the same USB interface as the given net port */ + cdc_wdm_qmi_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self), + MM_PORT_SUBSYS_USBMISC, + MM_PORT_TYPE_QMI, + NULL); + for (l = cdc_wdm_qmi_ports; l && !found; l = g_list_next (l)) { + const gchar *wdm_port_parent_path; + + g_assert (MM_IS_PORT_QMI (l->data)); + wdm_port_parent_path = mm_kernel_device_get_interface_sysfs_path (mm_port_peek_kernel_device (MM_PORT (l->data))); + if (wdm_port_parent_path && g_str_equal (wdm_port_parent_path, net_port_parent_path)) + found = MM_PORT_QMI (l->data); + } + + g_list_free_full (cdc_wdm_qmi_ports, g_object_unref); + + if (!found) + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND, + "Couldn't find associated QMI port for 'net/%s'", + mm_port_get_device (data)); + else + *out_sio_port = QMI_SIO_PORT_NONE; + + return found; +} + +MMPortQmi * +mm_broadband_modem_qmi_peek_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error) +{ + g_assert (MM_BROADBAND_MODEM_QMI_GET_CLASS (self)->peek_port_qmi_for_data); + + return MM_BROADBAND_MODEM_QMI_GET_CLASS (self)->peek_port_qmi_for_data (self, data, out_sio_port, error); +} + /*****************************************************************************/ /* Create Bearer (Modem interface) */ @@ -241,7 +387,7 @@ modem_load_manufacturer (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading manufacturer..."); + mm_obj_dbg (self, "loading manufacturer..."); qmi_client_dms_get_manufacturer (QMI_CLIENT_DMS (client), NULL, 5, @@ -301,7 +447,7 @@ modem_load_model (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading model..."); + mm_obj_dbg (self, "loading model..."); qmi_client_dms_get_model (QMI_CLIENT_DMS (client), NULL, 5, @@ -361,7 +507,7 @@ modem_load_revision (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading revision..."); + mm_obj_dbg (self, "loading revision..."); qmi_client_dms_get_revision (QMI_CLIENT_DMS (client), NULL, 5, @@ -421,7 +567,7 @@ modem_load_hardware_revision (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading hardware revision..."); + mm_obj_dbg (self, "loading hardware revision..."); qmi_client_dms_get_hardware_revision (QMI_CLIENT_DMS (client), NULL, 5, @@ -492,7 +638,7 @@ dms_get_ids_ready (QmiClientDms *client, else if (len == 8) self->priv->esn = g_strdup (str); else - mm_dbg ("Invalid ESN reported: '%s' (unexpected length)", str); + mm_obj_dbg (self, "invalid ESN reported: '%s' (unexpected length)", str); } if (qmi_message_dms_get_ids_output_get_meid (output, &str, NULL) && @@ -502,7 +648,7 @@ dms_get_ids_ready (QmiClientDms *client, if (len == 14) self->priv->meid = g_strdup (str); else - mm_dbg ("Invalid MEID reported: '%s' (unexpected length)", str); + mm_obj_dbg (self, "invalid MEID reported: '%s' (unexpected length)", str); } if (self->priv->imei) @@ -532,7 +678,7 @@ modem_load_equipment_identifier (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading equipment identifier..."); + mm_obj_dbg (self, "loading equipment identifier..."); qmi_client_dms_get_ids (QMI_CLIENT_DMS (client), NULL, 5, @@ -557,17 +703,21 @@ modem_load_device_identifier (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - gchar *device_identifier; - GTask *task; + gchar *device_identifier; + GTask *task; + GError *error = NULL; + + task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading device identifier..."); + mm_obj_dbg (self, "loading device identifier..."); /* Just use dummy ATI/ATI1 replies, all the other internal info should be * enough for uniqueness */ - device_identifier = mm_broadband_modem_create_device_identifier (MM_BROADBAND_MODEM (self), "", ""); - - task = g_task_new (self, NULL, callback, user_data); - g_task_return_pointer (task, device_identifier, g_free); + device_identifier = mm_broadband_modem_create_device_identifier (MM_BROADBAND_MODEM (self), "", "", &error); + if (!device_identifier) + g_task_return_error (task, error); + else + g_task_return_pointer (task, device_identifier, g_free); g_object_unref (task); } @@ -625,7 +775,7 @@ modem_load_own_numbers (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("loading own numbers..."); + mm_obj_dbg (self, "loading own numbers..."); qmi_client_dms_get_msisdn (QMI_CLIENT_DMS (client), NULL, 5, @@ -669,272 +819,33 @@ modem_load_unlock_required_finish (MMIfaceModem *self, static void load_unlock_required_context_step (GTask *task); -/* Used also when loading unlock retries left */ -static gboolean -uim_get_card_status_output_parse (QmiMessageUimGetCardStatusOutput *output, - MMModemLock *o_lock, - guint *o_pin1_retries, - guint *o_puk1_retries, - guint *o_pin2_retries, - guint *o_puk2_retries, - GError **error) -{ - GArray *cards; - QmiMessageUimGetCardStatusOutputCardStatusCardsElement *card; - QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement *app; - MMModemLock lock = MM_MODEM_LOCK_UNKNOWN; - guint i; - gint card_i = -1; - gint application_j = -1; - guint n_absent = 0; - guint n_error = 0; - guint n_invalid = 0; - - /* This command supports MULTIPLE cards with MULTIPLE applications each. For our - * purposes, we're going to consider as the SIM to use the first card present - * with a SIM/USIM application. */ - - if (!qmi_message_uim_get_card_status_output_get_result (output, error)) { - g_prefix_error (error, "QMI operation failed: "); - return FALSE; - } - - qmi_message_uim_get_card_status_output_get_card_status ( - output, - NULL, /* index_gw_primary */ - NULL, /* index_1x_primary */ - NULL, /* index_gw_secondary */ - NULL, /* index_1x_secondary */ - &cards, - NULL); - - if (cards->len == 0) { - g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED, - "No cards reported"); - return FALSE; - } - - if (cards->len > 1) - mm_dbg ("Multiple cards reported: %u", cards->len); - - /* All KNOWN applications in all cards will need to be in READY state for us - * to consider UNLOCKED */ - for (i = 0; i < cards->len; i++) { - card = &g_array_index (cards, QmiMessageUimGetCardStatusOutputCardStatusCardsElement, i); - - switch (card->card_state) { - case QMI_UIM_CARD_STATE_PRESENT: { - guint j; - gboolean sim_usim_found = FALSE; - - if (card->applications->len == 0) { - mm_dbg ("No applications reported in card [%u]", i); - n_invalid++; - break; - } - - if (card->applications->len > 1) - mm_dbg ("Multiple applications reported in card [%u]: %u", i, card->applications->len); - - for (j = 0; j < card->applications->len; j++) { - app = &g_array_index (card->applications, QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement, j); - - if (app->type == QMI_UIM_CARD_APPLICATION_TYPE_UNKNOWN) { - mm_dbg ("Unknown application [%u] found in card [%u]: %s. Ignored.", - j, i, qmi_uim_card_application_state_get_string (app->state)); - continue; - } - - mm_dbg ("Application '%s' [%u] in card [%u]: %s", - qmi_uim_card_application_type_get_string (app->type), j, i, qmi_uim_card_application_state_get_string (app->state)); - - if (app->type == QMI_UIM_CARD_APPLICATION_TYPE_SIM || app->type == QMI_UIM_CARD_APPLICATION_TYPE_USIM) { - /* We found the card/app pair to use! Only keep the first found, - * but still, keep on looping to log about the remaining ones */ - if (card_i < 0 && application_j < 0) { - card_i = i; - application_j = j; - } - - sim_usim_found = TRUE; - } - } - - if (!sim_usim_found) { - mm_dbg ("No SIM/USIM application found in card [%u]", i); - n_invalid++; - } - - break; - } - - case QMI_UIM_CARD_STATE_ABSENT: - mm_dbg ("Card '%u' is absent", i); - n_absent++; - break; - - case QMI_UIM_CARD_STATE_ERROR: - default: - n_error++; - if (qmi_uim_card_error_get_string (card->error_code) != NULL) - mm_warn ("Card '%u' is unusable: %s", i, qmi_uim_card_error_get_string (card->error_code)); - else - mm_warn ("Card '%u' is unusable: unknown error", i); - break; - } - - /* go on to next card */ - } - - /* If we found no card/app to use, we need to report an error */ - if (card_i < 0 || application_j < 0) { - /* If not a single card found, report SIM not inserted */ - if (n_absent > 0 && !n_error && !n_invalid) - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, - "No card found"); - else if (n_error > 0) - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, - "Card error"); - else - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE, - "Card failure: %u absent, %u errors, %u invalid", - n_absent, n_error, n_invalid); - return FALSE; - } - - /* Get card/app to use */ - card = &g_array_index (cards, QmiMessageUimGetCardStatusOutputCardStatusCardsElement, card_i); - app = &g_array_index (card->applications, QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement, application_j); - - /* If card not ready yet, return RETRY error. - * If the application state reports needing PIN/PUk, consider that ready as - * well, and let the logic fall down to check PIN1/PIN2. */ - if (app->state != QMI_UIM_CARD_APPLICATION_STATE_READY && - app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_OR_UPIN_PIN_REQUIRED && - app->state != QMI_UIM_CARD_APPLICATION_STATE_PUK1_OR_UPIN_PUK_REQUIRED && - app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_BLOCKED) { - mm_dbg ("Neither SIM nor USIM are ready"); - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY, - "SIM not ready yet (retry)"); - return FALSE; - } - - /* Report retries if requested to do so */ - if (o_pin1_retries) - *o_pin1_retries = app->pin1_retries; - if (o_puk1_retries) - *o_puk1_retries = app->puk1_retries; - if (o_pin2_retries) - *o_pin2_retries = app->pin2_retries; - if (o_puk2_retries) - *o_puk2_retries = app->puk2_retries; - - /* Early bail out if lock status isn't wanted at this point, so that we - * don't fail with an error the unlock retries check */ - if (!o_lock) - return TRUE; - - /* Card is ready, what's the lock status? */ - - /* PIN1 */ - switch (app->pin1_state) { - case QMI_UIM_PIN_STATE_NOT_INITIALIZED: - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, - "SIM PIN/PUK status not known yet"); - return FALSE; - - case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, - "SIM PIN/PUK permanently blocked"); - return FALSE; - - case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: - lock = MM_MODEM_LOCK_SIM_PIN; - break; - - case QMI_UIM_PIN_STATE_BLOCKED: - lock = MM_MODEM_LOCK_SIM_PUK; - break; - - case QMI_UIM_PIN_STATE_DISABLED: - case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: - lock = MM_MODEM_LOCK_NONE; - break; - - default: - g_set_error (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, - "Unknown SIM PIN/PUK status"); - return FALSE; - } - - /* PIN2 */ - if (lock == MM_MODEM_LOCK_NONE) { - switch (app->pin2_state) { - case QMI_UIM_PIN_STATE_NOT_INITIALIZED: - mm_warn ("SIM PIN2/PUK2 status not known yet"); - break; - - case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: - lock = MM_MODEM_LOCK_SIM_PIN2; - break; - - case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: - mm_warn ("PUK2 permanently blocked"); - /* Fall through */ - case QMI_UIM_PIN_STATE_BLOCKED: - lock = MM_MODEM_LOCK_SIM_PUK2; - break; - - case QMI_UIM_PIN_STATE_DISABLED: - case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: - break; - - default: - mm_warn ("Unknown SIM PIN2/PUK2 status"); - break; - } - } - - *o_lock = lock; - return TRUE; -} - static void unlock_required_uim_get_card_status_ready (QmiClientUim *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; LoadUnlockRequiredContext *ctx; QmiMessageUimGetCardStatusOutput *output; GError *error = NULL; MMModemLock lock = MM_MODEM_LOCK_UNKNOWN; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); output = qmi_client_uim_get_card_status_finish (client, res, &error); - if (!output) { + if (!output || !qmi_message_uim_get_card_status_output_get_result (output, &error)) { g_prefix_error (&error, "QMI operation failed: "); g_task_return_error (task, error); g_object_unref (task); return; } - if (!uim_get_card_status_output_parse (output, - &lock, - NULL, NULL, NULL, NULL, - &error)) { + if (!mm_qmi_uim_get_card_status_output_parse (self, + output, + &lock, + NULL, NULL, NULL, NULL, NULL, NULL, + &error)) { /* The device may report a SIM NOT INSERTED error if we're querying the * card status soon after power on. We'll let the Modem interface generic * logic retry loading the info a bit later if that's the case. This will @@ -1069,7 +980,7 @@ load_unlock_required_context_step (GTask *task) case LOAD_UNLOCK_REQUIRED_STEP_CDMA: /* CDMA-only modems don't need this */ if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (self))) { - mm_dbg ("Skipping unlock check in CDMA-only modem..."); + mm_obj_dbg (self, "skipping unlock check in CDMA-only modem..."); g_task_return_int (task, MM_MODEM_LOCK_NONE); g_object_unref (task); return; @@ -1090,7 +1001,7 @@ load_unlock_required_context_step (GTask *task) return; } - mm_dbg ("loading unlock required (DMS)..."); + mm_obj_dbg (self, "loading unlock required (DMS)..."); qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client), NULL, 5, @@ -1114,7 +1025,7 @@ load_unlock_required_context_step (GTask *task) return; } - mm_dbg ("loading unlock required (UIM)..."); + mm_obj_dbg (self, "loading unlock required (UIM)..."); qmi_client_uim_get_card_status (QMI_CLIENT_UIM (client), NULL, 5, @@ -1163,6 +1074,7 @@ unlock_retries_uim_get_card_status_ready (QmiClientUim *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; QmiMessageUimGetCardStatusOutput *output; GError *error = NULL; guint pin1_retries = 0; @@ -1171,19 +1083,22 @@ unlock_retries_uim_get_card_status_ready (QmiClientUim *client, guint puk2_retries = 0; MMUnlockRetries *retries; + self = g_task_get_source_object (task); + output = qmi_client_uim_get_card_status_finish (client, res, &error); - if (!output) { + if (!output || !qmi_message_uim_get_card_status_output_get_result (output, &error)) { g_prefix_error (&error, "QMI operation failed: "); g_task_return_error (task, error); g_object_unref (task); return; } - if (!uim_get_card_status_output_parse (output, - NULL, - &pin1_retries, &puk1_retries, - &pin2_retries, &puk2_retries, - &error)) { + if (!mm_qmi_uim_get_card_status_output_parse (self, + output, + NULL, + NULL, &pin1_retries, &puk1_retries, + NULL, &pin2_retries, &puk2_retries, + &error)) { g_task_return_error (task, error); g_object_unref (task); return; @@ -1330,7 +1245,7 @@ modem_load_unlock_retries (MMIfaceModem *_self, self = MM_BROADBAND_MODEM_QMI (_self); task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading unlock retries..."); + mm_obj_dbg (self, "loading unlock retries..."); if (!self->priv->dms_uim_deprecated) dms_uim_load_unlock_retries (MM_BROADBAND_MODEM_QMI (self), task); else @@ -1426,7 +1341,8 @@ load_signal_quality_finish (MMIfaceModem *self, #if defined WITH_NEWEST_QMI_COMMANDS static gboolean -common_signal_info_get_quality (gint8 cdma1x_rssi, +common_signal_info_get_quality (MMBroadbandModemQmi *self, + gint8 cdma1x_rssi, gint8 evdo_rssi, gint8 gsm_rssi, gint8 wcdma_rssi, @@ -1447,7 +1363,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, * order to report always the one with the maximum value. */ if (cdma1x_rssi < 0) { - mm_dbg ("RSSI (CDMA): %d dBm", cdma1x_rssi); + mm_obj_dbg (self, "RSSI (CDMA): %d dBm", cdma1x_rssi); if (qmi_dbm_valid (cdma1x_rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1X)) { rssi_max = MAX (cdma1x_rssi, rssi_max); signal_info_radio_interface = QMI_NAS_RADIO_INTERFACE_CDMA_1X; @@ -1455,7 +1371,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, } if (evdo_rssi < 0) { - mm_dbg ("RSSI (HDR): %d dBm", evdo_rssi); + mm_obj_dbg (self, "RSSI (HDR): %d dBm", evdo_rssi); if (qmi_dbm_valid (evdo_rssi, QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO)) { rssi_max = MAX (evdo_rssi, rssi_max); signal_info_radio_interface = QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO; @@ -1463,7 +1379,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, } if (gsm_rssi < 0) { - mm_dbg ("RSSI (GSM): %d dBm", gsm_rssi); + mm_obj_dbg (self, "RSSI (GSM): %d dBm", gsm_rssi); if (qmi_dbm_valid (gsm_rssi, QMI_NAS_RADIO_INTERFACE_GSM)) { rssi_max = MAX (gsm_rssi, rssi_max); signal_info_radio_interface = QMI_NAS_RADIO_INTERFACE_GSM; @@ -1471,7 +1387,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, } if (wcdma_rssi < 0) { - mm_dbg ("RSSI (WCDMA): %d dBm", wcdma_rssi); + mm_obj_dbg (self, "RSSI (WCDMA): %d dBm", wcdma_rssi); if (qmi_dbm_valid (wcdma_rssi, QMI_NAS_RADIO_INTERFACE_UMTS)) { rssi_max = MAX (wcdma_rssi, rssi_max); signal_info_radio_interface = QMI_NAS_RADIO_INTERFACE_UMTS; @@ -1479,7 +1395,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, } if (lte_rssi < 0) { - mm_dbg ("RSSI (LTE): %d dBm", lte_rssi); + mm_obj_dbg (self, "RSSI (LTE): %d dBm", lte_rssi); if (qmi_dbm_valid (lte_rssi, QMI_NAS_RADIO_INTERFACE_LTE)) { rssi_max = MAX (lte_rssi, rssi_max); signal_info_radio_interface = QMI_NAS_RADIO_INTERFACE_LTE; @@ -1491,7 +1407,7 @@ common_signal_info_get_quality (gint8 cdma1x_rssi, *out_quality = STRENGTH_TO_QUALITY (rssi_max); *out_act = mm_modem_access_technology_from_qmi_radio_interface (signal_info_radio_interface); - mm_dbg ("RSSI: %d dBm --> %u%%", rssi_max, *out_quality); + mm_obj_dbg (self, "RSSI: %d dBm --> %u%%", rssi_max, *out_quality); return TRUE; } @@ -1516,7 +1432,7 @@ signal_info_get_quality (MMBroadbandModemQmi *self, qmi_message_nas_get_signal_info_output_get_wcdma_signal_strength (output, &wcdma_rssi, NULL, NULL); qmi_message_nas_get_signal_info_output_get_lte_signal_strength (output, <e_rssi, NULL, NULL, NULL, NULL); - return common_signal_info_get_quality (cdma1x_rssi, evdo_rssi, gsm_rssi, wcdma_rssi, lte_rssi, out_quality, out_act); + return common_signal_info_get_quality (self, cdma1x_rssi, evdo_rssi, gsm_rssi, wcdma_rssi, lte_rssi, out_quality, out_act); } static void @@ -1569,7 +1485,7 @@ get_signal_info_ready (QmiClientNas *client, qmi_message_nas_get_signal_info_output_unref (output); } -#endif /* WITH_NEWEST_QMI_COMMANDS */ +#else /* WITH_NEWEST_QMI_COMMANDS */ static gboolean signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, @@ -1587,9 +1503,9 @@ signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, /* The mandatory one is always present */ qmi_message_nas_get_signal_strength_output_get_signal_strength (output, &signal_max, &main_interface, NULL); - mm_dbg ("Signal strength (%s): %d dBm", - qmi_nas_radio_interface_get_string (main_interface), - signal_max); + mm_obj_dbg (self, "signal strength (%s): %d dBm", + qmi_nas_radio_interface_get_string (main_interface), + signal_max); /* Treat results as invalid if main signal strength is invalid */ if (!qmi_dbm_valid (signal_max, main_interface)) @@ -1606,9 +1522,9 @@ signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, element = &g_array_index (array, QmiMessageNasGetSignalStrengthOutputStrengthListElement, i); - mm_dbg ("Signal strength (%s): %d dBm", - qmi_nas_radio_interface_get_string (element->radio_interface), - element->strength); + mm_obj_dbg (self, "signal strength (%s): %d dBm", + qmi_nas_radio_interface_get_string (element->radio_interface), + element->strength); if (qmi_dbm_valid (element->strength, element->radio_interface)) { signal_max = MAX (element->strength, signal_max); @@ -1622,7 +1538,7 @@ signal_strength_get_quality_and_access_tech (MMBroadbandModemQmi *self, *o_quality = STRENGTH_TO_QUALITY (signal_max); *o_act = act; - mm_dbg ("Signal strength: %d dBm --> %u%%", signal_max, *o_quality); + mm_obj_dbg (self, "signal strength: %d dBm --> %u%%", signal_max, *o_quality); } return (signal_max < 0); @@ -1678,6 +1594,8 @@ get_signal_strength_ready (QmiClientNas *client, qmi_message_nas_get_signal_strength_output_unref (output); } +#endif /* WITH_NEWEST_QMI_COMMANDS */ + static void load_signal_quality (MMIfaceModem *self, GAsyncReadyCallback callback, @@ -1693,120 +1611,59 @@ load_signal_quality (MMIfaceModem *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading signal quality..."); + mm_obj_dbg (self, "loading signal quality..."); #if defined WITH_NEWEST_QMI_COMMANDS - /* Signal info introduced in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { - qmi_client_nas_get_signal_info (QMI_CLIENT_NAS (client), - NULL, - 10, - NULL, - (GAsyncReadyCallback)get_signal_info_ready, - task); - return; - } -#endif /* WITH_NEWEST_QMI_COMMANDS */ - + qmi_client_nas_get_signal_info (QMI_CLIENT_NAS (client), + NULL, + 10, + NULL, + (GAsyncReadyCallback)get_signal_info_ready, + task); +#else qmi_client_nas_get_signal_strength (QMI_CLIENT_NAS (client), NULL, 10, NULL, (GAsyncReadyCallback)get_signal_strength_ready, task); +#endif /* WITH_NEWEST_QMI_COMMANDS */ } /*****************************************************************************/ /* Powering up the modem (Modem interface) */ -typedef enum { - SET_OPERATING_MODE_STEP_FIRST, - SET_OPERATING_MODE_STEP_FCC_AUTH, - SET_OPERATING_MODE_STEP_RETRY, - SET_OPERATING_MODE_STEP_LAST -} SetOperatingModeStep; - -typedef struct { - QmiClientDms *client; - QmiMessageDmsSetOperatingModeInput *input; - SetOperatingModeStep step; -} SetOperatingModeContext; - -static void -set_operating_mode_context_free (SetOperatingModeContext *ctx) -{ - g_object_unref (ctx->client); - qmi_message_dms_set_operating_mode_input_unref (ctx->input); - g_slice_free (SetOperatingModeContext, ctx); -} - static gboolean -modem_power_up_down_off_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) +modem_power_up_down_off_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } -static void set_operating_mode_context_step (GTask *task); - -static void -dms_set_fcc_authentication_ready (QmiClientDms *client, - GAsyncResult *res, - GTask *task) -{ - SetOperatingModeContext *ctx; - QmiMessageDmsSetFccAuthenticationOutput *output = NULL; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - output = qmi_client_dms_set_fcc_authentication_finish (client, res, &error); - if (!output || !qmi_message_dms_set_fcc_authentication_output_get_result (output, &error)) { - /* No hard errors */ - mm_dbg ("Couldn't set FCC authentication: %s", error->message); - g_error_free (error); - } - - if (output) - qmi_message_dms_set_fcc_authentication_output_unref (output); - - /* Retry Set Operating Mode */ - ctx->step++; - set_operating_mode_context_step (task); -} - static void dms_set_operating_mode_ready (QmiClientDms *client, GAsyncResult *res, - GTask *task) + GTask *task) { - SetOperatingModeContext *ctx; - QmiMessageDmsSetOperatingModeOutput *output = NULL; - GError *error = NULL; + MMBroadbandModemQmi *self; + QmiDmsOperatingMode mode; + GError *error = NULL; + g_autoptr(QmiMessageDmsSetOperatingModeOutput) output = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + mode = GPOINTER_TO_UINT (g_task_get_task_data (task)); output = qmi_client_dms_set_operating_mode_finish (client, res, &error); if (!output) { - /* If unsupported, just go out without errors */ + g_prefix_error (&error, "QMI operation failed: "); + /* If unsupported, just complete without errors */ if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED)) { - mm_dbg ("Device doesn't support operating mode setting. Ignoring power update."); - g_error_free (error); - ctx->step = SET_OPERATING_MODE_STEP_LAST; - set_operating_mode_context_step (task); - return; + mm_obj_dbg (self, "device doesn't support operating mode setting: ignoring power update"); + g_clear_error (&error); } - - g_prefix_error (&error, "QMI operation failed: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) { - QmiDmsOperatingMode mode; - + } else if (!qmi_message_dms_set_operating_mode_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't set operating mode: "); /* * Some new devices, like the Dell DW5770, will return an internal error when * trying to bring the power mode to online. @@ -1815,141 +1672,74 @@ dms_set_operating_mode_ready (QmiClientDms *client, * transition" instead when trying to bring the power mode to online. * * We can avoid this by sending the magic "DMS Set FCC Auth" message before - * retrying. + * retrying. Notify this to upper layers with the special MM_CORE_ERROR_RETRY + * error. */ - if (ctx->step == SET_OPERATING_MODE_STEP_FIRST && - qmi_message_dms_set_operating_mode_input_get_mode (ctx->input, &mode, NULL) && - mode == QMI_DMS_OPERATING_MODE_ONLINE && - (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INTERNAL) || - g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_TRANSITION))) { - g_error_free (error); - /* Go on to FCC auth */ - ctx->step++; - set_operating_mode_context_step (task); - qmi_message_dms_set_operating_mode_output_unref (output); - return; + if ((mode == QMI_DMS_OPERATING_MODE_ONLINE) && + ((g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INTERNAL) || + g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_TRANSITION)))) { + g_clear_error (&error); + error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_RETRY, "Invalid transition"); } - - g_prefix_error (&error, "Couldn't set operating mode: "); - g_task_return_error (task, error); - g_object_unref (task); - qmi_message_dms_set_operating_mode_output_unref (output); - return; } - qmi_message_dms_set_operating_mode_output_unref (output); - - /* Good! we're done, go to last step */ - ctx->step = SET_OPERATING_MODE_STEP_LAST; - set_operating_mode_context_step (task); -} - -static void -set_operating_mode_context_step (GTask *task) -{ - SetOperatingModeContext *ctx; - - ctx = g_task_get_task_data (task); - - switch (ctx->step) { - case SET_OPERATING_MODE_STEP_FIRST: - mm_dbg ("Setting device operating mode..."); - qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (ctx->client), - ctx->input, - 20, - NULL, - (GAsyncReadyCallback)dms_set_operating_mode_ready, - task); - return; - case SET_OPERATING_MODE_STEP_FCC_AUTH: - mm_dbg ("Setting FCC auth..."); - qmi_client_dms_set_fcc_authentication (QMI_CLIENT_DMS (ctx->client), - NULL, - 5, - NULL, - (GAsyncReadyCallback)dms_set_fcc_authentication_ready, - task); - return; - case SET_OPERATING_MODE_STEP_RETRY: - mm_dbg ("Setting device operating mode (retry)..."); - qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (ctx->client), - ctx->input, - 20, - NULL, - (GAsyncReadyCallback)dms_set_operating_mode_ready, - task); - return; - case SET_OPERATING_MODE_STEP_LAST: - /* Good! */ + if (error) + g_task_return_error (task, error); + else g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - default: - g_assert_not_reached (); - } + g_object_unref (task); } static void -common_power_up_down_off (MMIfaceModem *self, - QmiDmsOperatingMode mode, - GAsyncReadyCallback callback, - gpointer user_data) +common_power_up_down_off (MMIfaceModem *self, + QmiDmsOperatingMode mode, + GAsyncReadyCallback callback, + gpointer user_data) { - SetOperatingModeContext *ctx; - GTask *task; - QmiClient *client = NULL; + GTask *task; + QmiClient *client = NULL; + g_autoptr(QmiMessageDmsSetOperatingModeInput) input = NULL; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), QMI_SERVICE_DMS, &client, callback, user_data)) return; - /* Setup context */ - ctx = g_slice_new0 (SetOperatingModeContext); - ctx->client = g_object_ref (client); - ctx->input = qmi_message_dms_set_operating_mode_input_new (); - qmi_message_dms_set_operating_mode_input_set_mode (ctx->input, mode, NULL); - ctx->step = SET_OPERATING_MODE_STEP_FIRST; - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, - ctx, - (GDestroyNotify)set_operating_mode_context_free); + g_task_set_task_data (task, GUINT_TO_POINTER (mode), NULL); - set_operating_mode_context_step (task); + input = qmi_message_dms_set_operating_mode_input_new (); + qmi_message_dms_set_operating_mode_input_set_mode (input, mode, NULL); + qmi_client_dms_set_operating_mode (QMI_CLIENT_DMS (client), + input, + 20, + NULL, + (GAsyncReadyCallback)dms_set_operating_mode_ready, + task); } static void -modem_power_off (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +modem_power_off (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) { - common_power_up_down_off (self, - QMI_DMS_OPERATING_MODE_OFFLINE, - callback, - user_data); + common_power_up_down_off (self, QMI_DMS_OPERATING_MODE_OFFLINE, callback, user_data); } static void -modem_power_down (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +modem_power_down (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) { - common_power_up_down_off (self, - QMI_DMS_OPERATING_MODE_LOW_POWER, - callback, - user_data); + common_power_up_down_off (self, QMI_DMS_OPERATING_MODE_LOW_POWER, callback, user_data); } static void -modem_power_up (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +modem_power_up (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) { - common_power_up_down_off (self, - QMI_DMS_OPERATING_MODE_ONLINE, - callback, - user_data); + common_power_up_down_off (self, QMI_DMS_OPERATING_MODE_ONLINE, callback, user_data); } /*****************************************************************************/ @@ -2036,7 +1826,7 @@ load_power_state (MMIfaceModem *self, callback, user_data)) return; - mm_dbg ("Getting device operating mode..."); + mm_obj_dbg (self, "getting device operating mode..."); qmi_client_dms_get_operating_mode (QMI_CLIENT_DMS (client), NULL, 5, @@ -2110,7 +1900,7 @@ typedef struct { MMModem3gppFacility locks; } LoadEnabledFacilityLocksContext; -static void get_next_facility_lock_status (GTask *task); +static void get_next_facility_lock_status_via_dms (GTask *task); static void load_enabled_facility_locks_context_free (LoadEnabledFacilityLocksContext *ctx) @@ -2135,47 +1925,146 @@ modem_3gpp_load_enabled_facility_locks_finish (MMIfaceModem3gpp *self, return (MMModem3gppFacility)value; } +static void +get_sim_lock_status_via_get_card_status_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + LoadEnabledFacilityLocksContext *ctx; + QmiMessageUimGetCardStatusOutput *output; + GError *error = NULL; + MMModemLock lock = MM_MODEM_LOCK_UNKNOWN; + QmiUimPinState pin1_state; + QmiUimPinState pin2_state; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_uim_get_card_status_finish (client, res, &error); + if (!output || !qmi_message_uim_get_card_status_output_get_result (output, &error)) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + if (output) + qmi_message_uim_get_card_status_output_unref (output); + return; + } + + if (!mm_qmi_uim_get_card_status_output_parse (self, + output, + &lock, + &pin1_state, NULL, NULL, &pin2_state, NULL, NULL, + &error)) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + } else { + ctx->locks &= ~(MM_MODEM_3GPP_FACILITY_SIM); + ctx->locks &= ~(MM_MODEM_3GPP_FACILITY_FIXED_DIALING); + + if (pin1_state == QMI_UIM_PIN_STATE_ENABLED_VERIFIED || + pin1_state == QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED || + pin1_state == QMI_UIM_PIN_STATE_BLOCKED) { + ctx->locks |= (MM_MODEM_3GPP_FACILITY_SIM); + } + if (pin2_state == QMI_UIM_PIN_STATE_ENABLED_VERIFIED || + pin2_state == QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED || + pin2_state == QMI_UIM_PIN_STATE_BLOCKED) { + ctx->locks |= (MM_MODEM_3GPP_FACILITY_FIXED_DIALING); + } + + g_task_return_int (task, ctx->locks); + } + + qmi_message_uim_get_card_status_output_unref (output); + g_object_unref (task); +} + +static void +get_sim_lock_status_via_get_card_status (GTask *task) +{ + MMBroadbandModemQmi *self; + LoadEnabledFacilityLocksContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + mm_obj_dbg (self, "Getting UIM card status to read pin lock state..."); + qmi_client_uim_get_card_status (QMI_CLIENT_UIM (ctx->client), + NULL, + 5, + NULL, + (GAsyncReadyCallback) get_sim_lock_status_via_get_card_status_ready, + task); +} + static void get_sim_lock_status_via_pin_status_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; LoadEnabledFacilityLocksContext *ctx; QmiMessageDmsUimGetPinStatusOutput *output; - gboolean enabled; + QmiDmsUimPinStatus current_status; + GError *error; + gboolean pin1_enabled; + gboolean pin2_enabled; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - output = qmi_client_dms_uim_get_pin_status_finish (client, res, NULL); + output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error); if (!output || - !qmi_message_dms_uim_get_pin_status_output_get_result (output, NULL)) { - mm_dbg ("Couldn't query PIN status, assuming SIM PIN is disabled"); - enabled = FALSE; - } else { - QmiDmsUimPinStatus current_status; + !qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + if (output) + qmi_message_dms_uim_get_pin_status_output_unref (output); + return; + } - if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status ( - output, - ¤t_status, - NULL, /* verify_retries_left */ - NULL, /* unblock_retries_left */ - NULL)) { - enabled = mm_pin_enabled_from_qmi_uim_pin_status (current_status); - mm_dbg ("PIN is reported %s", (enabled ? "enabled" : "disabled")); - } else { - mm_dbg ("Couldn't find PIN1 status in the result, assuming SIM PIN is disabled"); - enabled = FALSE; - } + if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status ( + output, + ¤t_status, + NULL, /* verify_retries_left */ + NULL, /* unblock_retries_left */ + &error)) { + pin1_enabled = mm_pin_enabled_from_qmi_uim_pin_status (current_status); + mm_obj_dbg (self, "PIN1 is reported %s", (pin1_enabled ? "enabled" : "disabled")); + } else { + qmi_message_dms_uim_get_pin_status_output_unref (output); + g_task_return_error (task, error); + g_object_unref (task); + return; } - if (output) + if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status ( + output, + ¤t_status, + NULL, /* verify_retries_left */ + NULL, /* unblock_retries_left */ + &error)) { + pin2_enabled = mm_pin_enabled_from_qmi_uim_pin_status (current_status); + mm_obj_dbg (self, "PIN2 is reported %s", (pin2_enabled ? "enabled" : "disabled")); + } else { qmi_message_dms_uim_get_pin_status_output_unref (output); + g_task_return_error (task, error); + g_object_unref (task); + return; + } - if (enabled) { + qmi_message_dms_uim_get_pin_status_output_unref (output); + + if (pin1_enabled) ctx->locks |= (MM_MODEM_3GPP_FACILITY_SIM); - } else { + else ctx->locks &= ~(MM_MODEM_3GPP_FACILITY_SIM); - } + + if (pin2_enabled) + ctx->locks |= (MM_MODEM_3GPP_FACILITY_FIXED_DIALING); + else + ctx->locks &= ~(MM_MODEM_3GPP_FACILITY_FIXED_DIALING); /* No more facilities to query, all done */ g_task_return_int (task, ctx->locks); @@ -2187,11 +2076,13 @@ get_sim_lock_status_via_pin_status_ready (QmiClientDms *client, static void get_sim_lock_status_via_pin_status (GTask *task) { + MMBroadbandModemQmi *self; LoadEnabledFacilityLocksContext *ctx; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - mm_dbg ("Retrieving PIN status to check for enabled PIN"); + mm_obj_dbg (self, "retrieving PIN status to check for enabled PIN"); /* if the SIM is locked or not can only be queried by locking at * the PIN status */ qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (ctx->client), @@ -2207,17 +2098,20 @@ dms_uim_get_ck_status_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; LoadEnabledFacilityLocksContext *ctx; gchar *facility_str; QmiMessageDmsUimGetCkStatusOutput *output; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); + facility_str = mm_modem_3gpp_facility_build_string_from_mask (1 << ctx->current); output = qmi_client_dms_uim_get_ck_status_finish (client, res, NULL); if (!output || !qmi_message_dms_uim_get_ck_status_output_get_result (output, NULL)) { /* On errors, we'll just assume disabled */ - mm_dbg ("Couldn't query facility '%s' status, assuming disabled", facility_str); + mm_obj_dbg (self, "couldn't query facility '%s' status, assuming disabled", facility_str); ctx->locks &= ~(1 << ctx->current); } else { QmiDmsUimFacilityState state; @@ -2231,7 +2125,7 @@ dms_uim_get_ck_status_ready (QmiClientDms *client, &unblock_retries_left, NULL); - mm_dbg ("Facility '%s' is: '%s'", + mm_obj_dbg (self, "facility '%s' is: '%s'", facility_str, qmi_dms_uim_facility_state_get_string (state)); @@ -2247,11 +2141,11 @@ dms_uim_get_ck_status_ready (QmiClientDms *client, /* And go on with the next one */ ctx->current++; - get_next_facility_lock_status (task); + get_next_facility_lock_status_via_dms (task); } static void -get_next_facility_lock_status (GTask *task) +get_next_facility_lock_status_via_dms (GTask *task) { LoadEnabledFacilityLocksContext *ctx; guint i; @@ -2297,10 +2191,17 @@ modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self, GTask *task; QmiClient *client = NULL; - if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_DMS, &client, - callback, user_data)) - return; + if (!MM_BROADBAND_MODEM_QMI (self)->priv->dms_uim_deprecated) { + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_DMS, &client, + callback, user_data)) + return; + } else { + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_UIM, &client, + callback, user_data)) + return; + } ctx = g_new (LoadEnabledFacilityLocksContext, 1); ctx->client = g_object_ref (client); @@ -2317,7 +2218,13 @@ modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)load_enabled_facility_locks_context_free); - get_next_facility_lock_status (task); + /* DMS uses get_ck_status and get_pin_status to probe facilities + * UIM Messages to get all facility locks are not open-source yet + * UIM uses get_card_status to probe only FACILITY_SIM and FACILITY_FIXED_DIALING */ + if (!MM_BROADBAND_MODEM_QMI (self)->priv->dms_uim_deprecated) + get_next_facility_lock_status_via_dms (task); + else + get_sim_lock_status_via_get_card_status (task); } /*****************************************************************************/ @@ -2471,7 +2378,7 @@ modem_3gpp_scan_networks (MMIfaceModem3gpp *self, callback, user_data)) return; - mm_dbg ("Scanning networks..."); + mm_obj_dbg (self, "scanning networks..."); qmi_client_nas_network_scan (QMI_CLIENT_NAS (client), NULL, 300, @@ -2557,6 +2464,8 @@ modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self, return g_task_propagate_boolean (G_TASK (res), error); } +#if !defined WITH_NEWEST_QMI_COMMANDS + static void common_process_serving_system_3gpp (MMBroadbandModemQmi *self, QmiMessageNasGetServingSystemOutput *response_output, @@ -2579,6 +2488,7 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, MMModemAccessTechnology mm_access_technologies; MMModem3gppRegistrationState mm_cs_registration_state; MMModem3gppRegistrationState mm_ps_registration_state; + gboolean operator_updated = FALSE; if (response_output) qmi_message_nas_get_serving_system_output_get_serving_system ( @@ -2606,7 +2516,7 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, else qmi_indication_nas_serving_system_output_get_data_service_capability (indication_output, &data_service_capabilities, NULL); - if (data_service_capabilities) + if (data_service_capabilities && data_service_capabilities->len > 0) mm_access_technologies = mm_modem_access_technologies_from_qmi_data_capability_array (data_service_capabilities); else @@ -2615,15 +2525,17 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, /* Only process 3GPP info. * Seen the case already where 'selected_network' gives UNKNOWN but we still - * have valid LTE info around. */ + * have valid LTE/5GNR info around. */ if (selected_network == QMI_NAS_NETWORK_TYPE_3GPP || (selected_network == QMI_NAS_NETWORK_TYPE_UNKNOWN && (mm_access_technologies & MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK))) { - mm_dbg ("Processing 3GPP info..."); + mm_obj_dbg (self, "processing 3GPP info..."); } else { MMModem3gppRegistrationState reg_state_3gpp; - mm_dbg ("No 3GPP info given..."); + mm_obj_dbg (self, "no 3GPP info given..."); + if (self->priv->current_operator_id || self->priv->current_operator_description) + operator_updated = TRUE; g_free (self->priv->current_operator_id); self->priv->current_operator_id = NULL; g_free (self->priv->current_operator_description); @@ -2638,6 +2550,10 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), reg_state_3gpp); mm_iface_modem_3gpp_update_access_technologies (MM_IFACE_MODEM_3GPP (self), MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), 0, 0, 0); + /* request to reload operator info explicitly, so that the new + * operator name and code is propagated to the DBus interface */ + if (operator_updated) + mm_iface_modem_3gpp_reload_current_registration_info (MM_IFACE_MODEM_3GPP (self), NULL, NULL); return; } @@ -2677,23 +2593,26 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, &mnc, &description, NULL))) { + gchar *new_operator_id; + /* When we don't have information about leading PCS digit, guess best */ - g_free (self->priv->current_operator_id); if (mnc >= 100) - self->priv->current_operator_id = - g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT, - mcc, - mnc); + new_operator_id = g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT, mcc, mnc); else - self->priv->current_operator_id = - g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.2" G_GUINT16_FORMAT, - mcc, - mnc); - - g_clear_pointer (&self->priv->current_operator_description, g_free); - /* Some Telit modems apparently sometimes report non-UTF8 characters */ - if (g_utf8_validate (description, -1, NULL)) + new_operator_id = g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.2" G_GUINT16_FORMAT, mcc, mnc); + + if (!self->priv->current_operator_id || !g_str_equal (self->priv->current_operator_id, new_operator_id)) { + operator_updated = TRUE; + g_free (self->priv->current_operator_id); + self->priv->current_operator_id = new_operator_id; + } else + g_free (new_operator_id); + + if (!self->priv->current_operator_description || !g_str_equal (self->priv->current_operator_description, description)) { + operator_updated = TRUE; + g_free (self->priv->current_operator_description); self->priv->current_operator_description = g_strdup (description); + } } /* If MNC comes with PCS digit, we must make sure the additional @@ -2713,18 +2632,35 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, &has_pcs_digit, NULL))) && has_pcs_digit) { - g_free (self->priv->current_operator_id); - self->priv->current_operator_id = - g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT, - mcc, - mnc); - } - - /* Report new registration states */ + gchar *new_operator_id; + + new_operator_id = g_strdup_printf ("%.3" G_GUINT16_FORMAT "%.3" G_GUINT16_FORMAT, mcc, mnc); + if (!self->priv->current_operator_id || !g_str_equal (self->priv->current_operator_id, new_operator_id)) { + operator_updated = TRUE; + g_free (self->priv->current_operator_id); + self->priv->current_operator_id = new_operator_id; + } else + g_free (new_operator_id); + } + + /* Report new registration states. The QMI serving system API reports "CS" + * and "PS" registration states, and if the device is in LTE, we'll take the "PS" + * one as "EPS". But, if the device is not in LTE, we should also set the "EPS" + * state as unknown, so that the "PS" one takes precedence when building + * the consolidated registration state (otherwise we may be using some old cached + * "EPS" state wrongly). */ mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), mm_cs_registration_state); mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), mm_ps_registration_state); - if (mm_access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE) - mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), mm_ps_registration_state); + if (mm_iface_modem_is_3gpp_lte (MM_IFACE_MODEM (self))) + mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), + (mm_access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE) ? + mm_ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); + /* Same thing for "5GS" state */ + if (mm_iface_modem_is_3gpp_5gnr (MM_IFACE_MODEM (self))) + mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), + (mm_access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_5GNR) ? + mm_ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); + /* Get 3GPP location LAC/TAC and CI */ lac = 0; @@ -2740,9 +2676,14 @@ common_process_serving_system_3gpp (MMBroadbandModemQmi *self, qmi_indication_nas_serving_system_output_get_cid_3gpp (indication_output, &cid, NULL); } /* Only update info in the interface if we get something */ - if (cid && (lac || tac)) + if (cid || lac || tac) mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), lac, tac, cid); + /* request to reload operator info explicitly, so that the new + * operator name and code is propagated to the DBus interface */ + if (operator_updated) + mm_iface_modem_3gpp_reload_current_registration_info (MM_IFACE_MODEM_3GPP (self), NULL, NULL); + /* Note: don't update access technologies with the ones retrieved here; they * are not really the 'current' access technologies */ } @@ -2781,7 +2722,7 @@ get_serving_system_3gpp_ready (QmiClientNas *client, qmi_message_nas_get_serving_system_output_unref (output); } -#if defined WITH_NEWEST_QMI_COMMANDS +#else /* WITH_NEWEST_QMI_COMMANDS */ static gboolean process_common_info (QmiNasServiceStatus service_status, @@ -2829,8 +2770,9 @@ process_common_info (QmiNasServiceStatus service_status, apply_ps = FALSE; else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_PS) apply_cs = FALSE; - else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS) + else if (domain == QMI_NAS_NETWORK_SERVICE_DOMAIN_CS_PS) { /* both apply */ ; + } /* Check if we really are roaming or forbidden */ if (forbidden_valid && forbidden) @@ -2859,7 +2801,7 @@ process_common_info (QmiNasServiceStatus service_status, if (network_id_valid) { *mm_operator_id = g_malloc (7); memcpy (*mm_operator_id, mcc, 3); - if (mnc[2] == 0xFF) { + if ((guint8)mnc[2] == 0xFF) { memcpy (&((*mm_operator_id)[3]), mnc, 2); (*mm_operator_id)[5] = '\0'; } else { @@ -2872,7 +2814,8 @@ process_common_info (QmiNasServiceStatus service_status, } static gboolean -process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, +process_gsm_info (MMBroadbandModemQmi *self, + QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *mm_cs_registration_state, MMModem3gppRegistrationState *mm_ps_registration_state, @@ -2912,7 +2855,11 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_message_nas_get_system_info_output_get_gsm_system_info_v2 ( +#else !qmi_message_nas_get_system_info_output_get_gsm_system_info ( +#endif response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -2925,7 +2872,7 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, NULL, /* egprs support */ NULL, NULL, /* dtm_support */ NULL)) { - mm_dbg ("No GSM service reported"); + mm_obj_dbg (self, "no GSM service reported"); /* No GSM service */ return FALSE; } @@ -2936,7 +2883,11 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_indication_nas_system_info_output_get_gsm_system_info_v2 ( +#else !qmi_indication_nas_system_info_output_get_gsm_system_info ( +#endif indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -2949,7 +2900,7 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, NULL, /* egprs support */ NULL, NULL, /* dtm_support */ NULL)) { - mm_dbg ("No GSM service reported"); + mm_obj_dbg (self, "no GSM service reported"); /* No GSM service */ return FALSE; } @@ -2969,7 +2920,7 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, mm_cid, mm_operator_id)) { - mm_dbg ("No GSM service registered"); + mm_obj_dbg (self, "no GSM service registered"); return FALSE; } @@ -2977,7 +2928,8 @@ process_gsm_info (QmiMessageNasGetSystemInfoOutput *response_output, } static gboolean -process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, +process_wcdma_info (MMBroadbandModemQmi *self, + QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *mm_cs_registration_state, MMModem3gppRegistrationState *mm_ps_registration_state, @@ -3019,7 +2971,11 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_message_nas_get_system_info_output_get_wcdma_system_info_v2 ( +#else !qmi_message_nas_get_system_info_output_get_wcdma_system_info ( +#endif response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -3033,7 +2989,7 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, &hs_service_valid, &hs_service, NULL, NULL, /* primary_scrambling_code */ NULL)) { - mm_dbg ("No WCDMA service reported"); + mm_obj_dbg (self, "no WCDMA service reported"); /* No GSM service */ return FALSE; } @@ -3044,7 +3000,11 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_indication_nas_system_info_output_get_wcdma_system_info_v2 ( +#else !qmi_indication_nas_system_info_output_get_wcdma_system_info ( +#endif indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -3058,7 +3018,7 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, &hs_service_valid, &hs_service, NULL, NULL, /* primary_scrambling_code */ NULL)) { - mm_dbg ("No WCDMA service reported"); + mm_obj_dbg (self, "no WCDMA service reported"); /* No GSM service */ return FALSE; } @@ -3078,7 +3038,7 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, mm_cid, mm_operator_id)) { - mm_dbg ("No WCDMA service registered"); + mm_obj_dbg (self, "no WCDMA service registered"); return FALSE; } @@ -3086,7 +3046,8 @@ process_wcdma_info (QmiMessageNasGetSystemInfoOutput *response_output, } static gboolean -process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, +process_lte_info (MMBroadbandModemQmi *self, + QmiMessageNasGetSystemInfoOutput *response_output, QmiIndicationNasSystemInfoOutput *indication_output, MMModem3gppRegistrationState *mm_cs_registration_state, MMModem3gppRegistrationState *mm_ps_registration_state, @@ -3130,7 +3091,11 @@ process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_message_nas_get_system_info_output_get_lte_system_info_v2 ( +#else !qmi_message_nas_get_system_info_output_get_lte_system_info ( +#endif response_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -3142,7 +3107,7 @@ process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL)) { - mm_dbg ("No LTE service reported"); + mm_obj_dbg (self, "no LTE service reported"); /* No GSM service */ return FALSE; } @@ -3153,7 +3118,12 @@ process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, NULL, /* true_service_status */ NULL, /* preferred_data_path */ NULL) || +#if QMI_CHECK_VERSION(1,29,2) + !qmi_indication_nas_system_info_output_get_lte_system_info_v2 ( +#else !qmi_indication_nas_system_info_output_get_lte_system_info ( +#endif + indication_output, &domain_valid, &domain, NULL, NULL, /* service_capability */ @@ -3165,7 +3135,7 @@ process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, &network_id_valid, &mcc, &mnc, &tac_valid, &tac, NULL)) { - mm_dbg ("No LTE service reported"); + mm_obj_dbg (self, "no LTE service reported"); /* No GSM service */ return FALSE; } @@ -3185,7 +3155,7 @@ process_lte_info (QmiMessageNasGetSystemInfoOutput *response_output, mm_tac, mm_cid, mm_operator_id)) { - mm_dbg ("No LTE service registered"); + mm_obj_dbg (self, "no LTE service registered"); return FALSE; } @@ -3216,7 +3186,7 @@ common_process_system_info_3gpp (MMBroadbandModemQmi *self, * LTE > WCDMA > GSM * The first one giving results will be the one reported. */ - has_lte_info = process_lte_info (response_output, indication_output, + has_lte_info = process_lte_info (self, response_output, indication_output, &cs_registration_state, &ps_registration_state, &lac, @@ -3224,19 +3194,19 @@ common_process_system_info_3gpp (MMBroadbandModemQmi *self, &cid, &operator_id); if (!has_lte_info && - !process_wcdma_info (response_output, indication_output, + !process_wcdma_info (self, response_output, indication_output, &cs_registration_state, &ps_registration_state, &lac, &cid, &operator_id) && - !process_gsm_info (response_output, indication_output, + !process_gsm_info (self, response_output, indication_output, &cs_registration_state, &ps_registration_state, &lac, &cid, &operator_id)) { - mm_dbg ("No service (GSM, WCDMA or LTE) reported"); + mm_obj_dbg (self, "no service (GSM, WCDMA or LTE) reported"); } /* Cache current operator ID */ @@ -3290,12 +3260,13 @@ get_system_info_ready (QmiClientNas *client, #endif /* WITH_NEWEST_QMI_COMMANDS */ static void -modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, - GAsyncReadyCallback callback, - gpointer user_data) +modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, + gboolean is_cs_supported, + gboolean is_ps_supported, + gboolean is_eps_supported, + gboolean is_5gs_supported, + GAsyncReadyCallback callback, + gpointer user_data) { GTask *task; QmiClient *client = NULL; @@ -3308,24 +3279,20 @@ modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, task = g_task_new (self, NULL, callback, user_data); #if defined WITH_NEWEST_QMI_COMMANDS - /* System Info was added in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { - qmi_client_nas_get_system_info (QMI_CLIENT_NAS (client), - NULL, - 10, - NULL, - (GAsyncReadyCallback)get_system_info_ready, - task); - return; - } -#endif /* WITH_NEWEST_QMI_COMMANDS */ - + qmi_client_nas_get_system_info (QMI_CLIENT_NAS (client), + NULL, + 10, + NULL, + (GAsyncReadyCallback)get_system_info_ready, + task); +#else qmi_client_nas_get_serving_system (QMI_CLIENT_NAS (client), NULL, 10, NULL, (GAsyncReadyCallback)get_serving_system_3gpp_ready, task); +#endif /* WITH_NEWEST_QMI_COMMANDS */ } /*****************************************************************************/ @@ -3364,9 +3331,9 @@ unsolicited_registration_events_task_new (MMBroadbandModemQmi *self, } static gboolean -modem_3gpp_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) +modem_3gpp_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } @@ -3374,39 +3341,41 @@ modem_3gpp_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3g static void ri_serving_system_or_system_info_ready (QmiClientNas *client, GAsyncResult *res, - GTask *task) + GTask *task) { - MMBroadbandModemQmi *self; - UnsolicitedRegistrationEventsContext *ctx; - QmiMessageNasRegisterIndicationsOutput *output = NULL; - GError *error = NULL; + MMBroadbandModemQmi *self; + UnsolicitedRegistrationEventsContext *ctx; + g_autoptr(QmiMessageNasRegisterIndicationsOutput) output = NULL; + g_autoptr(GError) error = NULL; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); + ctx = g_task_get_task_data (task); output = qmi_client_nas_register_indications_finish (client, res, &error); - if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); - g_error_free (error); - } else if (!qmi_message_nas_register_indications_output_get_result (output, &error)) { - mm_dbg ("Couldn't register indications: '%s'", error->message); - g_error_free (error); + if (!output || !qmi_message_nas_register_indications_output_get_result (output, &error)) { + mm_obj_dbg (self, "couldn't register indications: '%s'", error->message); + if (ctx->enable) { +#if defined WITH_NEWEST_QMI_COMMANDS + mm_obj_dbg (self, "assuming system info indications are always enabled"); +#else + mm_obj_dbg (self, "assuming serving system indications are always enabled"); +#endif + } } - if (output) - qmi_message_nas_register_indications_output_unref (output); - /* Just ignore errors for now */ self->priv->unsolicited_registration_events_enabled = ctx->enable; g_task_return_boolean (task, TRUE); g_object_unref (task); } +#if !defined WITH_NEWEST_QMI_COMMANDS + static void common_enable_disable_unsolicited_registration_events_serving_system (GTask *task) { - UnsolicitedRegistrationEventsContext *ctx; - QmiMessageNasRegisterIndicationsInput *input; + UnsolicitedRegistrationEventsContext *ctx; + g_autoptr(QmiMessageNasRegisterIndicationsInput) input = NULL; ctx = g_task_get_task_data (task); input = qmi_message_nas_register_indications_input_new (); @@ -3418,15 +3387,15 @@ common_enable_disable_unsolicited_registration_events_serving_system (GTask *tas NULL, (GAsyncReadyCallback)ri_serving_system_or_system_info_ready, task); - qmi_message_nas_register_indications_input_unref (input); } -#if defined WITH_NEWEST_QMI_COMMANDS +#else /* WITH_NEWEST_QMI_COMMANDS */ + static void common_enable_disable_unsolicited_registration_events_system_info (GTask *task) { - UnsolicitedRegistrationEventsContext *ctx; - QmiMessageNasRegisterIndicationsInput *input; + UnsolicitedRegistrationEventsContext *ctx; + g_autoptr(QmiMessageNasRegisterIndicationsInput) input = NULL; ctx = g_task_get_task_data (task); input = qmi_message_nas_register_indications_input_new (); @@ -3438,20 +3407,19 @@ common_enable_disable_unsolicited_registration_events_system_info (GTask *task) NULL, (GAsyncReadyCallback)ri_serving_system_or_system_info_ready, task); - qmi_message_nas_register_indications_input_unref (input); } + #endif /* WITH_NEWEST_QMI_COMMANDS */ static void -modem_3gpp_disable_unsolicited_registration_events (MMIfaceModem3gpp *_self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, - GAsyncReadyCallback callback, - gpointer user_data) +modem_3gpp_disable_unsolicited_registration_events (MMIfaceModem3gpp *self, + gboolean cs_supported, + gboolean ps_supported, + gboolean eps_supported, + GAsyncReadyCallback callback, + gpointer user_data) { - MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); - GTask *task; + GTask *task; QmiClient *client = NULL; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), @@ -3459,46 +3427,28 @@ modem_3gpp_disable_unsolicited_registration_events (MMIfaceModem3gpp *_self, callback, user_data)) return; - task = unsolicited_registration_events_task_new (self, + task = unsolicited_registration_events_task_new (MM_BROADBAND_MODEM_QMI (self), client, FALSE, callback, user_data); #if defined WITH_NEWEST_QMI_COMMANDS - /* System Info was added in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { - common_enable_disable_unsolicited_registration_events_system_info (task); - return; - } + common_enable_disable_unsolicited_registration_events_system_info (task); +#else + common_enable_disable_unsolicited_registration_events_serving_system (task); #endif /* WITH_NEWEST_QMI_COMMANDS */ - - /* Ability to explicitly enable/disable serving system indications was - * added in NAS 1.2 */ - if (qmi_client_check_version (client, 1, 2)) { - common_enable_disable_unsolicited_registration_events_serving_system (task); - return; - } - - /* Devices with NAS < 1.2 will just always issue serving system indications */ - self->priv->unsolicited_registration_events_enabled = FALSE; - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Device doesn't allow disabling registration events"); - g_object_unref (task); } static void -modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *_self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, - GAsyncReadyCallback callback, - gpointer user_data) +modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *self, + gboolean cs_supported, + gboolean ps_supported, + gboolean eps_supported, + GAsyncReadyCallback callback, + gpointer user_data) { - MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); - GTask *task; + GTask *task; QmiClient *client = NULL; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), @@ -3506,24 +3456,17 @@ modem_3gpp_enable_unsolicited_registration_events (MMIfaceModem3gpp *_self, callback, user_data)) return; - task = unsolicited_registration_events_task_new (self, + task = unsolicited_registration_events_task_new (MM_BROADBAND_MODEM_QMI (self), client, TRUE, callback, user_data); - /* Ability to explicitly enable/disable serving system indications was - * added in NAS 1.2 */ - if (qmi_client_check_version (client, 1, 2)) { - common_enable_disable_unsolicited_registration_events_serving_system (task); - return; - } - - /* Devices with NAS < 1.2 will just always issue serving system indications */ - mm_dbg ("Assuming serving system indications are always enabled"); - self->priv->unsolicited_registration_events_enabled = TRUE; - g_task_return_boolean (task, TRUE); - g_object_unref (task); +#if defined WITH_NEWEST_QMI_COMMANDS + common_enable_disable_unsolicited_registration_events_system_info (task); +#else + common_enable_disable_unsolicited_registration_events_serving_system (task); +#endif /* WITH_NEWEST_QMI_COMMANDS */ } /*****************************************************************************/ @@ -3595,9 +3538,9 @@ common_process_serving_system_cdma (MMBroadbandModemQmi *self, if (selected_network == QMI_NAS_NETWORK_TYPE_3GPP2 || (selected_network == QMI_NAS_NETWORK_TYPE_UNKNOWN && (mm_access_technologies & MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK))) { - mm_dbg ("Processing CDMA info..."); + mm_obj_dbg (self, "processing CDMA info..."); } else { - mm_dbg ("No CDMA info given..."); + mm_obj_dbg (self, "no CDMA info given..."); mm_iface_modem_cdma_update_cdma1x_registration_state (MM_IFACE_MODEM_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN, 0, 0); @@ -3966,13 +3909,15 @@ activate_manual_get_msisdn_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; CdmaActivationContext *ctx; QmiMessageDmsGetMsisdnOutput *output = NULL; GError *error = NULL; const gchar *current_mdn = NULL; const gchar *expected_mdn = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); qmi_message_dms_activate_manual_input_get_info (ctx->input_manual, NULL, /* spc */ @@ -3986,7 +3931,7 @@ activate_manual_get_msisdn_ready (QmiClientDms *client, qmi_message_dms_get_msisdn_output_get_result (output, NULL) && qmi_message_dms_get_msisdn_output_get_msisdn (output, ¤t_mdn, NULL) && g_str_equal (current_mdn, expected_mdn)) { - mm_dbg ("MDN successfully updated to '%s'", expected_mdn); + mm_obj_dbg (self, "MDN successfully updated to '%s'", expected_mdn); qmi_message_dms_get_msisdn_output_unref (output); /* And go on to next step */ ctx->step++; @@ -3999,7 +3944,7 @@ activate_manual_get_msisdn_ready (QmiClientDms *client, if (ctx->n_mdn_check_retries < MAX_MDN_CHECK_RETRIES) { /* Retry after some time */ - mm_dbg ("MDN not yet updated, retrying..."); + mm_obj_dbg (self, "MDN not yet updated, retrying..."); g_timeout_add (1, (GSourceFunc) retry_msisdn_check_cb, task); return; } @@ -4025,15 +3970,15 @@ activation_event_report_indication_cb (QmiClientDms *client, if (!qmi_indication_dms_event_report_output_get_activation_state (output, &state, NULL)) return; - mm_dbg ("Activation state update: '%s'", + mm_obj_dbg (self, "activation state update: '%s'", qmi_dms_activation_state_get_string (state)); new = mm_modem_cdma_activation_state_from_qmi_activation_state (state); if (self->priv->activation_state != new) - mm_info ("Activation state changed: '%s'-->'%s'", - mm_modem_cdma_activation_state_get_string (self->priv->activation_state), - mm_modem_cdma_activation_state_get_string (new)); + mm_obj_info (self, "activation state changed: '%s'-->'%s'", + mm_modem_cdma_activation_state_get_string (self->priv->activation_state), + mm_modem_cdma_activation_state_get_string (new)); /* Cache the new value */ self->priv->activation_state = new; @@ -4073,7 +4018,7 @@ activation_event_report_indication_cb (QmiClientDms *client, return; } - mm_dbg ("Activation process still ongoing..."); + mm_obj_dbg (self, "activation process still ongoing..."); } static void @@ -4218,8 +4163,7 @@ cdma_activation_context_step (GTask *task) if (ctx->input_automatic) { QmiMessageDmsSetEventReportInput *input; - mm_info ("Activation step [1/5]: enabling indications"); - + mm_obj_info (ctx->self, "activation step [1/5]: enabling indications"); input = qmi_message_dms_set_event_report_input_new (); qmi_message_dms_set_event_report_input_set_activation_state_reporting (input, TRUE, NULL); qmi_client_dms_set_event_report ( @@ -4235,15 +4179,14 @@ cdma_activation_context_step (GTask *task) /* Manual activation, no indications needed */ g_assert (ctx->input_manual != NULL); - mm_info ("Activation step [1/5]: indications not needed in manual activation"); + mm_obj_info (ctx->self, "activation step [1/5]: indications not needed in manual activation"); ctx->step++; /* Fall through */ case CDMA_ACTIVATION_STEP_REQUEST_ACTIVATION: /* Automatic activation */ if (ctx->input_automatic) { - mm_info ("Activation step [2/5]: requesting automatic (OTA) activation"); - + mm_obj_info (ctx->self, "activation step [2/5]: requesting automatic (OTA) activation"); qmi_client_dms_activate_automatic (ctx->client, ctx->input_automatic, 10, @@ -4256,10 +4199,10 @@ cdma_activation_context_step (GTask *task) /* Manual activation */ g_assert (ctx->input_manual != NULL); if (!ctx->segments) - mm_info ("Activation step [2/5]: requesting manual activation"); + mm_obj_info (ctx->self, "activation step [2/5]: requesting manual activation"); else { - mm_info ("Activation step [2/5]: requesting manual activation (PRL segment %u/%u)", - (ctx->segment_i + 1), ctx->n_segments); + mm_obj_info (ctx->self, "activation step [2/5]: requesting manual activation (PRL segment %u/%u)", + (ctx->segment_i + 1), ctx->n_segments); qmi_message_dms_activate_manual_input_set_prl ( ctx->input_manual, (guint16)ctx->total_segments_size, @@ -4280,14 +4223,14 @@ cdma_activation_context_step (GTask *task) /* Automatic activation */ if (ctx->input_automatic) { /* State updates via unsolicited messages */ - mm_info ("Activation step [3/5]: waiting for activation state updates"); + mm_obj_info (ctx->self, "activation step [3/5]: waiting for activation state updates"); return; } /* Manual activation; needs MSISDN checks */ g_assert (ctx->input_manual != NULL); ctx->n_mdn_check_retries++; - mm_info ("Activation step [3/5]: checking MDN update (retry %u)", ctx->n_mdn_check_retries); + mm_obj_info (ctx->self, "activation step [3/5]: checking MDN update (retry %u)", ctx->n_mdn_check_retries); qmi_client_dms_get_msisdn (ctx->client, NULL, 5, @@ -4297,14 +4240,14 @@ cdma_activation_context_step (GTask *task) return; case CDMA_ACTIVATION_STEP_RESET: - mm_info ("Activation step [4/5]: power-cycling..."); + mm_obj_info (ctx->self, "activation step [4/5]: power-cycling..."); mm_shared_qmi_reset (MM_IFACE_MODEM (ctx->self), (GAsyncReadyCallback)activation_reset_ready, task); return; case CDMA_ACTIVATION_STEP_LAST: - mm_info ("Activation step [5/5]: finished"); + mm_obj_info (ctx->self, "activation step [5/5]: finished"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -4488,7 +4431,8 @@ system_info_indication_cb (QmiClientNas *client, if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) common_process_system_info_3gpp (self, NULL, output); } -#endif + +#else /* WITH_NEWEST_QMI_COMMANDS */ static void serving_system_indication_cb (QmiClientNas *client, @@ -4501,6 +4445,8 @@ serving_system_indication_cb (QmiClientNas *client, common_process_serving_system_cdma (self, NULL, output); } +#endif + static void common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, gboolean enable, @@ -4518,7 +4464,7 @@ common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->unsolicited_registration_events_setup) { - mm_dbg ("Unsolicited registration events already %s; skipping", + mm_obj_dbg (self, "unsolicited registration events already %s; skipping", enable ? "setup" : "cleanup"); g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -4529,38 +4475,34 @@ common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, self->priv->unsolicited_registration_events_setup = enable; #if defined WITH_NEWEST_QMI_COMMANDS - /* Signal info introduced in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { - /* Connect/Disconnect "System Info" indications */ - if (enable) { - g_assert (self->priv->system_info_indication_id == 0); - self->priv->system_info_indication_id = - g_signal_connect (client, - "system-info", - G_CALLBACK (system_info_indication_cb), - self); - } else { - g_assert (self->priv->system_info_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->system_info_indication_id); - self->priv->system_info_indication_id = 0; - } - } else -#endif /* WITH_NEWEST_QMI_COMMANDS */ - { - /* Connect/Disconnect "Serving System" indications */ - if (enable) { - g_assert (self->priv->serving_system_indication_id == 0); - self->priv->serving_system_indication_id = - g_signal_connect (client, - "serving-system", - G_CALLBACK (serving_system_indication_cb), - self); - } else { - g_assert (self->priv->serving_system_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->serving_system_indication_id); - self->priv->serving_system_indication_id = 0; - } + /* Connect/Disconnect "System Info" indications */ + if (enable) { + g_assert (self->priv->system_info_indication_id == 0); + self->priv->system_info_indication_id = + g_signal_connect (client, + "system-info", + G_CALLBACK (system_info_indication_cb), + self); + } else { + g_assert (self->priv->system_info_indication_id != 0); + g_signal_handler_disconnect (client, self->priv->system_info_indication_id); + self->priv->system_info_indication_id = 0; } +#else + /* Connect/Disconnect "Serving System" indications */ + if (enable) { + g_assert (self->priv->serving_system_indication_id == 0); + self->priv->serving_system_indication_id = + g_signal_connect (client, + "serving-system", + G_CALLBACK (serving_system_indication_cb), + self); + } else { + g_assert (self->priv->serving_system_indication_id != 0); + g_signal_handler_disconnect (client, self->priv->serving_system_indication_id); + self->priv->serving_system_indication_id = 0; + } +#endif /* WITH_NEWEST_QMI_COMMANDS */ g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -4662,175 +4604,204 @@ modem_cdma_load_esn (MMIfaceModemCdma *_self, } /*****************************************************************************/ -/* Enabling/disabling unsolicited events (3GPP and CDMA interface) - * - * If NAS >= 1.8: - * - Config Signal Info (only when enabling) - * - Register Indications with Signal Info - * - * If NAS < 1.8: - * - Set Event Report with Signal Strength - */ +/* Enabling/disabling unsolicited events (3GPP and CDMA interface) */ typedef struct { - QmiClientNas *client; - gboolean enable; + QmiClientNas *client_nas; + QmiClientWds *client_wds; + gboolean enable; } EnableUnsolicitedEventsContext; static void enable_unsolicited_events_context_free (EnableUnsolicitedEventsContext *ctx) { - g_object_unref (ctx->client); + g_clear_object (&ctx->client_wds); + g_clear_object (&ctx->client_nas); g_free (ctx); } static gboolean -common_enable_disable_unsolicited_events_finish (MMBroadbandModemQmi *self, - GAsyncResult *res, - GError **error) +common_enable_disable_unsolicited_events_finish (MMBroadbandModemQmi *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void -ser_signal_strength_ready (QmiClientNas *client, - GAsyncResult *res, - GTask *task) +ser_data_system_status_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) { - MMBroadbandModemQmi *self; - EnableUnsolicitedEventsContext *ctx; - QmiMessageNasSetEventReportOutput *output = NULL; - GError *error = NULL; + MMBroadbandModemQmi *self; + g_autoptr(QmiMessageWdsSetEventReportOutput) output = NULL; + g_autoptr(GError) error = NULL; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - output = qmi_client_nas_set_event_report_finish (client, res, &error); - if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); - g_error_free (error); - } else if (!qmi_message_nas_set_event_report_output_get_result (output, &error)) { - mm_dbg ("Couldn't set event report: '%s'", error->message); - g_error_free (error); - } - if (output) - qmi_message_nas_set_event_report_output_unref (output); + output = qmi_client_wds_set_event_report_finish (client, res, &error); + if (!output || !qmi_message_wds_set_event_report_output_get_result (output, &error)) + mm_obj_dbg (self, "couldn't set event report: '%s'", error->message); - /* Just ignore errors for now */ - self->priv->unsolicited_events_enabled = ctx->enable; g_task_return_boolean (task, TRUE); g_object_unref (task); } static void -common_enable_disable_unsolicited_events_signal_strength (GTask *task) +common_enable_disable_unsolicited_events_data_system_status (GTask *task) { - EnableUnsolicitedEventsContext *ctx; + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageWdsSetEventReportInput) input = NULL; - /* The device doesn't really like to have many threshold values, so don't - * grow this array without checking first */ - static const gint8 thresholds_data[] = { -80, -40, 0, 40, 80 }; - QmiMessageNasSetEventReportInput *input; - GArray *thresholds; + ctx = g_task_get_task_data (task); - ctx = g_task_get_task_data (task); - input = qmi_message_nas_set_event_report_input_new (); + input = qmi_message_wds_set_event_report_input_new (); + qmi_message_wds_set_event_report_input_set_data_systems (input, ctx->enable, NULL); + qmi_client_wds_set_event_report (ctx->client_wds, + input, + 5, + NULL, + (GAsyncReadyCallback)ser_data_system_status_ready, + task); +} - /* Prepare thresholds, separated 20 each */ - thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data)); +#if !defined WITH_NEWEST_QMI_COMMANDS - /* Only set thresholds during enable */ - if (ctx->enable) - g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data)); +static void +ser_signal_strength_ready (QmiClientNas *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageNasSetEventReportOutput) output = NULL; + g_autoptr(GError) error = NULL; - qmi_message_nas_set_event_report_input_set_signal_strength_indicator ( - input, - ctx->enable, + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_nas_set_event_report_finish (client, res, &error); + if (!output || !qmi_message_nas_set_event_report_output_get_result (output, &error)) + mm_obj_dbg (self, "couldn't enable signal strength indications: '%s'", error->message); + else { + /* Disable access technology and signal quality polling if we can use the indications */ + mm_obj_dbg (self, "signal strength indications enabled: polling disabled"); + g_object_set (self, + MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE, + MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, TRUE, + NULL); + } + + if (!ctx->client_wds) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + common_enable_disable_unsolicited_events_data_system_status (task); +} + +static void +common_enable_disable_unsolicited_events_signal_strength (GTask *task) +{ + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageNasSetEventReportInput) input = NULL; + g_autoptr(GArray) thresholds = NULL; + + /* The device doesn't really like to have many threshold values, so don't + * grow this array without checking first */ + static const gint8 thresholds_data[] = { -80, -40, 0, 40, 80 }; + + ctx = g_task_get_task_data (task); + + /* Always set thresholds, both in enable and disable, or otherwise the protocol will + * complain with FAILURE: NoThresholdsProvided */ + thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data)); + g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data)); + + input = qmi_message_nas_set_event_report_input_new (); + qmi_message_nas_set_event_report_input_set_signal_strength_indicator ( + input, + ctx->enable, thresholds, NULL); - g_array_unref (thresholds); qmi_client_nas_set_event_report ( - ctx->client, + ctx->client_nas, input, 5, NULL, (GAsyncReadyCallback)ser_signal_strength_ready, task); - qmi_message_nas_set_event_report_input_unref (input); } -#if defined WITH_NEWEST_QMI_COMMANDS +#else /* WITH_NEWEST_QMI_COMMANDS */ static void ri_signal_info_ready (QmiClientNas *client, GAsyncResult *res, - GTask *task) + GTask *task) { - MMBroadbandModemQmi *self; - EnableUnsolicitedEventsContext *ctx; - QmiMessageNasRegisterIndicationsOutput *output = NULL; - GError *error = NULL; + MMBroadbandModemQmi *self; + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageNasRegisterIndicationsOutput) output = NULL; + g_autoptr(GError) error = NULL; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); + ctx = g_task_get_task_data (task); output = qmi_client_nas_register_indications_finish (client, res, &error); - if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); - g_error_free (error); - } else if (!qmi_message_nas_register_indications_output_get_result (output, &error)) { - mm_dbg ("Couldn't register indications: '%s'", error->message); - g_error_free (error); + if (!output || !qmi_message_nas_register_indications_output_get_result (output, &error)) + mm_obj_dbg (self, "couldn't register signal info indications: '%s'", error->message); + else { + /* Disable access technology and signal quality polling if we can use the indications */ + mm_obj_dbg (self, "signal strength indications enabled: polling disabled"); + g_object_set (self, + MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE, + MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, TRUE, + NULL); } - if (output) - qmi_message_nas_register_indications_output_unref (output); + if (!ctx->client_wds) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } - /* Just ignore errors for now */ - self->priv->unsolicited_events_enabled = ctx->enable; - g_task_return_boolean (task, TRUE); - g_object_unref (task); + common_enable_disable_unsolicited_events_data_system_status (task); } static void common_enable_disable_unsolicited_events_signal_info (GTask *task) { - EnableUnsolicitedEventsContext *ctx; - QmiMessageNasRegisterIndicationsInput *input; + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageNasRegisterIndicationsInput) input = NULL; ctx = g_task_get_task_data (task); input = qmi_message_nas_register_indications_input_new (); qmi_message_nas_register_indications_input_set_signal_info (input, ctx->enable, NULL); qmi_client_nas_register_indications ( - ctx->client, + ctx->client_nas, input, 5, NULL, (GAsyncReadyCallback)ri_signal_info_ready, task); - qmi_message_nas_register_indications_input_unref (input); } static void config_signal_info_ready (QmiClientNas *client, GAsyncResult *res, - GTask *task) + GTask *task) { - QmiMessageNasConfigSignalInfoOutput *output = NULL; - GError *error = NULL; + MMBroadbandModemQmi *self; + g_autoptr(QmiMessageNasConfigSignalInfoOutput) output = NULL; + g_autoptr(GError) error = NULL; - output = qmi_client_nas_config_signal_info_finish (client, res, &error); - if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); - g_error_free (error); - } else if (!qmi_message_nas_config_signal_info_output_get_result (output, &error)) { - mm_dbg ("Couldn't config signal info: '%s'", error->message); - g_error_free (error); - } + self = g_task_get_source_object (task); - if (output) - qmi_message_nas_config_signal_info_output_unref (output); + output = qmi_client_nas_config_signal_info_finish (client, res, &error); + if (!output || !qmi_message_nas_config_signal_info_output_get_result (output, &error)) + mm_obj_dbg (self, "couldn't config signal info: '%s'", error->message); /* Keep on */ common_enable_disable_unsolicited_events_signal_info (task); @@ -4839,12 +4810,8 @@ config_signal_info_ready (QmiClientNas *client, static void common_enable_disable_unsolicited_events_signal_info_config (GTask *task) { - EnableUnsolicitedEventsContext *ctx; - /* RSSI values go between -105 and -60 for 3GPP technologies, - * and from -105 to -90 in 3GPP2 technologies (approx). */ - static const gint8 thresholds_data[] = { -100, -97, -95, -92, -90, -85, -80, -75, -70, -65 }; - QmiMessageNasConfigSignalInfoInput *input; - GArray *thresholds; + EnableUnsolicitedEventsContext *ctx; + g_autoptr(QmiMessageNasConfigSignalInfoInput) input = NULL; ctx = g_task_get_task_data (task); @@ -4857,65 +4824,85 @@ common_enable_disable_unsolicited_events_signal_info_config (GTask *task) input = qmi_message_nas_config_signal_info_input_new (); /* Prepare thresholds, separated 20 each */ - thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data)); - g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data)); + { + /* RSSI values go between -105 and -60 for 3GPP technologies, + * and from -105 to -90 in 3GPP2 technologies (approx). */ + static const gint8 thresholds_data[] = { -100, -97, -95, -92, -90, -85, -80, -75, -70, -65 }; + g_autoptr(GArray) thresholds = NULL; + + thresholds = g_array_sized_new (FALSE, FALSE, sizeof (gint8), G_N_ELEMENTS (thresholds_data)); + g_array_append_vals (thresholds, thresholds_data, G_N_ELEMENTS (thresholds_data)); + qmi_message_nas_config_signal_info_input_set_rssi_threshold ( + input, + thresholds, + NULL); + } - qmi_message_nas_config_signal_info_input_set_rssi_threshold ( - input, - thresholds, - NULL); - g_array_unref (thresholds); qmi_client_nas_config_signal_info ( - ctx->client, + ctx->client_nas, input, 5, NULL, (GAsyncReadyCallback)config_signal_info_ready, task); - qmi_message_nas_config_signal_info_input_unref (input); } #endif /* WITH_NEWEST_QMI_COMMANDS */ static void common_enable_disable_unsolicited_events (MMBroadbandModemQmi *self, - gboolean enable, - GAsyncReadyCallback callback, - gpointer user_data) + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) { EnableUnsolicitedEventsContext *ctx; - GTask *task; - QmiClient *client = NULL; - - if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_NAS, &client, - callback, user_data)) - return; + GTask *task; + QmiClient *client_nas = NULL; + QmiClient *client_wds = NULL; task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->unsolicited_events_enabled) { - mm_dbg ("Unsolicited events already %s; skipping", - enable ? "enabled" : "disabled"); + mm_obj_dbg (self, "unsolicited events already %s; skipping", + enable ? "enabled" : "disabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } + self->priv->unsolicited_events_enabled = enable; + + client_nas = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_NAS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + client_wds = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_WDS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); ctx = g_new0 (EnableUnsolicitedEventsContext, 1); - ctx->client = g_object_ref (client); + ctx->enable = enable; + ctx->client_nas = client_nas ? g_object_ref (client_nas) : NULL; + ctx->client_wds = client_wds ? g_object_ref (client_wds) : NULL; g_task_set_task_data (task, ctx, (GDestroyNotify)enable_unsolicited_events_context_free); + if (ctx->client_nas) { #if defined WITH_NEWEST_QMI_COMMANDS - /* Signal info introduced in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { common_enable_disable_unsolicited_events_signal_info_config (task); +#else + common_enable_disable_unsolicited_events_signal_strength (task); +#endif /* WITH_NEWEST_QMI_COMMANDS */ return; } -#endif /* WITH_NEWEST_QMI_COMMANDS */ - common_enable_disable_unsolicited_events_signal_strength (task); + if (ctx->client_wds) { + common_enable_disable_unsolicited_events_data_system_status (task); + return; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /*****************************************************************************/ @@ -4996,9 +4983,26 @@ common_setup_cleanup_unsolicited_events_finish (MMBroadbandModemQmi *self, } static void -event_report_indication_cb (QmiClientNas *client, - QmiIndicationNasEventReportOutput *output, - MMBroadbandModemQmi *self) +wds_event_report_indication_cb (QmiClientWds *client, + QmiIndicationWdsEventReportOutput *output, + MMBroadbandModemQmi *self) +{ + QmiWdsDataSystemNetworkType preferred_network; + + if (qmi_indication_wds_event_report_output_get_data_systems (output, &preferred_network, NULL, NULL)) { + mm_obj_dbg (self, "data systems update, preferred network: %s", + qmi_wds_data_system_network_type_get_string (preferred_network)); + if (preferred_network == QMI_WDS_DATA_SYSTEM_NETWORK_TYPE_3GPP) + mm_iface_modem_3gpp_reload_initial_eps_bearer (MM_IFACE_MODEM_3GPP (self)); + else + mm_iface_modem_3gpp_update_initial_eps_bearer (MM_IFACE_MODEM_3GPP (self), NULL); + } +} + +static void +nas_event_report_indication_cb (QmiClientNas *client, + QmiIndicationNasEventReportOutput *output, + MMBroadbandModemQmi *self) { gint8 signal_strength; QmiNasRadioInterface signal_strength_radio_interface; @@ -5014,10 +5018,10 @@ event_report_indication_cb (QmiClientNas *client, /* This signal strength comes as negative dBms */ quality = STRENGTH_TO_QUALITY (signal_strength); - mm_dbg ("Signal strength indication (%s): %d dBm --> %u%%", - qmi_nas_radio_interface_get_string (signal_strength_radio_interface), - signal_strength, - quality); + mm_obj_dbg (self, "signal strength indication (%s): %d dBm --> %u%%", + qmi_nas_radio_interface_get_string (signal_strength_radio_interface), + signal_strength, + quality); mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality); mm_iface_modem_update_access_technologies ( @@ -5025,9 +5029,9 @@ event_report_indication_cb (QmiClientNas *client, mm_modem_access_technology_from_qmi_radio_interface (signal_strength_radio_interface), (MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK | MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK)); } else { - mm_dbg ("Ignoring invalid signal strength (%s): %d dBm", - qmi_nas_radio_interface_get_string (signal_strength_radio_interface), - signal_strength); + mm_obj_dbg (self, "ignoring invalid signal strength (%s): %d dBm", + qmi_nas_radio_interface_get_string (signal_strength_radio_interface), + signal_strength); } } } @@ -5035,9 +5039,9 @@ event_report_indication_cb (QmiClientNas *client, #if defined WITH_NEWEST_QMI_COMMANDS static void -signal_info_indication_cb (QmiClientNas *client, - QmiIndicationNasSignalInfoOutput *output, - MMBroadbandModemQmi *self) +nas_signal_info_indication_cb (QmiClientNas *client, + QmiIndicationNasSignalInfoOutput *output, + MMBroadbandModemQmi *self) { gint8 cdma1x_rssi = 0; gint8 evdo_rssi = 0; @@ -5053,7 +5057,8 @@ signal_info_indication_cb (QmiClientNas *client, qmi_indication_nas_signal_info_output_get_wcdma_signal_strength (output, &wcdma_rssi, NULL, NULL); qmi_indication_nas_signal_info_output_get_lte_signal_strength (output, <e_rssi, NULL, NULL, NULL, NULL); - if (common_signal_info_get_quality (cdma1x_rssi, + if (common_signal_info_get_quality (self, + cdma1x_rssi, evdo_rssi, gsm_rssi, wcdma_rssi, @@ -5076,59 +5081,72 @@ common_setup_cleanup_unsolicited_events (MMBroadbandModemQmi *self, GAsyncReadyCallback callback, gpointer user_data) { - GTask *task; - QmiClient *client = NULL; - - if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_NAS, &client, - callback, user_data)) - return; + GTask *task; + QmiClient *client_nas = NULL; + QmiClient *client_wds = NULL; task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->unsolicited_events_setup) { - mm_dbg ("Unsolicited events already %s; skipping", - enable ? "setup" : "cleanup"); + mm_obj_dbg (self, "unsolicited events already %s; skipping", + enable ? "setup" : "cleanup"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - - /* Store new state */ self->priv->unsolicited_events_setup = enable; + client_nas = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_NAS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + client_wds = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_WDS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + /* Connect/Disconnect "Event Report" indications */ - if (enable) { - g_assert (self->priv->event_report_indication_id == 0); - self->priv->event_report_indication_id = - g_signal_connect (client, - "event-report", - G_CALLBACK (event_report_indication_cb), - self); - } else { - g_assert (self->priv->event_report_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->event_report_indication_id); - self->priv->event_report_indication_id = 0; - } + if (client_nas) { + if (enable) { + g_assert (self->priv->nas_event_report_indication_id == 0); + self->priv->nas_event_report_indication_id = + g_signal_connect (client_nas, + "event-report", + G_CALLBACK (nas_event_report_indication_cb), + self); + } else if (self->priv->nas_event_report_indication_id != 0) { + g_signal_handler_disconnect (client_nas, self->priv->nas_event_report_indication_id); + self->priv->nas_event_report_indication_id = 0; + } #if defined WITH_NEWEST_QMI_COMMANDS - /* Connect/Disconnect "Signal Info" indications. - * Signal info introduced in NAS 1.8 */ - if (qmi_client_check_version (client, 1, 8)) { if (enable) { - g_assert (self->priv->signal_info_indication_id == 0); - self->priv->signal_info_indication_id = - g_signal_connect (client, + g_assert (self->priv->nas_signal_info_indication_id == 0); + self->priv->nas_signal_info_indication_id = + g_signal_connect (client_nas, "signal-info", - G_CALLBACK (signal_info_indication_cb), + G_CALLBACK (nas_signal_info_indication_cb), self); - } else { - g_assert (self->priv->signal_info_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->signal_info_indication_id); - self->priv->signal_info_indication_id = 0; + } else if (self->priv->nas_signal_info_indication_id != 0) { + g_signal_handler_disconnect (client_nas, self->priv->nas_signal_info_indication_id); + self->priv->nas_signal_info_indication_id = 0; } - } #endif /* WITH_NEWEST_QMI_COMMANDS */ + } + + if (client_wds) { + if (enable) { + g_assert (self->priv->wds_event_report_indication_id == 0); + self->priv->wds_event_report_indication_id = + g_signal_connect (client_wds, + "event-report", + G_CALLBACK (wds_event_report_indication_cb), + self); + } else if (self->priv->wds_event_report_indication_id != 0) { + g_signal_handler_disconnect (client_wds, self->priv->wds_event_report_indication_id); + self->priv->wds_event_report_indication_id = 0; + } + } g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -5246,7 +5264,7 @@ messaging_check_support (MMIfaceModemMessaging *self, return; } - mm_dbg ("Messaging capabilities supported"); + mm_obj_dbg (self, "messaging capabilities supported"); g_task_return_boolean (task, TRUE); g_object_unref (task); } @@ -5419,7 +5437,7 @@ messaging_set_default_storage (MMIfaceModemMessaging *_self, g_array_append_val (routes_array, route); qmi_message_wms_set_routes_input_set_route_list (input, routes_array, NULL); - mm_dbg ("setting default messaging routes..."); + mm_obj_dbg (self, "setting default messaging routes..."); qmi_client_wms_set_routes (QMI_CLIENT_WMS (client), input, 5, @@ -5496,6 +5514,7 @@ add_new_read_sms_part (MMIfaceModemMessaging *self, guint32 index, QmiWmsMessageTagType tag, QmiWmsMessageFormat format, + gboolean transfer_route, GArray *data) { MMSmsPart *part = NULL; @@ -5506,6 +5525,7 @@ add_new_read_sms_part (MMIfaceModemMessaging *self, part = mm_sms_part_cdma_new_from_binary_pdu (index, (guint8 *)data->data, data->len, + self, &error); break; @@ -5514,25 +5534,27 @@ add_new_read_sms_part (MMIfaceModemMessaging *self, part = mm_sms_part_3gpp_new_from_binary_pdu (index, (guint8 *)data->data, data->len, + self, + transfer_route, &error); break; case QMI_WMS_MESSAGE_FORMAT_MWI: - mm_dbg ("Don't know how to process 'message waiting indicator' messages"); + mm_obj_dbg (self, "don't know how to process 'message waiting indicator' messages"); break; default: - mm_dbg ("Unhandled message format '%u'", format); + mm_obj_dbg (self, "unhandled message format '%u'", format); break; } if (part) { - mm_dbg ("Correctly parsed PDU (%d)", index); + mm_obj_dbg (self, "correctly parsed PDU (%d)", index); mm_iface_modem_messaging_take_part (self, part, mm_sms_state_from_qmi_message_tag (tag), mm_sms_storage_from_qmi_storage_type (storage)); } else if (error) { /* Don't treat the error as critical */ - mm_dbg ("Error parsing PDU (%d): %s", index, error->message); + mm_obj_dbg (self, "error parsing PDU (%d): %s", index, error->message); g_error_free (error); } } @@ -5554,10 +5576,10 @@ wms_raw_read_ready (QmiClientWms *client, output = qmi_client_wms_raw_read_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: %s", error->message); + mm_obj_dbg (self, "QMI operation failed: %s", error->message); g_error_free (error); } else if (!qmi_message_wms_raw_read_output_get_result (output, &error)) { - mm_dbg ("Couldn't read raw message: %s", error->message); + mm_obj_dbg (self, "couldn't read raw message: %s", error->message); g_error_free (error); } else { QmiWmsMessageTagType tag; @@ -5580,6 +5602,7 @@ wms_raw_read_ready (QmiClientWms *client, message->memory_index, tag, format, + FALSE, data); } @@ -5654,12 +5677,14 @@ wms_list_messages_ready (QmiClientWms *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; LoadInitialSmsPartsContext *ctx; QmiMessageWmsListMessagesOutput *output = NULL; GError *error = NULL; GArray *message_array; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); output = qmi_client_wms_list_messages_finish (client, res, &error); if (!output) { @@ -5671,7 +5696,7 @@ wms_list_messages_ready (QmiClientWms *client, if (!qmi_message_wms_list_messages_output_get_result (output, &error)) { /* Ignore error, keep on */ - mm_dbg ("Couldn't read SMS messages: %s", error->message); + mm_obj_dbg (self, "couldn't read SMS messages: %s", error->message); g_error_free (error); ctx->step++; load_initial_sms_parts_step (task); @@ -5724,34 +5749,34 @@ load_initial_sms_parts_step (GTask *task) /* Fall through */ case LOAD_INITIAL_SMS_PARTS_STEP_3GPP_LIST_ALL: - mm_dbg ("loading all 3GPP messages from storage '%s'...", + mm_obj_dbg (self, "loading all 3GPP messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); mode = QMI_WMS_MESSAGE_MODE_GSM_WCDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_3GPP_LIST_MT_READ: - mm_dbg ("loading 3GPP MT-read messages from storage '%s'...", + mm_obj_dbg (self, "loading 3GPP MT-read messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MT_READ; mode = QMI_WMS_MESSAGE_MODE_GSM_WCDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_3GPP_LIST_MT_NOT_READ: - mm_dbg ("loading 3GPP MT-not-read messages from storage '%s'...", + mm_obj_dbg (self, "loading 3GPP MT-not-read messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ; mode = QMI_WMS_MESSAGE_MODE_GSM_WCDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_3GPP_LIST_MO_SENT: - mm_dbg ("loading 3GPP MO-sent messages from storage '%s'...", + mm_obj_dbg (self, "loading 3GPP MO-sent messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MO_SENT; mode = QMI_WMS_MESSAGE_MODE_GSM_WCDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_3GPP_LIST_MO_NOT_SENT: - mm_dbg ("loading 3GPP MO-not-sent messages from storage '%s'...", + mm_obj_dbg (self, "loading 3GPP MO-not-sent messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MO_NOT_SENT; mode = QMI_WMS_MESSAGE_MODE_GSM_WCDMA; @@ -5772,34 +5797,34 @@ load_initial_sms_parts_step (GTask *task) /* Fall through */ case LOAD_INITIAL_SMS_PARTS_STEP_CDMA_LIST_ALL: - mm_dbg ("loading all CDMA messages from storage '%s'...", + mm_obj_dbg (self, "loading all CDMA messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); mode = QMI_WMS_MESSAGE_MODE_CDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_CDMA_LIST_MT_READ: - mm_dbg ("loading CDMA MT-read messages from storage '%s'...", + mm_obj_dbg (self, "loading CDMA MT-read messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MT_READ; mode = QMI_WMS_MESSAGE_MODE_CDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_CDMA_LIST_MT_NOT_READ: - mm_dbg ("loading CDMA MT-not-read messages from storage '%s'...", + mm_obj_dbg (self, "loading CDMA MT-not-read messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ; mode = QMI_WMS_MESSAGE_MODE_CDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_CDMA_LIST_MO_SENT: - mm_dbg ("loading CDMA MO-sent messages from storage '%s'...", + mm_obj_dbg (self, "loading CDMA MO-sent messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MO_SENT; mode = QMI_WMS_MESSAGE_MODE_CDMA; break; case LOAD_INITIAL_SMS_PARTS_STEP_CDMA_LIST_MO_NOT_SENT: - mm_dbg ("loading CDMA MO-not-sent messages from storage '%s'...", + mm_obj_dbg (self, "loading CDMA MO-not-sent messages from storage '%s'...", mm_sms_storage_get_string (ctx->storage)); tag_type = QMI_WMS_MESSAGE_TAG_TYPE_MO_NOT_SENT; mode = QMI_WMS_MESSAGE_MODE_CDMA; @@ -5907,10 +5932,10 @@ wms_indication_raw_read_ready (QmiClientWms *client, output = qmi_client_wms_raw_read_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: %s", error->message); + mm_obj_dbg (ctx->self, "QMI operation failed: %s", error->message); g_error_free (error); } else if (!qmi_message_wms_raw_read_output_get_result (output, &error)) { - mm_dbg ("Couldn't read raw message: %s", error->message); + mm_obj_dbg (ctx->self, "couldn't read raw message: %s", error->message); g_error_free (error); } else { QmiWmsMessageTagType tag; @@ -5928,6 +5953,7 @@ wms_indication_raw_read_ready (QmiClientWms *client, ctx->memory_index, tag, format, + FALSE, data); } @@ -5937,6 +5963,21 @@ wms_indication_raw_read_ready (QmiClientWms *client, indication_raw_read_context_free (ctx); } +static void +wms_send_ack_ready (QmiClientWms *client, + GAsyncResult *res, + MMBroadbandModemQmi *self) +{ + g_autoptr(QmiMessageWmsSendAckOutput) output = NULL; + g_autoptr(GError) error= NULL; + + output = qmi_client_wms_send_ack_finish (client, res, &error); + if (!output) { + mm_obj_dbg (self, "QMI operation failed: '%s'", error->message); + } + g_object_unref (self); +} + static void messaging_event_report_indication_cb (QmiClientNas *client, QmiIndicationWmsEventReportOutput *output, @@ -5944,8 +5985,66 @@ messaging_event_report_indication_cb (QmiClientNas *client, { QmiWmsStorageType storage; guint32 memory_index; + QmiWmsAckIndicator ack_ind; + guint32 transaction_id; + QmiWmsMessageFormat msg_format; + QmiWmsMessageTagType tag; + GArray *raw_data = NULL; + + /* Handle transfer-route MT messages */ + if (qmi_indication_wms_event_report_output_get_transfer_route_mt_message ( + output, + &ack_ind, + &transaction_id, + &msg_format, + &raw_data, + NULL)) { + mm_obj_dbg (self, "Got transfer-route MT message"); + /* If this is the first of a multi-part message, send an ACK to get the + * second part */ + if (ack_ind == QMI_WMS_ACK_INDICATOR_SEND) { + g_autoptr(QmiMessageWmsSendAckInput) ack_input = NULL; + QmiWmsMessageProtocol message_protocol; + /* Need to ack message */ + mm_obj_dbg (self, "Need to ACK indicator"); + switch (msg_format) { + case QMI_WMS_MESSAGE_FORMAT_CDMA: + message_protocol = QMI_WMS_MESSAGE_PROTOCOL_CDMA; + break; + case QMI_WMS_MESSAGE_FORMAT_MWI: + case QMI_WMS_MESSAGE_FORMAT_GSM_WCDMA_POINT_TO_POINT: + case QMI_WMS_MESSAGE_FORMAT_GSM_WCDMA_BROADCAST: + default: + message_protocol = QMI_WMS_MESSAGE_PROTOCOL_WCDMA; + break; + } + ack_input = qmi_message_wms_send_ack_input_new(); + qmi_message_wms_send_ack_input_set_information (ack_input, + transaction_id, + message_protocol, + TRUE, + NULL); + qmi_client_wms_send_ack (QMI_CLIENT_WMS (client), + ack_input, + 180, + NULL, + (GAsyncReadyCallback)wms_send_ack_ready, + g_object_ref (self)); + } - /* Currently ignoring transfer-route MT messages */ + /* Defaults for transfer-route messages, which are not stored anywhere */ + storage = QMI_WMS_STORAGE_TYPE_NONE; + memory_index = 0; + tag = QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ; + add_new_read_sms_part (MM_IFACE_MODEM_MESSAGING (self), + storage, + memory_index, + tag, + msg_format, + TRUE, + raw_data); + return; + } if (qmi_indication_wms_event_report_output_get_mt_message ( output, @@ -6036,8 +6135,8 @@ common_setup_cleanup_messaging_unsolicited_events (MMBroadbandModemQmi *self, task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->messaging_unsolicited_events_setup) { - mm_dbg ("Messaging unsolicited events already %s; skipping", - enable ? "setup" : "cleanup"); + mm_obj_dbg (self, "messaging unsolicited events already %s; skipping", + enable ? "setup" : "cleanup"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -6152,10 +6251,10 @@ ser_messaging_indicator_ready (QmiClientWms *client, output = qmi_client_wms_set_event_report_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); + mm_obj_dbg (self, "QMI operation failed: '%s'", error->message); g_error_free (error); } else if (!qmi_message_wms_set_event_report_output_get_result (output, &error)) { - mm_dbg ("Couldn't set event report: '%s'", error->message); + mm_obj_dbg (self, "couldn't set event report: '%s'", error->message); g_error_free (error); } @@ -6187,8 +6286,8 @@ common_enable_disable_messaging_unsolicited_events (MMBroadbandModemQmi *self, task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->messaging_unsolicited_events_enabled) { - mm_dbg ("Messaging unsolicited events already %s; skipping", - enable ? "enabled" : "disabled"); + mm_obj_dbg (self, "messaging unsolicited events already %s; skipping", + enable ? "enabled" : "disabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -6489,10 +6588,10 @@ oma_check_support (MMIfaceModemOma *self, QMI_SERVICE_OMA, MM_PORT_QMI_FLAG_DEFAULT, NULL)) { - mm_dbg ("OMA capabilities not supported"); + mm_obj_dbg (self, "OMA capabilities not supported"); g_task_return_boolean (task, FALSE); } else { - mm_dbg ("OMA capabilities supported"); + mm_obj_dbg (self, "OMA capabilities supported"); g_task_return_boolean (task, TRUE); } @@ -6877,7 +6976,7 @@ oma_event_report_indication_cb (QmiClientNas *client, session_type = mm_oma_session_type_from_qmi_oma_session_type (network_initiated_alert_session_type); if (session_type == MM_OMA_SESSION_TYPE_UNKNOWN) - mm_warn ("Unknown QMI OMA session type '%u'", network_initiated_alert_session_type); + mm_obj_warn (self, "unknown QMI OMA session type '%u'", network_initiated_alert_session_type); else mm_iface_modem_oma_add_pending_network_initiated_session ( MM_IFACE_MODEM_OMA (self), @@ -6911,8 +7010,8 @@ common_setup_cleanup_oma_unsolicited_events (MMBroadbandModemQmi *self, task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->oma_unsolicited_events_setup) { - mm_dbg ("OMA unsolicited events already %s; skipping", - enable ? "setup" : "cleanup"); + mm_obj_dbg (self, "OMA unsolicited events already %s; skipping", + enable ? "setup" : "cleanup"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -6935,148 +7034,1243 @@ common_setup_cleanup_oma_unsolicited_events (MMBroadbandModemQmi *self, self->priv->oma_event_report_indication_id = 0; } - g_task_return_boolean (task, TRUE); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +oma_cleanup_unsolicited_events (MMIfaceModemOma *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_setup_cleanup_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), + FALSE, + callback, + user_data); +} + +static void +oma_setup_unsolicited_events (MMIfaceModemOma *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_setup_cleanup_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), + TRUE, + callback, + user_data); +} + +/*****************************************************************************/ +/* Enable/Disable unsolicited events (OMA interface) */ + +typedef struct { + gboolean enable; +} EnableOmaUnsolicitedEventsContext; + +static gboolean +common_oma_enable_disable_unsolicited_events_finish (MMIfaceModemOma *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +ser_oma_indicator_ready (QmiClientOma *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + EnableOmaUnsolicitedEventsContext *ctx; + QmiMessageOmaSetEventReportOutput *output = NULL; + GError *error = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_oma_set_event_report_finish (client, res, &error); + if (!output) { + mm_obj_dbg (self, "QMI operation failed: '%s'", error->message); + g_error_free (error); + } else if (!qmi_message_oma_set_event_report_output_get_result (output, &error)) { + mm_obj_dbg (self, "couldn't set event report: '%s'", error->message); + g_error_free (error); + } + + if (output) + qmi_message_oma_set_event_report_output_unref (output); + + /* Just ignore errors for now */ + self->priv->oma_unsolicited_events_enabled = ctx->enable; + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +common_enable_disable_oma_unsolicited_events (MMBroadbandModemQmi *self, + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + EnableOmaUnsolicitedEventsContext *ctx; + GTask *task; + QmiClient *client = NULL; + QmiMessageOmaSetEventReportInput *input; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_OMA, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + if (enable == self->priv->oma_unsolicited_events_enabled) { + mm_obj_dbg (self, "OMA unsolicited events already %s; skipping", + enable ? "enabled" : "disabled"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + ctx = g_new (EnableOmaUnsolicitedEventsContext, 1); + ctx->enable = enable; + + g_task_set_task_data (task, ctx, g_free); + + input = qmi_message_oma_set_event_report_input_new (); + qmi_message_oma_set_event_report_input_set_session_state_reporting ( + input, + ctx->enable, + NULL); + qmi_message_oma_set_event_report_input_set_network_initiated_alert_reporting ( + input, + ctx->enable, + NULL); + qmi_client_oma_set_event_report ( + QMI_CLIENT_OMA (client), + input, + 5, + NULL, + (GAsyncReadyCallback)ser_oma_indicator_ready, + task); + qmi_message_oma_set_event_report_input_unref (input); +} + +static void +oma_disable_unsolicited_events (MMIfaceModemOma *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_enable_disable_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), + FALSE, + callback, + user_data); +} + +static void +oma_enable_unsolicited_events (MMIfaceModemOma *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_enable_disable_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), + TRUE, + callback, + user_data); +} + +/*****************************************************************************/ +/* Check support (3GPP USSD interface) */ + +static gboolean +modem_3gpp_ussd_check_support_finish (MMIfaceModem3gppUssd *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +modem_3gpp_ussd_check_support (MMIfaceModem3gppUssd *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + /* If we have support for the Voice client, USSD is supported */ + if (!mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_VOICE, + MM_PORT_QMI_FLAG_DEFAULT, + NULL)) { + mm_obj_dbg (self, "USSD capabilities not supported"); + g_task_return_boolean (task, FALSE); + } else { + mm_obj_dbg (self, "USSD capabilities supported"); + g_task_return_boolean (task, TRUE); + } + + g_object_unref (task); +} + +/*****************************************************************************/ +/* USSD encode/decode helpers */ + +static GArray * +ussd_encode (const gchar *command, + QmiVoiceUssDataCodingScheme *scheme, + GError **error) +{ + gsize command_len; + g_autoptr(GByteArray) barray = NULL; + g_autoptr(GError) inner_error = NULL; + + command_len = strlen (command); + + if (g_str_is_ascii (command)) { + barray = g_byte_array_sized_new (command_len); + g_byte_array_append (barray, (const guint8 *)command, command_len); + + *scheme = QMI_VOICE_USS_DATA_CODING_SCHEME_ASCII; + return (GArray *) g_steal_pointer (&barray); + } + + barray = mm_modem_charset_bytearray_from_utf8 (command, MM_MODEM_CHARSET_UCS2, FALSE, &inner_error); + if (!barray) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Failed to encode USSD command in UCS2 charset: %s", inner_error->message); + return NULL; + } + + *scheme = QMI_VOICE_USS_DATA_CODING_SCHEME_UCS2; + return (GArray *) g_steal_pointer (&barray); +} + +static gchar * +ussd_decode (QmiVoiceUssDataCodingScheme scheme, + GArray *data, + GError **error) +{ + gchar *decoded = NULL; + + if (scheme == QMI_VOICE_USS_DATA_CODING_SCHEME_ASCII) { + decoded = g_strndup ((const gchar *) data->data, data->len); + if (!decoded) + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Error decoding USSD command in 0x%04x scheme (ASCII charset)", + scheme); + } else if (scheme == QMI_VOICE_USS_DATA_CODING_SCHEME_UCS2) { + decoded = mm_modem_charset_bytearray_to_utf8 ((GByteArray *) data, MM_MODEM_CHARSET_UCS2, FALSE, error); + if (!decoded) + g_prefix_error (error, "Error decoding USSD command in 0x%04x scheme (UCS2 charset): ", scheme); + } else + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Failed to decode USSD command in unsupported 0x%04x scheme", scheme); + + return decoded; +} + +/*****************************************************************************/ +/* USSD indications */ + +static void +process_ussd_message (MMBroadbandModemQmi *self, + QmiVoiceUserAction user_action, + gchar *utf8_take, + GError *error_take) +{ + MMModem3gppUssdSessionState ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE; + g_autoptr(GTask) task = NULL; + g_autofree gchar *utf8 = utf8_take; + g_autoptr(GError) error = error_take; + + task = g_steal_pointer (&self->priv->pending_ussd_action); + + if (error) { + g_assert (!utf8); + if (task) + g_task_return_error (task, g_steal_pointer (&error)); + else + mm_obj_dbg (self, "USSD operation failed: %s", error->message); + return; + } + + switch (user_action) { + case QMI_VOICE_USER_ACTION_NOT_REQUIRED: + /* no response, or a response to user's request? */ + if (!utf8 || task) + break; + /* Network-initiated USSD-Notify */ + mm_iface_modem_3gpp_ussd_update_network_notification (MM_IFACE_MODEM_3GPP_USSD (self), utf8); + g_clear_pointer (&utf8, g_free); + break; + case QMI_VOICE_USER_ACTION_REQUIRED: + /* further action required */ + ussd_state = MM_MODEM_3GPP_USSD_SESSION_STATE_USER_RESPONSE; + /* no response, or a response to user's request? */ + if (!utf8 || task) + break; + /* Network-initiated USSD-Request */ + mm_iface_modem_3gpp_ussd_update_network_request (MM_IFACE_MODEM_3GPP_USSD (self), utf8); + g_clear_pointer (&utf8, g_free); + break; + case QMI_VOICE_USER_ACTION_UNKNOWN: + default: + /* Not an indication */ + break; + } + + mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self), ussd_state); + + if (!task) { + if (utf8) + mm_obj_dbg (self, "ignoring unprocessed USSD message: %s", utf8); + return; + } + + /* Complete the pending action, if any */ + if (utf8) + g_task_return_pointer (task, g_steal_pointer (&utf8), g_free); + else + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "USSD action response not processed correctly"); +} + +static void +ussd_indication_cb (QmiClientVoice *client, + QmiIndicationVoiceUssdOutput *output, + MMBroadbandModemQmi *self) +{ + QmiVoiceUserAction user_action = QMI_VOICE_USER_ACTION_UNKNOWN; + QmiVoiceUssDataCodingScheme scheme; + GArray *uss_data = NULL; + gchar *utf8 = NULL; + GError *error = NULL; + + qmi_indication_voice_ussd_output_get_user_action (output, &user_action, NULL); + if (qmi_indication_voice_ussd_output_get_uss_data_utf16 (output, &uss_data, NULL) && uss_data) + utf8 = g_convert ((const gchar *) uss_data->data, (2 * uss_data->len), "UTF-8", "UTF-16LE", NULL, NULL, &error); + else if (qmi_indication_voice_ussd_output_get_uss_data (output, &scheme, &uss_data, NULL) && uss_data) + utf8 = ussd_decode(scheme, uss_data, &error); + + process_ussd_message (self, user_action, utf8, error); +} + +static void +ussd_release_indication_cb (QmiClientVoice *client, + MMBroadbandModemQmi *self) +{ + GTask *pending_task; + GError *error; + + mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self), + MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE); + + error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, "USSD terminated by network"); + + pending_task = g_steal_pointer (&self->priv->pending_ussd_action); + if (pending_task) { + g_task_return_error (pending_task, error); + g_object_unref (pending_task); + return; + } + + /* If no pending task, just report the error */ + mm_obj_dbg (self, "USSD release indication: %s", error->message); + g_error_free (error); +} + +/*****************************************************************************/ +/* Setup/cleanup unsolicited events */ + +static gboolean +common_3gpp_ussd_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gppUssd *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +common_3gpp_ussd_setup_cleanup_unsolicited_events (MMBroadbandModemQmi *self, + gboolean setup, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + QmiClient *client = NULL; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_VOICE, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + if (setup == self->priv->ussd_unsolicited_events_setup) { + mm_obj_dbg (self, "USSD unsolicited events already %s; skipping", + setup ? "setup" : "cleanup"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + self->priv->ussd_unsolicited_events_setup = setup; + + if (setup) { + g_assert (self->priv->ussd_indication_id == 0); + self->priv->ussd_indication_id = + g_signal_connect (client, + "ussd", + G_CALLBACK (ussd_indication_cb), + self); + g_assert (self->priv->ussd_release_indication_id == 0); + self->priv->ussd_release_indication_id = + g_signal_connect (client, + "release-ussd", + G_CALLBACK (ussd_release_indication_cb), + self); + } else { + g_assert (self->priv->ussd_indication_id != 0); + g_signal_handler_disconnect (client, self->priv->ussd_indication_id); + self->priv->ussd_indication_id = 0; + g_assert (self->priv->ussd_release_indication_id != 0); + g_signal_handler_disconnect (client, self->priv->ussd_release_indication_id); + self->priv->ussd_release_indication_id = 0; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +modem_3gpp_ussd_setup_unsolicited_events (MMIfaceModem3gppUssd *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_3gpp_ussd_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), TRUE, callback, user_data); +} + +static void +modem_3gpp_ussd_cleanup_unsolicited_events (MMIfaceModem3gppUssd *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_3gpp_ussd_setup_cleanup_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), FALSE, callback, user_data); +} + +/*****************************************************************************/ +/* Enable/disable unsolicited events */ + +static gboolean +common_3gpp_ussd_enable_disable_unsolicited_events_finish (MMIfaceModem3gppUssd *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +voice_indication_register_ready (QmiClientVoice *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageVoiceIndicationRegisterOutput) output = NULL; + GError *error = NULL; + + output = qmi_client_voice_indication_register_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + } else if (!qmi_message_voice_indication_register_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't register voice USSD indications: "); + g_task_return_error (task, error); + } else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +common_3gpp_ussd_enable_disable_unsolicited_events (MMBroadbandModemQmi *self, + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(QmiMessageVoiceIndicationRegisterInput) input = NULL; + GTask *task; + QmiClient *client; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_VOICE, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + if (enable == self->priv->ussd_unsolicited_events_enabled) { + mm_obj_dbg (self, "USSD unsolicited events already %s; skipping", + enable ? "enabled" : "disabled"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + self->priv->ussd_unsolicited_events_enabled = enable; + + input = qmi_message_voice_indication_register_input_new (); + qmi_message_voice_indication_register_input_set_ussd_notification_events (input, enable, NULL); + qmi_client_voice_indication_register (QMI_CLIENT_VOICE (client), + input, + 10, + NULL, + (GAsyncReadyCallback) voice_indication_register_ready, + task); +} + +static void +modem_3gpp_ussd_enable_unsolicited_events (MMIfaceModem3gppUssd *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_3gpp_ussd_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), TRUE, callback, user_data); +} + +static void +modem_3gpp_ussd_disable_unsolicited_events (MMIfaceModem3gppUssd *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_3gpp_ussd_enable_disable_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), FALSE, callback, user_data); +} + +/*****************************************************************************/ +/* Send command (3GPP/USSD interface) */ + +static gchar * +modem_3gpp_ussd_send_finish (MMIfaceModem3gppUssd *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +voice_answer_ussd_ready (QmiClientVoice *client, + GAsyncResult *res, + MMBroadbandModemQmi *self) +{ + g_autoptr(QmiMessageVoiceAnswerUssdOutput) output = NULL; + GError *error = NULL; + + output = qmi_client_voice_answer_ussd_finish (client, res, &error); + if (!output) + g_prefix_error (&error, "QMI operation failed: "); + else if (!qmi_message_voice_answer_ussd_output_get_result (output, &error)) + g_prefix_error (&error, "Couldn't answer USSD operation: "); + + process_ussd_message (self, QMI_VOICE_USER_ACTION_UNKNOWN, error ? NULL : g_strdup (""), error); + + /* balance out the full reference we received */ + g_object_unref (self); +} + +static void +voice_originate_ussd_ready (QmiClientVoice *client, + GAsyncResult *res, + MMBroadbandModemQmi *self) +{ + g_autoptr(QmiMessageVoiceOriginateUssdOutput) output = NULL; + QmiVoiceUssDataCodingScheme scheme; + GError *error = NULL; + GArray *uss_data = NULL; + gchar *utf8 = NULL; + + output = qmi_client_voice_originate_ussd_finish (client, res, &error); + if (!output) + g_prefix_error (&error, "QMI operation failed: "); + else if (!qmi_message_voice_originate_ussd_output_get_result (output, &error)) + g_prefix_error (&error, "Couldn't originate USSD operation: "); + else if (qmi_message_voice_originate_ussd_output_get_uss_data_utf16 (output, &uss_data, NULL) && uss_data) + utf8 = g_convert ((const gchar *) uss_data->data, (2 * uss_data->len), "UTF-8", "UTF-16LE", NULL, NULL, &error); + else if (qmi_message_voice_originate_ussd_output_get_uss_data (output, &scheme, &uss_data, NULL) && uss_data) + utf8 = ussd_decode (scheme, uss_data, &error); + + process_ussd_message (self, QMI_VOICE_USER_ACTION_UNKNOWN, utf8, error); + + /* balance out the full reference we received */ + g_object_unref (self); +} + +static void +modem_3gpp_ussd_send (MMIfaceModem3gppUssd *_self, + const gchar *command, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); + GTask *task; + QmiClient *client; + QmiVoiceUssDataCodingScheme scheme; + g_autoptr(GArray) encoded = NULL; + GError *error = NULL; + MMModem3gppUssdSessionState state; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_VOICE, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + /* Fail if there is an ongoing operation already */ + if (self->priv->pending_ussd_action) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS, + "there is already an ongoing USSD operation"); + g_object_unref (task); + return; + } + + encoded = ussd_encode (command, &scheme, &error); + if (!encoded) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + state = mm_iface_modem_3gpp_ussd_get_state (MM_IFACE_MODEM_3GPP_USSD (self)); + + /* Cache the action, as it may be completed via URCs */ + self->priv->pending_ussd_action = task; + mm_iface_modem_3gpp_ussd_update_state (_self, MM_MODEM_3GPP_USSD_SESSION_STATE_ACTIVE); + + switch (state) { + case MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE: { + g_autoptr(QmiMessageVoiceOriginateUssdInput) input = NULL; + + input = qmi_message_voice_originate_ussd_input_new (); + qmi_message_voice_originate_ussd_input_set_uss_data (input, scheme, encoded, NULL); + qmi_client_voice_originate_ussd (QMI_CLIENT_VOICE (client), input, 100, NULL, + (GAsyncReadyCallback) voice_originate_ussd_ready, + g_object_ref (self)); /* full reference! */ + return; + } + case MM_MODEM_3GPP_USSD_SESSION_STATE_USER_RESPONSE: { + g_autoptr(QmiMessageVoiceAnswerUssdInput) input = NULL; + + input = qmi_message_voice_answer_ussd_input_new (); + qmi_message_voice_answer_ussd_input_set_uss_data (input, scheme, encoded, NULL); + qmi_client_voice_answer_ussd (QMI_CLIENT_VOICE (client), input, 100, NULL, + (GAsyncReadyCallback) voice_answer_ussd_ready, + g_object_ref (self)); /* full reference! */ + return; + } + case MM_MODEM_3GPP_USSD_SESSION_STATE_UNKNOWN: + case MM_MODEM_3GPP_USSD_SESSION_STATE_ACTIVE: + default: + g_assert_not_reached (); + return; + } +} + +/*****************************************************************************/ +/* Cancel USSD (3GPP/USSD interface) */ + +static gboolean +modem_3gpp_ussd_cancel_finish (MMIfaceModem3gppUssd *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +voice_cancel_ussd_ready (QmiClientVoice *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageVoiceCancelUssdOutput) output = NULL; + MMBroadbandModemQmi *self; + GTask *pending_task; + GError *error = NULL; + + self = g_task_get_source_object (task); + + output = qmi_client_voice_cancel_ussd_finish (client, res, &error); + if (!output) + g_prefix_error (&error, "QMI operation failed: "); + else if (!qmi_message_voice_cancel_ussd_output_get_result (output, &error)) + g_prefix_error (&error, "Couldn't cancel USSD operation: "); + + /* Complete the pending action, regardless of the operation result */ + pending_task = g_steal_pointer (&self->priv->pending_ussd_action); + if (pending_task) { + g_task_return_new_error (pending_task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, + "USSD session was cancelled"); + g_object_unref (pending_task); + } + + mm_iface_modem_3gpp_ussd_update_state (MM_IFACE_MODEM_3GPP_USSD (self), + MM_MODEM_3GPP_USSD_SESSION_STATE_IDLE); + + if (error) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +modem_3gpp_ussd_cancel (MMIfaceModem3gppUssd *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); + GTask *task; + QmiClient *client; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_VOICE, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + qmi_client_voice_cancel_ussd (QMI_CLIENT_VOICE (client), NULL, 100, NULL, + (GAsyncReadyCallback) voice_cancel_ussd_ready, + task); +} + +/*****************************************************************************/ +/* Initial EPS bearer info loading */ + +static MMBearerProperties * +modem_3gpp_load_initial_eps_bearer_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) +{ + return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error)); +} + +static void +get_lte_attach_parameters_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageWdsGetLteAttachParametersOutput) output = NULL; + GError *error = NULL; + MMBearerProperties *properties; + const gchar *apn; + QmiWdsIpSupportType ip_support_type; + + output = qmi_client_wds_get_lte_attach_parameters_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!qmi_message_wds_get_lte_attach_parameters_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't get LTE attach parameters: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + properties = mm_bearer_properties_new (); + if (qmi_message_wds_get_lte_attach_parameters_output_get_apn (output, &apn, NULL)) + mm_bearer_properties_set_apn (properties, apn); + if (qmi_message_wds_get_lte_attach_parameters_output_get_ip_support_type (output, &ip_support_type, NULL)) { + MMBearerIpFamily ip_family; + + ip_family = mm_bearer_ip_family_from_qmi_ip_support_type (ip_support_type); + if (ip_family != MM_BEARER_IP_FAMILY_NONE) + mm_bearer_properties_set_ip_type (properties, ip_family); + } + g_task_return_pointer (task, properties, g_object_unref); + g_object_unref (task); +} + +static void +modem_3gpp_load_initial_eps_bearer (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + QmiClient *client; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_WDS, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + qmi_client_wds_get_lte_attach_parameters (QMI_CLIENT_WDS (client), + NULL, + 10, + NULL, + (GAsyncReadyCallback) get_lte_attach_parameters_ready, + task); +} + +/*****************************************************************************/ +/* Initial EPS bearer settings setting */ + +typedef enum { + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FIRST, + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE, + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN, + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE, + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP, + SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LAST_SETTING, +} SetInitialEpsBearerSettingsStep; + +typedef struct { + SetInitialEpsBearerSettingsStep step; + QmiClientWds *client; + MMBearerProperties *settings; + MMModemPowerState power_state; +} SetInitialEpsBearerSettingsContext; + +static void +set_initial_eps_bearer_settings_context_free (SetInitialEpsBearerSettingsContext *ctx) +{ + g_clear_object (&ctx->client); + g_clear_object (&ctx->settings); + g_slice_free (SetInitialEpsBearerSettingsContext, ctx); +} + +static gboolean +modem_3gpp_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void set_initial_eps_bearer_settings_step (GTask *task); + +static void +set_initial_eps_bearer_power_up_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + SetInitialEpsBearerSettingsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + if (!modem_power_up_down_off_finish (self, res, &error)) { + g_prefix_error (&error, "Couldn't power up modem: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx->step++; + set_initial_eps_bearer_settings_step (task); +} + +static void +set_initial_eps_bearer_modify_profile_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageWdsModifyProfileOutput) output = NULL; + GError *error = NULL; + SetInitialEpsBearerSettingsContext *ctx; + + ctx = g_task_get_task_data (task); + + output = qmi_client_wds_modify_profile_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!qmi_message_wds_modify_profile_output_get_result (output, &error)) { + QmiWdsDsProfileError ds_profile_error; + + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) && + qmi_message_wds_modify_profile_output_get_extended_error_code (output, &ds_profile_error, NULL)) { + g_prefix_error (&error, "DS profile error: %s: ", + qmi_wds_ds_profile_error_get_string (ds_profile_error)); + } + g_prefix_error (&error, "Couldn't modify default LTE attach PDN settings: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx->step++; + set_initial_eps_bearer_settings_step (task); +} + +static void +set_initial_eps_bearer_modify_profile (GTask *task) +{ + g_autoptr(QmiMessageWdsModifyProfileInput) input = NULL; + MMBroadbandModemQmi *self; + SetInitialEpsBearerSettingsContext *ctx; + const gchar *str; + MMBearerIpFamily ip_family; + QmiWdsPdpType pdp_type; + MMBearerAllowedAuth allowed_auth; + QmiWdsAuthentication auth; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + input = qmi_message_wds_modify_profile_input_new (); + qmi_message_wds_modify_profile_input_set_profile_identifier (input, + QMI_WDS_PROFILE_TYPE_3GPP, + self->priv->default_attach_pdn, + NULL); + + str = mm_bearer_properties_get_apn (ctx->settings); + qmi_message_wds_modify_profile_input_set_apn_name (input, str ? str : "", NULL); + + ip_family = mm_bearer_properties_get_ip_type (ctx->settings); + if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY) + ip_family = MM_BEARER_IP_FAMILY_IPV4; + if (mm_bearer_ip_family_to_qmi_pdp_type (ip_family, &pdp_type)) + qmi_message_wds_modify_profile_input_set_pdp_type (input, pdp_type, NULL); + + allowed_auth = mm_bearer_properties_get_allowed_auth (ctx->settings); + if (allowed_auth == MM_BEARER_ALLOWED_AUTH_UNKNOWN) + allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE; + auth = mm_bearer_allowed_auth_to_qmi_authentication (allowed_auth); + qmi_message_wds_modify_profile_input_set_authentication (input, auth, NULL); + + str = mm_bearer_properties_get_user (ctx->settings); + qmi_message_wds_modify_profile_input_set_username (input, str ? str : "", NULL); + + str = mm_bearer_properties_get_password (ctx->settings); + qmi_message_wds_modify_profile_input_set_password (input, str ? str : "", NULL); + + qmi_client_wds_modify_profile (ctx->client, + input, + 10, + NULL, + (GAsyncReadyCallback)set_initial_eps_bearer_modify_profile_ready, + task); +} + +static void +set_initial_eps_bearer_power_down_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + SetInitialEpsBearerSettingsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + if (!modem_power_up_down_off_finish (self, res, &error)) { + g_prefix_error (&error, "Couldn't power down modem: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx->step++; + set_initial_eps_bearer_settings_step (task); +} + +static void +set_initial_eps_bearer_load_power_state_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + SetInitialEpsBearerSettingsContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + ctx->power_state = load_power_state_finish (self, res, &error); + if (ctx->power_state == MM_MODEM_POWER_STATE_UNKNOWN) { + g_prefix_error (&error, "Couldn't load power state: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx->step++; + set_initial_eps_bearer_settings_step (task); +} + +static void +set_initial_eps_bearer_settings_step (GTask *task) +{ + SetInitialEpsBearerSettingsContext *ctx; + MMBroadbandModemQmi *self; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FIRST: + ctx->step++; + /* fall through */ + + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE: + mm_obj_dbg (self, "querying current power state..."); + load_power_state (MM_IFACE_MODEM (self), + (GAsyncReadyCallback) set_initial_eps_bearer_load_power_state_ready, + task); + return; + + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN: + if (ctx->power_state == MM_MODEM_POWER_STATE_ON) { + mm_obj_dbg (self, "powering down before changing initial EPS bearer settings..."); + modem_power_down (MM_IFACE_MODEM (self), + (GAsyncReadyCallback) set_initial_eps_bearer_power_down_ready, + task); + return; + } + ctx->step++; + /* fall through */ + + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE: + mm_obj_dbg (self, "modifying initial EPS bearer settings profile..."); + set_initial_eps_bearer_modify_profile (task); + return; + + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP: + if (ctx->power_state == MM_MODEM_POWER_STATE_ON) { + mm_obj_dbg (self, "powering up after changing initial EPS bearer settings..."); + modem_power_up (MM_IFACE_MODEM (self), + (GAsyncReadyCallback) set_initial_eps_bearer_power_up_ready, + task); + return; + } + ctx->step++; + /* fall through */ + + case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LAST_SETTING: + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + default: + g_assert_not_reached (); + } +} + +static void +modem_3gpp_set_initial_eps_bearer_settings (MMIfaceModem3gpp *_self, + MMBearerProperties *config, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); + SetInitialEpsBearerSettingsContext *ctx; + GTask *task; + QmiClient *client; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_WDS, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + if (!self->priv->default_attach_pdn) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Unknown default LTE attach APN index"); + g_object_unref (task); + return; + } + + ctx = g_slice_new0 (SetInitialEpsBearerSettingsContext); + ctx->settings = g_object_ref (config);; + ctx->client = QMI_CLIENT_WDS (g_object_ref (client)); + ctx->step = SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FIRST; + g_task_set_task_data (task, ctx, (GDestroyNotify) set_initial_eps_bearer_settings_context_free); + + set_initial_eps_bearer_settings_step (task); +} + +/*****************************************************************************/ +/* Initial EPS bearer settings loading */ + +static MMBearerProperties * +modem_3gpp_load_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) +{ + return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error)); +} + +static void +load_initial_eps_bearer_get_profile_settings_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageWdsGetProfileSettingsOutput) output = NULL; + GError *error = NULL; + const gchar *str; + QmiWdsPdpType pdp_type; + QmiWdsAuthentication auth; + gboolean flag; + MMBearerProperties *properties; + + output = qmi_client_wds_get_profile_settings_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!qmi_message_wds_get_profile_settings_output_get_result (output, &error)) { + QmiWdsDsProfileError ds_profile_error; + + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) && + qmi_message_wds_get_profile_settings_output_get_extended_error_code (output, &ds_profile_error, NULL)) { + g_prefix_error (&error, "DS profile error: %s: ", + qmi_wds_ds_profile_error_get_string (ds_profile_error)); + } + g_prefix_error (&error, "Couldn't get default LTE attach PDN settings: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + properties = mm_bearer_properties_new (); + if (qmi_message_wds_get_profile_settings_output_get_apn_name (output, &str, NULL)) + mm_bearer_properties_set_apn (properties, str); + + if (qmi_message_wds_get_profile_settings_output_get_pdp_type (output, &pdp_type, NULL)) { + MMBearerIpFamily ip_family; + + ip_family = mm_bearer_ip_family_from_qmi_pdp_type (pdp_type); + if (ip_family != MM_BEARER_IP_FAMILY_NONE) + mm_bearer_properties_set_ip_type (properties, ip_family); + } + + if (qmi_message_wds_get_profile_settings_output_get_username (output, &str, NULL)) + mm_bearer_properties_set_user (properties, str); + + if (qmi_message_wds_get_profile_settings_output_get_password (output, &str, NULL)) + mm_bearer_properties_set_password (properties, str); + + if (qmi_message_wds_get_profile_settings_output_get_authentication (output, &auth, NULL)) { + MMBearerAllowedAuth allowed_auth; + + allowed_auth = mm_bearer_allowed_auth_from_qmi_authentication (auth); + if (allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) + mm_bearer_properties_set_allowed_auth (properties, allowed_auth); + } + + if (qmi_message_wds_get_profile_settings_output_get_roaming_disallowed_flag (output, &flag, NULL)) + mm_bearer_properties_set_allow_roaming (properties, !flag); + + g_task_return_pointer (task, properties, g_object_unref); g_object_unref (task); } static void -oma_cleanup_unsolicited_events (MMIfaceModemOma *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_setup_cleanup_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), - FALSE, - callback, - user_data); -} - -static void -oma_setup_unsolicited_events (MMIfaceModemOma *self, - GAsyncReadyCallback callback, - gpointer user_data) +load_initial_eps_bearer_get_profile_settings (GTask *task, + QmiClientWds *client) { - common_setup_cleanup_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), - TRUE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Enable/Disable unsolicited events (OMA interface) */ - -typedef struct { - gboolean enable; -} EnableOmaUnsolicitedEventsContext; + g_autoptr(QmiMessageWdsGetProfileSettingsInput) input = NULL; + MMBroadbandModemQmi *self; -static gboolean -common_oma_enable_disable_unsolicited_events_finish (MMIfaceModemOma *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); + self = g_task_get_source_object (task); + g_assert (self->priv->default_attach_pdn); + + input = qmi_message_wds_get_profile_settings_input_new (); + qmi_message_wds_get_profile_settings_input_set_profile_id (input, + QMI_WDS_PROFILE_TYPE_3GPP, + self->priv->default_attach_pdn, + NULL); + mm_obj_dbg (self, "querying LTE attach PDN settings at index %u...", self->priv->default_attach_pdn); + qmi_client_wds_get_profile_settings (client, + input, + 10, + NULL, + (GAsyncReadyCallback)load_initial_eps_bearer_get_profile_settings_ready, + task); } static void -ser_oma_indicator_ready (QmiClientOma *client, - GAsyncResult *res, - GTask *task) +load_initial_eps_bearer_get_lte_attach_pdn_list_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) { + g_autoptr(QmiMessageWdsGetLteAttachPdnListOutput) output = NULL; MMBroadbandModemQmi *self; - EnableOmaUnsolicitedEventsContext *ctx; - QmiMessageOmaSetEventReportOutput *output = NULL; - GError *error = NULL; + GError *error = NULL; + GArray *current_list = NULL; + guint i; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - output = qmi_client_oma_set_event_report_finish (client, res, &error); + output = qmi_client_wds_get_lte_attach_pdn_list_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: '%s'", error->message); - g_error_free (error); - } else if (!qmi_message_oma_set_event_report_output_get_result (output, &error)) { - mm_dbg ("Couldn't set event report: '%s'", error->message); - g_error_free (error); + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; } - if (output) - qmi_message_oma_set_event_report_output_unref (output); + if (!qmi_message_wds_get_lte_attach_pdn_list_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't get LTE attach PDN list: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } - /* Just ignore errors for now */ - self->priv->oma_unsolicited_events_enabled = ctx->enable; - g_task_return_boolean (task, TRUE); - g_object_unref (task); + qmi_message_wds_get_lte_attach_pdn_list_output_get_current_list (output, ¤t_list, NULL); + if (!current_list || !current_list->len) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Undefined list of LTE attach PDN"); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "Found %u LTE attach PDNs defined", current_list->len); + for (i = 0; i < current_list->len; i++) { + if (i == 0) { + self->priv->default_attach_pdn = g_array_index (current_list, guint16, i); + mm_obj_dbg (self, "Default LTE attach PDN profile: %u", self->priv->default_attach_pdn); + } else + mm_obj_dbg (self, "Additional LTE attach PDN profile: %u", g_array_index (current_list, guint16, i)); + } + + load_initial_eps_bearer_get_profile_settings (task, client); } static void -common_enable_disable_oma_unsolicited_events (MMBroadbandModemQmi *self, - gboolean enable, - GAsyncReadyCallback callback, - gpointer user_data) +modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *_self, + GAsyncReadyCallback callback, + gpointer user_data) { - EnableOmaUnsolicitedEventsContext *ctx; - GTask *task; - QmiClient *client = NULL; - QmiMessageOmaSetEventReportInput *input; + MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); + QmiClient *client; + GTask *task; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_OMA, &client, + QMI_SERVICE_WDS, &client, callback, user_data)) return; task = g_task_new (self, NULL, callback, user_data); - if (enable == self->priv->oma_unsolicited_events_enabled) { - mm_dbg ("OMA unsolicited events already %s; skipping", - enable ? "enabled" : "disabled"); - g_task_return_boolean (task, TRUE); - g_object_unref (task); + /* Default attach PDN is assumed to never change during runtime + * (we don't change it) so just load it the first time */ + if (!self->priv->default_attach_pdn) { + mm_obj_dbg (self, "querying LTE attach PDN list..."); + qmi_client_wds_get_lte_attach_pdn_list (QMI_CLIENT_WDS (client), + NULL, + 10, + NULL, + (GAsyncReadyCallback)load_initial_eps_bearer_get_lte_attach_pdn_list_ready, + task); return; } - ctx = g_new (EnableOmaUnsolicitedEventsContext, 1); - ctx->enable = enable; - - g_task_set_task_data (task, ctx, g_free); - - input = qmi_message_oma_set_event_report_input_new (); - qmi_message_oma_set_event_report_input_set_session_state_reporting ( - input, - ctx->enable, - NULL); - qmi_message_oma_set_event_report_input_set_network_initiated_alert_reporting ( - input, - ctx->enable, - NULL); - qmi_client_oma_set_event_report ( - QMI_CLIENT_OMA (client), - input, - 5, - NULL, - (GAsyncReadyCallback)ser_oma_indicator_ready, - task); - qmi_message_oma_set_event_report_input_unref (input); -} - -static void -oma_disable_unsolicited_events (MMIfaceModemOma *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_enable_disable_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), - FALSE, - callback, - user_data); -} - -static void -oma_enable_unsolicited_events (MMIfaceModemOma *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_enable_disable_oma_unsolicited_events (MM_BROADBAND_MODEM_QMI (self), - TRUE, - callback, - user_data); + load_initial_eps_bearer_get_profile_settings (task, QMI_CLIENT_WDS (client)); } /*****************************************************************************/ @@ -7134,9 +8328,9 @@ store_preloaded_firmware_image_info (MMBroadbandModemQmi *self, /* If this is is also the running image, keep an extra reference to it */ if (running) { if (self->priv->current_firmware) - mm_warn ("A running firmware is already set (%s), not setting '%s'", - mm_firmware_properties_get_unique_id (self->priv->current_firmware), - mm_firmware_properties_get_unique_id (firmware)); + mm_obj_warn (self, "a running firmware is already set (%s), not setting '%s'", + mm_firmware_properties_get_unique_id (self->priv->current_firmware), + mm_firmware_properties_get_unique_id (firmware)); else self->priv->current_firmware = g_object_ref (firmware); } @@ -7165,8 +8359,8 @@ get_pri_image_info_ready (QmiClientDms *client, if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) ctx->skip_image_info = TRUE; else - mm_dbg ("couldn't get detailed info for PRI image with build ID '%s': %s", - ctx->current_pair->build_id, error->message); + mm_obj_dbg (self, "couldn't get detailed info for PRI image with build ID '%s': %s", + ctx->current_pair->build_id, error->message); g_error_free (error); goto out; } @@ -7344,7 +8538,8 @@ match_images (const gchar *pri_id, const gchar *modem_id) } static GList * -find_image_pairs (QmiMessageDmsListStoredImagesOutputListImage *image_pri, +find_image_pairs (MMBroadbandModemQmi *self, + QmiMessageDmsListStoredImagesOutputListImage *image_pri, QmiMessageDmsListStoredImagesOutputListImage *image_modem, GError **error) { @@ -7368,7 +8563,7 @@ find_image_pairs (QmiMessageDmsListStoredImagesOutputListImage *image_pri, if (match_images (subimage_pri->build_id, subimage_modem->build_id)) { FirmwarePair *pair; - mm_dbg ("Found pairing PRI+MODEM images with build ID '%s'", subimage_pri->build_id); + mm_obj_dbg (self, "found pairing PRI+MODEM images with build ID '%s'", subimage_pri->build_id); pair = g_slice_new (FirmwarePair); pair->build_id = g_strdup (subimage_pri->build_id); pair->modem_unique_id = g_array_ref (subimage_modem->unique_id); @@ -7387,7 +8582,7 @@ find_image_pairs (QmiMessageDmsListStoredImagesOutputListImage *image_pri, } if (j == image_modem->sublist->len) - mm_dbg ("Pairing for PRI image with build ID '%s' not found", subimage_pri->build_id); + mm_obj_dbg (self, "pairing for PRI image with build ID '%s' not found", subimage_pri->build_id); } if (!pairs) @@ -7397,7 +8592,8 @@ find_image_pairs (QmiMessageDmsListStoredImagesOutputListImage *image_pri, } static gboolean -find_image_type_indices (GArray *array, +find_image_type_indices (MMBroadbandModemQmi *self, + GArray *array, QmiMessageDmsListStoredImagesOutputListImage **image_pri, QmiMessageDmsListStoredImagesOutputListImage **image_modem, GError **error) @@ -7422,13 +8618,13 @@ find_image_type_indices (GArray *array, switch (image->type) { case QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI: if (*image_pri != NULL) - mm_dbg ("Multiple array elements found with PRI type: ignoring additional list at index %u", i); + mm_obj_dbg (self, "multiple array elements found with PRI type: ignoring additional list at index %u", i); else *image_pri = image; break; case QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM: if (*image_modem != NULL) - mm_dbg ("Multiple array elements found with MODEM type: ignoring additional list at index %u", i); + mm_obj_dbg (self, "multiple array elements found with MODEM type: ignoring additional list at index %u", i); else *image_modem = image; break; @@ -7453,6 +8649,7 @@ list_stored_images_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; FirmwareListPreloadContext *ctx; GArray *array; QmiMessageDmsListStoredImagesOutputListImage *image_pri; @@ -7460,7 +8657,8 @@ list_stored_images_ready (QmiClientDms *client, QmiMessageDmsListStoredImagesOutput *output; GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); /* Read array from output */ output = qmi_client_dms_list_stored_images_finish (client, res, &error); @@ -7473,14 +8671,14 @@ list_stored_images_ready (QmiClientDms *client, } /* Find which index corresponds to each image type */ - if (!find_image_type_indices (array, &image_pri, &image_modem, &error)) { + if (!find_image_type_indices (self, array, &image_pri, &image_modem, &error)) { g_task_return_error (task, error); g_object_unref (task); goto out; } /* Build firmware PRI+MODEM pair list */ - ctx->pairs = find_image_pairs (image_pri, image_modem, &error); + ctx->pairs = find_image_pairs (self, image_pri, image_modem, &error); if (!ctx->pairs) { g_task_return_error (task, error); g_object_unref (task); @@ -7516,7 +8714,7 @@ firmware_list_preload (MMBroadbandModemQmi *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)firmware_list_preload_context_free); - mm_dbg ("loading firmware images..."); + mm_obj_dbg (self, "loading firmware images..."); qmi_client_dms_list_stored_images (QMI_CLIENT_DMS (client), NULL, 10, @@ -7568,7 +8766,7 @@ firmware_list_preload_ready (MMBroadbandModemQmi *self, GError *error = NULL; if (!firmware_list_preload_finish (self, res, &error)) { - mm_dbg ("firmware list loading failed: %s", error ? error->message : "unsupported"); + mm_obj_dbg (self, "firmware list loading failed: %s", error ? error->message : "unsupported"); g_clear_error (&error); } @@ -7800,7 +8998,7 @@ firmware_change_current (MMIfaceModemFirmware *_self, if (self->priv->current_firmware && g_str_equal (mm_firmware_properties_get_unique_id (self->priv->current_firmware), mm_firmware_properties_get_unique_id (ctx->firmware))) { - mm_dbg ("Modem is already running firmware image '%s'", + mm_obj_dbg (self, "modem is already running firmware image '%s'", mm_firmware_properties_get_unique_id (self->priv->current_firmware)); g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -7829,10 +9027,10 @@ firmware_change_current (MMIfaceModemFirmware *_self, goto out; } - mm_dbg ("Changing Gobi firmware to MODEM '%s' and PRI '%s' with Build ID '%s'...", - mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), - mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), - unique_id); + mm_obj_dbg (self, "changing Gobi firmware to MODEM '%s' and PRI '%s' with Build ID '%s'...", + mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), + mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), + unique_id); /* Build array of image IDs */ array = g_array_sized_new (FALSE, FALSE, sizeof (QmiMessageDmsSetFirmwarePreferenceInputListImage), 2); @@ -7841,6 +9039,8 @@ firmware_change_current (MMIfaceModemFirmware *_self, input = qmi_message_dms_set_firmware_preference_input_new (); qmi_message_dms_set_firmware_preference_input_set_list (input, array, NULL); + g_array_unref (array); + qmi_client_dms_set_firmware_preference ( QMI_CLIENT_DMS (client), input, @@ -7884,10 +9084,10 @@ signal_check_support (MMIfaceModemSignal *self, QMI_SERVICE_NAS, MM_PORT_QMI_FLAG_DEFAULT, NULL)) { - mm_dbg ("Extended signal capabilities not supported"); + mm_obj_dbg (self, "extended signal capabilities not supported"); g_task_return_boolean (task, FALSE); } else { - mm_dbg ("Extended signal capabilities supported"); + mm_obj_dbg (self, "extended signal capabilities supported"); g_task_return_boolean (task, TRUE); } g_object_unref (task); @@ -7909,40 +9109,35 @@ typedef struct { MMSignal *gsm; MMSignal *umts; MMSignal *lte; + MMSignal *nr5g; } SignalLoadValuesResult; typedef struct { - QmiClientNas *client; - SignalLoadValuesStep step; + QmiClientNas *client; + SignalLoadValuesStep step; SignalLoadValuesResult *values_result; } SignalLoadValuesContext; static void signal_load_values_result_free (SignalLoadValuesResult *result) { - if (result->cdma) - g_object_unref (result->cdma); - if (result->evdo) - g_object_unref (result->evdo); - if (result->gsm) - g_object_unref (result->gsm); - if (result->umts) - g_object_unref (result->umts); - if (result->lte) - g_object_unref (result->lte); + g_clear_object (&result->cdma); + g_clear_object (&result->evdo); + g_clear_object (&result->gsm); + g_clear_object (&result->lte); g_slice_free (SignalLoadValuesResult, result); } static void signal_load_values_context_free (SignalLoadValuesContext *ctx) { - if (ctx->values_result) - signal_load_values_result_free (ctx->values_result); + g_clear_pointer (&ctx->values_result, (GDestroyNotify)signal_load_values_result_free); g_slice_free (SignalLoadValuesContext, ctx); } static gdouble -get_db_from_sinr_level (QmiNasEvdoSinrLevel level) +get_db_from_sinr_level (MMBroadbandModemQmi *self, + QmiNasEvdoSinrLevel level) { switch (level) { case QMI_NAS_EVDO_SINR_LEVEL_0: return -9.0; @@ -7955,20 +9150,21 @@ get_db_from_sinr_level (QmiNasEvdoSinrLevel level) case QMI_NAS_EVDO_SINR_LEVEL_7: return 6; case QMI_NAS_EVDO_SINR_LEVEL_8: return +9; default: - mm_warn ("Invalid SINR level '%u'", level); + mm_obj_warn (self, "invalid SINR level '%u'", level); return -G_MAXDOUBLE; } } static gboolean signal_load_values_finish (MMIfaceModemSignal *self, - GAsyncResult *res, - MMSignal **cdma, - MMSignal **evdo, - MMSignal **gsm, - MMSignal **umts, - MMSignal **lte, - GError **error) + GAsyncResult *res, + MMSignal **cdma, + MMSignal **evdo, + MMSignal **gsm, + MMSignal **umts, + MMSignal **lte, + MMSignal **nr5g, + GError **error) { SignalLoadValuesResult *values_result; @@ -7981,6 +9177,7 @@ signal_load_values_finish (MMIfaceModemSignal *self, *gsm = values_result->gsm ? g_object_ref (values_result->gsm) : NULL; *umts = values_result->umts ? g_object_ref (values_result->umts) : NULL; *lte = values_result->lte ? g_object_ref (values_result->lte) : NULL; + *nr5g = values_result->nr5g ? g_object_ref (values_result->nr5g) : NULL; signal_load_values_result_free (values_result); return TRUE; } @@ -7990,25 +9187,26 @@ static void signal_load_values_context_step (GTask *task); static void signal_load_values_get_signal_strength_ready (QmiClientNas *client, GAsyncResult *res, - GTask *task) -{ - SignalLoadValuesContext *ctx; - QmiMessageNasGetSignalStrengthOutput *output; - GArray *array; - gint32 aux_int32; - gint16 aux_int16; - gint8 aux_int8; - QmiNasRadioInterface radio_interface; - QmiNasEvdoSinrLevel sinr; + GTask *task) +{ + MMBroadbandModemQmi *self; + SignalLoadValuesContext *ctx; + GArray *array; + gint32 aux_int32; + gint16 aux_int16; + gint8 aux_int8; + QmiNasRadioInterface radio_interface; + QmiNasEvdoSinrLevel sinr; + g_autoptr(QmiMessageNasGetSignalStrengthOutput) output = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - ctx = g_task_get_task_data (task); output = qmi_client_nas_get_signal_strength_finish (client, res, NULL); if (!output || !qmi_message_nas_get_signal_strength_output_get_result (output, NULL)) { /* No hard errors, go on to next step */ ctx->step++; signal_load_values_context_step (task); - if (output) - qmi_message_nas_get_signal_strength_output_unref (output); return; } @@ -8131,11 +9329,9 @@ signal_load_values_get_signal_strength_ready (QmiClientNas *client, /* SINR (EV-DO) */ if (qmi_message_nas_get_signal_strength_output_get_sinr (output, &sinr, NULL)) { if (ctx->values_result->evdo) - mm_signal_set_sinr (ctx->values_result->evdo, get_db_from_sinr_level (sinr)); + mm_signal_set_sinr (ctx->values_result->evdo, get_db_from_sinr_level (self, sinr)); } - qmi_message_nas_get_signal_strength_output_unref (output); - /* Go on */ ctx->step++; signal_load_values_context_step (task); @@ -8144,26 +9340,28 @@ signal_load_values_get_signal_strength_ready (QmiClientNas *client, static void signal_load_values_get_signal_info_ready (QmiClientNas *client, GAsyncResult *res, - GTask *task) + GTask *task) { + MMBroadbandModemQmi *self; SignalLoadValuesContext *ctx; - QmiMessageNasGetSignalInfoOutput *output; - gint8 rssi; - gint16 ecio; - QmiNasEvdoSinrLevel sinr_level; - gint32 io; - gint8 rsrq; - gint16 rsrp; - gint16 snr; + gint8 rssi; + gint16 ecio; + QmiNasEvdoSinrLevel sinr_level; + gint32 io; + gint8 rsrq; + gint16 rsrp; + gint16 snr; + gint16 rsrq_5g; + g_autoptr(QmiMessageNasGetSignalInfoOutput) output = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - ctx = g_task_get_task_data (task); output = qmi_client_nas_get_signal_info_finish (client, res, NULL); if (!output || !qmi_message_nas_get_signal_info_output_get_result (output, NULL)) { /* No hard errors, go on to next step */ ctx->step++; signal_load_values_context_step (task); - if (output) - qmi_message_nas_get_signal_info_output_unref (output); return; } @@ -8190,7 +9388,7 @@ signal_load_values_get_signal_info_ready (QmiClientNas *client, ctx->values_result->evdo = mm_signal_new (); mm_signal_set_rssi (ctx->values_result->evdo, (gdouble)rssi); mm_signal_set_ecio (ctx->values_result->evdo, ((gdouble)ecio) * (-0.5)); - mm_signal_set_sinr (ctx->values_result->evdo, get_db_from_sinr_level (sinr_level)); + mm_signal_set_sinr (ctx->values_result->evdo, get_db_from_sinr_level (self, sinr_level)); mm_signal_set_io (ctx->values_result->evdo, (gdouble)io); } @@ -8226,7 +9424,21 @@ signal_load_values_get_signal_info_ready (QmiClientNas *client, mm_signal_set_snr (ctx->values_result->lte, (0.1) * ((gdouble)snr)); } - qmi_message_nas_get_signal_info_output_unref (output); + /* 5G */ + if (qmi_message_nas_get_signal_info_output_get_5g_signal_strength (output, + &rsrp, + &snr, + NULL)) { + ctx->values_result->nr5g = mm_signal_new (); + mm_signal_set_rsrp (ctx->values_result->nr5g, (gdouble)rsrp); + mm_signal_set_snr (ctx->values_result->nr5g, (gdouble)snr); + } + + if (qmi_message_nas_get_signal_info_output_get_5g_signal_strength_extended (output, + &rsrq_5g, + NULL)) { + mm_signal_set_rsrq (ctx->values_result->nr5g, (gdouble)rsrq_5g); + } /* Keep on */ ctx->step++; @@ -8254,22 +9466,18 @@ signal_load_values_context_step (GTask *task) /* Fall through */ case SIGNAL_LOAD_VALUES_STEP_SIGNAL_INFO: - if (qmi_client_check_version (QMI_CLIENT (ctx->client), 1, 8)) { - qmi_client_nas_get_signal_info (ctx->client, - NULL, - 5, - NULL, - (GAsyncReadyCallback)signal_load_values_get_signal_info_ready, - task); - return; - } - ctx->step++; - /* Fall through */ + qmi_client_nas_get_signal_info (ctx->client, + NULL, + 5, + NULL, + (GAsyncReadyCallback)signal_load_values_get_signal_info_ready, + task); + return; case SIGNAL_LOAD_VALUES_STEP_SIGNAL_STRENGTH: /* If already loaded with signal info, don't try signal strength */ if (!VALUES_RESULT_LOADED (ctx)) { - QmiMessageNasGetSignalStrengthInput *input; + g_autoptr(QmiMessageNasGetSignalStrengthInput) input = NULL; input = qmi_message_nas_get_signal_strength_input_new (); qmi_message_nas_get_signal_strength_input_set_request_mask ( @@ -8288,7 +9496,6 @@ signal_load_values_context_step (GTask *task) NULL, (GAsyncReadyCallback)signal_load_values_get_signal_strength_ready, task); - qmi_message_nas_get_signal_strength_input_unref (input); return; } ctx->step++; @@ -8296,22 +9503,15 @@ signal_load_values_context_step (GTask *task) case SIGNAL_LOAD_VALUES_STEP_SIGNAL_LAST: /* If any result is set, succeed */ - if (VALUES_RESULT_LOADED (ctx)) { - SignalLoadValuesResult *values_result; - - /* Steal results from context in order to return them */ - values_result = ctx->values_result; - ctx->values_result = NULL; - + if (VALUES_RESULT_LOADED (ctx)) g_task_return_pointer (task, - values_result, + g_steal_pointer (&ctx->values_result), (GDestroyNotify)signal_load_values_result_free); - } else { + else g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No way to load extended signal information"); - } g_object_unref (task); return; @@ -8325,16 +9525,16 @@ signal_load_values_context_step (GTask *task) } static void -signal_load_values (MMIfaceModemSignal *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +signal_load_values (MMIfaceModemSignal *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { SignalLoadValuesContext *ctx; - GTask *task; - QmiClient *client = NULL; + GTask *task; + QmiClient *client = NULL; - mm_dbg ("loading extended signal information..."); + mm_obj_dbg (self, "loading extended signal information..."); if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), QMI_SERVICE_NAS, &client, @@ -8346,9 +9546,7 @@ signal_load_values (MMIfaceModemSignal *self, ctx->step = SIGNAL_LOAD_VALUES_STEP_SIGNAL_FIRST; task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, - ctx, - (GDestroyNotify)signal_load_values_context_free); + g_task_set_task_data (task, ctx, (GDestroyNotify)signal_load_values_context_free); signal_load_values_context_step (task); } @@ -8357,38 +9555,127 @@ signal_load_values (MMIfaceModemSignal *self, /* First enabling step */ static gboolean -enabling_started_finish (MMBroadbandModem *self, - GAsyncResult *res, - GError **error) +enabling_started_finish (MMBroadbandModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void -parent_enabling_started_ready (MMBroadbandModem *self, - GAsyncResult *res, - GTask *task) +wds_set_autoconnect_settings_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) { - GError *error = NULL; + MMBroadbandModemQmi *self; + g_autoptr(GError) error = NULL; + g_autoptr(QmiMessageWdsSetAutoconnectSettingsOutput) output = NULL; - if (!MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->enabling_started_finish ( - self, - res, - &error)) { + self = g_task_get_source_object (task); + + output = qmi_client_wds_set_autoconnect_settings_finish (client, res, &error); + if (!output || !qmi_message_wds_set_autoconnect_settings_output_get_result (output, &error)) + mm_obj_warn (self, "failed disabling autoconnect: %s", error->message); + else + mm_obj_info (self, "autoconnect explicitly disabled"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +wds_get_autoconnect_settings_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + QmiWdsAutoconnectSetting autoconnect_setting; + g_autoptr(GError) error = NULL; + g_autoptr(QmiMessageWdsSetAutoconnectSettingsInput) input = NULL; + g_autoptr(QmiMessageWdsGetAutoconnectSettingsOutput) output = NULL; + + self = g_task_get_source_object (task); + + output = qmi_client_wds_get_autoconnect_settings_finish (client, res, &error); + if (!output || + !qmi_message_wds_get_autoconnect_settings_output_get_result (output, &error) || + !qmi_message_wds_get_autoconnect_settings_output_get_status (output, &autoconnect_setting, &error)) { + mm_obj_warn (self, "failed checking whether autoconnect is disabled or not: %s", error->message); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + if (autoconnect_setting != QMI_WDS_AUTOCONNECT_SETTING_ENABLED) { + mm_obj_dbg (self, "autoconnect is already disabled"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "need to explicitly disable autoconnect"); + input = qmi_message_wds_set_autoconnect_settings_input_new (); + qmi_message_wds_set_autoconnect_settings_input_set_status (input, QMI_WDS_AUTOCONNECT_SETTING_DISABLED, NULL); + qmi_client_wds_set_autoconnect_settings (client, + input, + 10, + NULL, + (GAsyncReadyCallback) wds_set_autoconnect_settings_ready, + task); +} + +static void +parent_enabling_started_ready (MMBroadbandModem *_self, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); + QmiClient *client = NULL; + g_autoptr(GError) error = NULL; + + if (!MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->enabling_started_finish (_self, res, &error)) { /* Don't treat this as fatal. Parent enabling may fail if it cannot grab a primary * AT port, which isn't really an issue in QMI-based modems */ - mm_dbg ("Couldn't start parent enabling: %s", error->message); - g_error_free (error); + mm_obj_dbg (self, "couldn't start parent enabling: %s", error->message); } - g_task_return_boolean (task, TRUE); - g_object_unref (task); + /* If the autoconnect check has already been done, we're finished */ + if (self->priv->autoconnect_checked) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + /* The connection logic doesn't work properly when the device is already set + * to autoconnect, so automatically disable autoconnect ourselves. */ + mm_obj_dbg (self, "need to check whether autoconnect is disabled or not..."); + self->priv->autoconnect_checked = TRUE; + + /* Use default WDS client to query autoconnect settings */ + client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_WDS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + + if (!client) { + mm_obj_warn (self, "cannot check whether autoconnect is disabled or not: couldn't peek default WDS client"); + /* not fatal, just assume autoconnect is disabled */ + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + qmi_client_wds_get_autoconnect_settings (QMI_CLIENT_WDS (client), + NULL, + 5, + NULL, + (GAsyncReadyCallback) wds_get_autoconnect_settings_ready, + task); } static void -enabling_started (MMBroadbandModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +enabling_started (MMBroadbandModem *self, + GAsyncReadyCallback callback, + gpointer user_data) { GTask *task; @@ -8406,12 +9693,14 @@ enabling_started (MMBroadbandModem *self, static const QmiService qmi_services[] = { QMI_SERVICE_DMS, QMI_SERVICE_NAS, + QMI_SERVICE_WDS, QMI_SERVICE_WMS, QMI_SERVICE_PDS, QMI_SERVICE_OMA, QMI_SERVICE_UIM, QMI_SERVICE_LOC, QMI_SERVICE_PDC, + QMI_SERVICE_VOICE, }; typedef struct { @@ -8450,7 +9739,7 @@ parent_initialization_started_ready (MMBroadbandModem *self, if (error) { /* Don't treat this as fatal. Parent initialization may fail if it cannot grab a primary * AT port, which isn't really an issue in QMI-based modems */ - mm_dbg ("Couldn't start parent initialization: %s", error->message); + mm_obj_dbg (self, "couldn't start parent initialization: %s", error->message); g_error_free (error); } @@ -8476,8 +9765,8 @@ qmi_device_removed_cb (QmiDevice *device, MMBroadbandModemQmi *self) { /* Reprobe the modem here so we can get notifications back. */ - mm_info ("Connection to qmi-proxy for %s lost, reprobing", - qmi_device_get_path_display (device)); + mm_obj_info (self, "connection to qmi-proxy for %s lost, reprobing", + qmi_device_get_path_display (device)); g_signal_handler_disconnect (device, self->priv->qmi_device_removed_id); self->priv->qmi_device_removed_id = 0; @@ -8486,25 +9775,31 @@ qmi_device_removed_cb (QmiDevice *device, mm_base_modem_set_valid (MM_BASE_MODEM (self), FALSE); } -static void -track_qmi_device_removed (MMBroadbandModemQmi *self, - MMPortQmi* qmi) +static gboolean +track_qmi_device_removed (MMBroadbandModemQmi *self, + MMPortQmi *qmi, + GError **error) { QmiDevice *device; device = mm_port_qmi_peek_device (qmi); - g_assert (device); + if (!device) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Cannot track QMI device removal: QMI port no longer available"); + return FALSE; + } self->priv->qmi_device_removed_id = g_signal_connect ( device, QMI_DEVICE_SIGNAL_REMOVED, G_CALLBACK (qmi_device_removed_cb), self); + return TRUE; } static void untrack_qmi_device_removed (MMBroadbandModemQmi *self, - MMPortQmi* qmi) + MMPortQmi *qmi) { QmiDevice *device; @@ -8526,15 +9821,17 @@ qmi_port_allocate_client_ready (MMPortQmi *qmi, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; InitializationStartedContext *ctx; GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!mm_port_qmi_allocate_client_finish (qmi, res, &error)) { - mm_dbg ("Couldn't allocate client for service '%s': %s", - qmi_service_get_string (qmi_services[ctx->service_index]), - error->message); + mm_obj_dbg (self, "couldn't allocate client for service '%s': %s", + qmi_service_get_string (qmi_services[ctx->service_index]), + error->message); g_error_free (error); } @@ -8546,14 +9843,20 @@ static void allocate_next_client (GTask *task) { InitializationStartedContext *ctx; - MMBroadbandModemQmi *self; + MMBroadbandModemQmi *self; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); if (ctx->service_index == G_N_ELEMENTS (qmi_services)) { + GError *error = NULL; + /* Done we are, track device removal and launch parent's callback */ - track_qmi_device_removed (self, ctx->qmi); + if (!track_qmi_device_removed (self, ctx->qmi, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } parent_initialization_started (task); return; } @@ -8589,10 +9892,12 @@ qmi_port_open_ready (MMPortQmi *qmi, GAsyncResult *res, GTask *task) { + MMBroadbandModemQmi *self; InitializationStartedContext *ctx; GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!mm_port_qmi_open_finish (qmi, res, &error)) { /* Really, really old devices (Gobi 1K, 2008-era firmware) may not @@ -8600,7 +9905,7 @@ qmi_port_open_ready (MMPortQmi *qmi, * try without it. The qmi_wwan driver will fix up any issues that * the device might have between raw-ip and 802.3 mode anyway. */ - mm_dbg ("Couldn't open QMI port with data format update: %s", error->message); + mm_obj_dbg (self, "couldn't open QMI port with data format update: %s", error->message); g_error_free (error); mm_port_qmi_open (ctx->qmi, FALSE, @@ -8620,9 +9925,10 @@ initialization_started (MMBroadbandModem *self, { InitializationStartedContext *ctx; GTask *task; + GError *error = NULL; ctx = g_new0 (InitializationStartedContext, 1); - ctx->qmi = mm_base_modem_get_port_qmi (MM_BASE_MODEM (self)); + ctx->qmi = mm_broadband_modem_qmi_get_port_qmi (MM_BROADBAND_MODEM_QMI (self)); task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_started_context_free); @@ -8632,7 +9938,7 @@ initialization_started (MMBroadbandModem *self, g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Cannot initialize: QMI port went missing"); + "Cannot initialize: QMI port no longer available"); g_object_unref (task); return; } @@ -8640,7 +9946,12 @@ initialization_started (MMBroadbandModem *self, if (mm_port_qmi_is_open (ctx->qmi)) { /* Nothing to be done, just track device removal and launch parent's * callback */ - track_qmi_device_removed (MM_BROADBAND_MODEM_QMI (self), ctx->qmi); + if (!track_qmi_device_removed (MM_BROADBAND_MODEM_QMI (self), ctx->qmi, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + parent_initialization_started (task); return; } @@ -8703,9 +10014,9 @@ dispose (GObject *object) MMPortQmi *qmi; /* If any port cleanup is needed, it must be done during dispose(), as - * the modem object will be affected by an explciit g_object_run_dispose() + * the modem object will be affected by an explicit g_object_run_dispose() * that will remove all port references right away */ - qmi = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self)); + qmi = mm_broadband_modem_qmi_peek_port_qmi (self); if (qmi) { /* Disconnect signal handler for qmi-proxy disappearing, if it exists */ untrack_qmi_device_removed (self, qmi); @@ -8766,6 +10077,8 @@ iface_modem_init (MMIfaceModem *iface) /* Enabling/disabling */ iface->modem_power_up = modem_power_up; iface->modem_power_up_finish = modem_power_up_down_off_finish; + iface->fcc_unlock = mm_shared_qmi_fcc_unlock; + iface->fcc_unlock_finish = mm_shared_qmi_fcc_unlock_finish; iface->modem_after_power_up = NULL; iface->modem_after_power_up_finish = NULL; iface->modem_power_down = modem_power_down; @@ -8798,6 +10111,12 @@ iface_modem_init (MMIfaceModem *iface) /* Create QMI-specific SIM */ iface->create_sim = create_sim; iface->create_sim_finish = create_sim_finish; + iface->load_sim_slots = mm_shared_qmi_load_sim_slots; + iface->load_sim_slots_finish = mm_shared_qmi_load_sim_slots_finish; + iface->set_primary_sim_slot = mm_shared_qmi_set_primary_sim_slot; + iface->set_primary_sim_slot_finish = mm_shared_qmi_set_primary_sim_slot_finish; + iface->setup_sim_hot_swap = mm_shared_qmi_setup_sim_hot_swap; + iface->setup_sim_hot_swap_finish = mm_shared_qmi_setup_sim_hot_swap_finish; /* Create QMI-specific bearer */ iface->create_bearer = modem_create_bearer; @@ -8848,14 +10167,31 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface) iface->load_operator_code_finish = modem_3gpp_load_operator_code_finish; iface->load_operator_name = modem_3gpp_load_operator_name; iface->load_operator_name_finish = modem_3gpp_load_operator_name_finish; + iface->load_initial_eps_bearer = modem_3gpp_load_initial_eps_bearer; + iface->load_initial_eps_bearer_finish = modem_3gpp_load_initial_eps_bearer_finish; + iface->load_initial_eps_bearer_settings = modem_3gpp_load_initial_eps_bearer_settings; + iface->load_initial_eps_bearer_settings_finish = modem_3gpp_load_initial_eps_bearer_settings_finish; + iface->set_initial_eps_bearer_settings = modem_3gpp_set_initial_eps_bearer_settings; + iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish; } static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface) { - /* Assume we don't have USSD support */ - iface->check_support = NULL; - iface->check_support_finish = NULL; + iface->check_support = modem_3gpp_ussd_check_support; + iface->check_support_finish = modem_3gpp_ussd_check_support_finish; + iface->setup_unsolicited_events = modem_3gpp_ussd_setup_unsolicited_events; + iface->setup_unsolicited_events_finish = common_3gpp_ussd_setup_cleanup_unsolicited_events_finish; + iface->cleanup_unsolicited_events = modem_3gpp_ussd_cleanup_unsolicited_events; + iface->cleanup_unsolicited_events_finish = common_3gpp_ussd_setup_cleanup_unsolicited_events_finish; + iface->enable_unsolicited_events = modem_3gpp_ussd_enable_unsolicited_events; + iface->enable_unsolicited_events_finish = common_3gpp_ussd_enable_disable_unsolicited_events_finish; + iface->disable_unsolicited_events = modem_3gpp_ussd_disable_unsolicited_events; + iface->disable_unsolicited_events_finish = common_3gpp_ussd_enable_disable_unsolicited_events_finish; + iface->send = modem_3gpp_ussd_send; + iface->send_finish = modem_3gpp_ussd_send_finish; + iface->cancel = modem_3gpp_ussd_cancel; + iface->cancel_finish = modem_3gpp_ussd_cancel_finish; } static void @@ -9003,6 +10339,8 @@ mm_broadband_modem_qmi_class_init (MMBroadbandModemQmiClass *klass) g_type_class_add_private (object_class, sizeof (MMBroadbandModemQmiPrivate)); + klass->peek_port_qmi_for_data = peek_port_qmi_for_data; + object_class->finalize = finalize; object_class->dispose = dispose; diff --git a/src/mm-broadband-modem-qmi.h b/src/mm-broadband-modem-qmi.h index 6c79e5eb..9b712109 100644 --- a/src/mm-broadband-modem-qmi.h +++ b/src/mm-broadband-modem-qmi.h @@ -36,14 +36,31 @@ struct _MMBroadbandModemQmi { struct _MMBroadbandModemQmiClass{ MMBroadbandModemClass parent; + + MMPortQmi * (* peek_port_qmi_for_data) (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error); }; GType mm_broadband_modem_qmi_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBroadbandModemQmi, g_object_unref) -MMBroadbandModemQmi *mm_broadband_modem_qmi_new (const gchar *device, +MMBroadbandModemQmi *mm_broadband_modem_qmi_new (const gchar *device, const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id); + const gchar *plugin, + guint16 vendor_id, + guint16 product_id); + +MMPortQmi *mm_broadband_modem_qmi_peek_port_qmi (MMBroadbandModemQmi *self); +MMPortQmi *mm_broadband_modem_qmi_peek_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error); +MMPortQmi *mm_broadband_modem_qmi_get_port_qmi (MMBroadbandModemQmi *self); +MMPortQmi *mm_broadband_modem_qmi_get_port_qmi_for_data (MMBroadbandModemQmi *self, + MMPort *data, + QmiSioPort *out_sio_port, + GError **error); #endif /* MM_BROADBAND_MODEM_QMI_H */ diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 6b7687f3..e2f4398b 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -48,7 +48,7 @@ #include "mm-sms-part-3gpp.h" #include "mm-call-list.h" #include "mm-base-sim.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-modem-helpers.h" #include "mm-error-helpers.h" #include "mm-port-serial-qcdm.h" @@ -100,12 +100,14 @@ enum { PROP_MODEM_OMA_DBUS_SKELETON, PROP_MODEM_FIRMWARE_DBUS_SKELETON, PROP_MODEM_SIM, + PROP_MODEM_SIM_SLOTS, PROP_MODEM_BEARER_LIST, PROP_MODEM_STATE, PROP_MODEM_3GPP_REGISTRATION_STATE, PROP_MODEM_3GPP_CS_NETWORK_SUPPORTED, PROP_MODEM_3GPP_PS_NETWORK_SUPPORTED, PROP_MODEM_3GPP_EPS_NETWORK_SUPPORTED, + PROP_MODEM_3GPP_5GS_NETWORK_SUPPORTED, PROP_MODEM_3GPP_IGNORED_FACILITY_LOCKS, PROP_MODEM_3GPP_INITIAL_EPS_BEARER, PROP_MODEM_CDMA_CDMA1X_REGISTRATION_STATE, @@ -124,6 +126,7 @@ enum { PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED, PROP_MODEM_CARRIER_CONFIG_MAPPING, + PROP_MODEM_FIRMWARE_IGNORE_CARRIER, PROP_FLOW_CONTROL, PROP_INDICATORS_DISABLED, PROP_LAST @@ -152,6 +155,7 @@ struct _MMBroadbandModemPrivate { /* Properties */ GObject *modem_dbus_skeleton; MMBaseSim *modem_sim; + GPtrArray *modem_sim_slots; MMBearerList *modem_bearer_list; MMModemState modem_state; gchar *carrier_config_mapping; @@ -179,6 +183,7 @@ struct _MMBroadbandModemPrivate { gboolean modem_3gpp_cs_network_supported; gboolean modem_3gpp_ps_network_supported; gboolean modem_3gpp_eps_network_supported; + gboolean modem_3gpp_5gs_network_supported; /* Implementation helpers */ GPtrArray *modem_3gpp_registration_regex; MMModem3gppFacility modem_3gpp_ignored_facility_locks; @@ -249,7 +254,8 @@ struct _MMBroadbandModemPrivate { /*<--- Modem Firmware interface --->*/ /* Properties */ - GObject *modem_firmware_dbus_skeleton; + GObject *modem_firmware_dbus_skeleton; + gboolean modem_firmware_ignore_carrier; }; /*****************************************************************************/ @@ -365,30 +371,6 @@ ports_context_new (void) return ctx; } -/*****************************************************************************/ - -static gboolean -response_processor_string_ignore_at_errors (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, - const GError *error, - GVariant **result, - GError **result_error) -{ - if (error) { - /* Ignore AT errors (ie, ERROR or CMx ERROR) */ - if (error->domain != MM_MOBILE_EQUIPMENT_ERROR || last_command) - *result_error = g_error_copy (error); - - return FALSE; - } - - *result = g_variant_new_string (response); - return TRUE; -} - /*****************************************************************************/ /* Create Bearer (Modem interface) */ @@ -427,7 +409,7 @@ modem_create_bearer (MMIfaceModem *self, task = g_task_new (self, NULL, callback, user_data); /* We just create a MMBroadbandBearer */ - mm_dbg ("Creating Broadband bearer in broadband modem"); + mm_obj_dbg (self, "creating broadband bearer in broadband modem..."); mm_broadband_bearer_new (MM_BROADBAND_MODEM (self), props, NULL, /* cancellable */ @@ -501,6 +483,10 @@ current_capabilities_ws46_test_ready (MMBaseModem *self, const gchar *response; GArray *modes; guint i; + gboolean is_2g = FALSE; + gboolean is_3g = FALSE; + gboolean is_4g = FALSE; + gboolean is_5g = FALSE; ctx = g_task_get_task_data (task); @@ -513,27 +499,37 @@ current_capabilities_ws46_test_ready (MMBaseModem *self, if (!modes) goto out; - /* Add LTE caps if any of the reported modes supports 4G */ + /* Process list of modes to gather supported ones */ for (i = 0; i < modes->len; i++) { - if (g_array_index (modes, MMModemMode, i) & MM_MODEM_MODE_4G) { - ctx->caps |= MM_MODEM_CAPABILITY_LTE; - break; - } - } + if (g_array_index (modes, MMModemMode, i) & MM_MODEM_MODE_2G) + is_2g = TRUE; + if (g_array_index (modes, MMModemMode, i) & MM_MODEM_MODE_3G) + is_3g = TRUE; + if (g_array_index (modes, MMModemMode, i) & MM_MODEM_MODE_4G) + is_4g = TRUE; + if (g_array_index (modes, MMModemMode, i) & MM_MODEM_MODE_5G) + is_5g = TRUE; + } + + /* Add capabilities from modes */ + if (is_2g || is_3g) + ctx->caps |= MM_MODEM_CAPABILITY_GSM_UMTS; + if (is_4g) + ctx->caps |= MM_MODEM_CAPABILITY_LTE; + if (is_5g) + ctx->caps |= MM_MODEM_CAPABILITY_5GNR; /* The +CGSM capability is saying that the modem is a 3GPP modem, but that * doesn't necessarily mean it's a GSM/UMTS modem, it could be a LTE-only - * device. We did add the GSM_UMTS capability when +CGSM was found, so now - * we'll check if the device only reports 4G-only mode, and remove the - * capability if so. + * or 5GNR-only device. We did add the GSM_UMTS capability when +CGSM was + * found, so now we'll check if the device only reports 4G or 5G modes, and + * remove the capability if so. * * Note that we don't change the default +CGSM -> GSM/UMTS logic, we just * fix it up. */ - if ((modes->len == 1) && (g_array_index (modes, MMModemMode, 0) == MM_MODEM_MODE_4G)) { - g_assert (ctx->caps & MM_MODEM_CAPABILITY_LTE); + if ((is_4g || is_5g) && !is_2g && !is_3g) ctx->caps &= ~MM_MODEM_CAPABILITY_GSM_UMTS; - } g_array_unref (modes); @@ -567,27 +563,30 @@ static const ModemCaps modem_caps[] = { { NULL } }; -static gboolean -parse_caps_gcap (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, - const GError *error, - GVariant **variant, - GError **result_error) +static MMBaseModemAtResponseProcessorResult +parse_caps_gcap (MMBaseModem *self, + gpointer none, + const gchar *command, + const gchar *response, + gboolean last_command, + const GError *error, + GVariant **result, + GError **result_error) { const ModemCaps *cap = modem_caps; guint32 ret = 0; + *result = NULL; + *result_error = NULL; + if (!response) - return FALSE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; /* Some modems (Huawei E160g) won't respond to +GCAP with no SIM, but * will respond to ATI. Ignore the error and continue. */ - if (strstr (response, "+CME ERROR:")) - return FALSE; + if (strstr (response, "+CME ERROR:") || (error && error->domain == MM_MOBILE_EQUIPMENT_ERROR)) + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; while (cap->name) { if (strstr (response, cap->name)) @@ -597,22 +596,25 @@ parse_caps_gcap (MMBaseModem *self, /* No result built? */ if (ret == 0) - return FALSE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; - *variant = g_variant_new_uint32 (ret); - return TRUE; + *result = g_variant_new_uint32 (ret); + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } -static gboolean -parse_caps_cpin (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, - const GError *error, - GVariant **result, - GError **result_error) +static MMBaseModemAtResponseProcessorResult +parse_caps_cpin (MMBaseModem *self, + gpointer none, + const gchar *command, + const gchar *response, + gboolean last_command, + const GError *error, + GVariant **result, + GError **result_error) { + *result = NULL; + *result_error = NULL; + if (!response) { if (error && (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) || @@ -621,9 +623,9 @@ parse_caps_cpin (MMBaseModem *self, g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG))) { /* At least, it's a GSM modem */ *result = g_variant_new_uint32 (MM_MODEM_CAPABILITY_GSM_UMTS); - return TRUE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } - return FALSE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; } if (strcasestr (response, "SIM PIN") || @@ -644,23 +646,27 @@ parse_caps_cpin (MMBaseModem *self, strcasestr (response, "READY")) { /* At least, it's a GSM modem */ *result = g_variant_new_uint32 (MM_MODEM_CAPABILITY_GSM_UMTS); - return TRUE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } - return FALSE; + + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; } -static gboolean -parse_caps_cgmm (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, - const GError *error, - GVariant **result, - GError **result_error) +static MMBaseModemAtResponseProcessorResult +parse_caps_cgmm (MMBaseModem *self, + gpointer none, + const gchar *command, + const gchar *response, + gboolean last_command, + const GError *error, + GVariant **result, + GError **result_error) { + *result = NULL; + *result_error = NULL; + if (!response) - return FALSE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; /* This check detects some really old Motorola GPRS dongles and phones */ if (strstr (response, "GSM900") || @@ -669,9 +675,10 @@ parse_caps_cgmm (MMBaseModem *self, strstr (response, "GSM850")) { /* At least, it's a GSM modem */ *result = g_variant_new_uint32 (MM_MODEM_CAPABILITY_GSM_UMTS); - return TRUE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } - return FALSE; + + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; } static const MMBaseModemAtCommand capabilities[] = { @@ -760,6 +767,7 @@ mode_pref_qcdm_ready (MMPortSerialQcdm *port, GAsyncResult *res, GTask *task) { + MMBroadbandModem *self; LoadCapabilitiesContext *ctx; QcdmResult *result; gint err = QCDM_SUCCESS; @@ -767,12 +775,13 @@ mode_pref_qcdm_ready (MMPortSerialQcdm *port, GError *error = NULL; GByteArray *response; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); response = mm_port_serial_qcdm_command_finish (port, res, &error); if (error) { /* Fall back to AT checking */ - mm_dbg ("Failed to load NV ModePref: %s", error->message); + mm_obj_dbg (self, "failed to load NV ModePref: %s", error->message); g_error_free (error); goto at_caps; } @@ -783,7 +792,7 @@ mode_pref_qcdm_ready (MMPortSerialQcdm *port, &err); g_byte_array_unref (response); if (!result) { - mm_dbg ("Failed to parse NV ModePref result: %d", err); + mm_obj_dbg (self, "failed to parse NV ModePref result: %d", err); g_byte_array_unref (response); goto at_caps; } @@ -791,7 +800,7 @@ mode_pref_qcdm_ready (MMPortSerialQcdm *port, err = qcdm_result_get_u8 (result, QCDM_CMD_NV_GET_MODE_PREF_ITEM_MODE_PREF, &pref); qcdm_result_unref (result); if (err) { - mm_dbg ("Failed to read NV ModePref: %d", err); + mm_obj_dbg (self, "failed to read NV ModePref: %d", err); goto at_caps; } @@ -847,8 +856,7 @@ load_current_capabilities_qcdm (GTask *task) g_assert (ctx->qcdm_port); if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->qcdm_port), &error)) { - mm_dbg ("Failed to open QCDM port for NV ModePref request: %s", - error->message); + mm_obj_dbg (self, "failed to open QCDM port for NV ModePref request: %s", error->message); g_error_free (error); ctx->qcdm_port = NULL; load_current_capabilities_at (task); @@ -878,11 +886,10 @@ modem_load_current_capabilities (MMIfaceModem *self, LoadCapabilitiesContext *ctx; GTask *task; - mm_dbg ("loading current capabilities..."); - - ctx = g_slice_new0 (LoadCapabilitiesContext); + mm_obj_dbg (self, "loading current capabilities..."); task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (LoadCapabilitiesContext); g_task_set_task_data (task, ctx, (GDestroyNotify)load_capabilities_context_free); if (mm_base_modem_peek_port_qcdm (MM_BASE_MODEM (self))) @@ -920,14 +927,14 @@ modem_load_manufacturer_finish (MMIfaceModem *self, result = mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error); if (result) { manufacturer = sanitize_info_reply (result, "GMI:"); - mm_dbg ("loaded manufacturer: %s", manufacturer); + mm_obj_dbg (self, "loaded manufacturer: %s", manufacturer); } return manufacturer; } static const MMBaseModemAtCommand manufacturers[] = { - { "+CGMI", 3, TRUE, response_processor_string_ignore_at_errors }, - { "+GMI", 3, TRUE, response_processor_string_ignore_at_errors }, + { "+CGMI", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, + { "+GMI", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, { NULL } }; @@ -936,7 +943,7 @@ modem_load_manufacturer (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading manufacturer..."); + mm_obj_dbg (self, "loading manufacturer..."); mm_base_modem_at_sequence ( MM_BASE_MODEM (self), manufacturers, @@ -960,14 +967,14 @@ modem_load_model_finish (MMIfaceModem *self, result = mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error); if (result) { model = sanitize_info_reply (result, "GMM:"); - mm_dbg ("loaded model: %s", model); + mm_obj_dbg (self, "loaded model: %s", model); } return model; } static const MMBaseModemAtCommand models[] = { - { "+CGMM", 3, TRUE, response_processor_string_ignore_at_errors }, - { "+GMM", 3, TRUE, response_processor_string_ignore_at_errors }, + { "+CGMM", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, + { "+GMM", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, { NULL } }; @@ -976,7 +983,7 @@ modem_load_model (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading model..."); + mm_obj_dbg (self, "loading model..."); mm_base_modem_at_sequence ( MM_BASE_MODEM (self), models, @@ -1000,14 +1007,14 @@ modem_load_revision_finish (MMIfaceModem *self, result = mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error); if (result) { revision = sanitize_info_reply (result, "GMR:"); - mm_dbg ("loaded revision: %s", revision); + mm_obj_dbg (self, "loaded revision: %s", revision); } return revision; } static const MMBaseModemAtCommand revisions[] = { - { "+CGMR", 3, TRUE, response_processor_string_ignore_at_errors }, - { "+GMR", 3, TRUE, response_processor_string_ignore_at_errors }, + { "+CGMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, + { "+GMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, { NULL } }; @@ -1016,7 +1023,7 @@ modem_load_revision (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading revision..."); + mm_obj_dbg (self, "loading revision..."); mm_base_modem_at_sequence ( MM_BASE_MODEM (self), revisions, @@ -1060,14 +1067,14 @@ modem_load_equipment_identifier_finish (MMIfaceModem *self, } else { /* Leave whatever the modem returned alone */ } - mm_dbg ("loaded equipment identifier: %s", equip_id); + mm_obj_dbg (self, "loaded equipment identifier: %s", equip_id); } return equip_id; } static const MMBaseModemAtCommand equipment_identifiers[] = { - { "+CGSN", 3, TRUE, response_processor_string_ignore_at_errors }, - { "+GSN", 3, TRUE, response_processor_string_ignore_at_errors }, + { "+CGSN", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, + { "+GSN", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors }, { NULL } }; @@ -1078,7 +1085,7 @@ modem_load_equipment_identifier (MMIfaceModem *self, { const MMBaseModemAtCommand *commands = equipment_identifiers; - mm_dbg ("loading equipment identifier..."); + mm_obj_dbg (self, "loading equipment identifier..."); /* On CDMA-only (non-3GPP) modems, just try +GSN */ if (mm_iface_modem_is_cdma_only (self)) @@ -1114,9 +1121,9 @@ modem_load_device_identifier_finish (MMIfaceModem *self, GAsyncResult *res, GError **error) { - GError *inner_error = NULL; - gpointer ctx = NULL; - gchar *device_identifier; + GError *inner_error = NULL; + gpointer ctx = NULL; + gchar *device_identifier; mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, &ctx, &inner_error); if (inner_error) { @@ -1125,11 +1132,17 @@ modem_load_device_identifier_finish (MMIfaceModem *self, } g_assert (ctx != NULL); - device_identifier = (mm_broadband_modem_create_device_identifier ( - MM_BROADBAND_MODEM (self), - ((DeviceIdentifierContext *)ctx)->ati, - ((DeviceIdentifierContext *)ctx)->ati1)); - mm_dbg ("loaded device identifier: %s", device_identifier); + device_identifier = mm_broadband_modem_create_device_identifier ( + MM_BROADBAND_MODEM (self), + ((DeviceIdentifierContext *)ctx)->ati, + ((DeviceIdentifierContext *)ctx)->ati1, + &inner_error); + if (!device_identifier) { + g_propagate_error (error, inner_error); + return NULL; + } + + mm_obj_dbg (self, "loaded device identifier: %s", device_identifier); return device_identifier; } @@ -1166,7 +1179,7 @@ modem_load_device_identifier (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading device identifier..."); + mm_obj_dbg (self, "loading device identifier..."); mm_base_modem_at_sequence ( MM_BASE_MODEM (self), device_identifier_steps, @@ -1327,9 +1340,9 @@ modem_load_own_numbers (MMIfaceModem *self, if (mm_port_serial_open (MM_PORT_SERIAL (ctx->qcdm), &error)) { ctx->qcdm = g_object_ref (ctx->qcdm); } else { - mm_dbg ("Couldn't open QCDM port: (%d) %s", - error ? error->code : -1, - error ? error->message : "(unknown)"); + mm_obj_dbg (self, "couldn't open QCDM port: (%d) %s", + error ? error->code : -1, + error ? error->message : "(unknown)"); ctx->qcdm = NULL; } } @@ -1337,7 +1350,7 @@ modem_load_own_numbers (MMIfaceModem *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)own_numbers_context_free); - mm_dbg ("loading own numbers..."); + mm_obj_dbg (self, "loading own numbers..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CNUM", 3, @@ -1448,13 +1461,13 @@ modem_load_unlock_required (MMIfaceModem *self, /* CDMA-only modems don't need this */ if (mm_iface_modem_is_cdma_only (self)) { - mm_dbg ("Skipping unlock check in CDMA-only modem..."); + mm_obj_dbg (self, "skipping unlock check in CDMA-only modem..."); g_task_return_int (task, MM_MODEM_LOCK_NONE); g_object_unref (task); return; } - mm_dbg ("checking if unlock required..."); + mm_obj_dbg (self, "checking if unlock required..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CPIN?", 10, @@ -1514,17 +1527,17 @@ csim_ready (MMBaseModem *self, response = mm_base_modem_at_command_finish (self, res, &error); if (!response) { - mm_dbg ("Couldn't load retry count for lock '%s': %s", - mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock), - error->message); + mm_obj_dbg (self, "couldn't load retry count for lock '%s': %s", + mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock), + error->message); goto next; } val = mm_parse_csim_response (response, &error); if (val < 0) { - mm_dbg ("Couldn't parse retry count value for lock '%s': %s", - mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock), - error->message); + mm_obj_dbg (self, "couldn't parse retry count value for lock '%s': %s", + mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock), + error->message); goto next; } @@ -1640,7 +1653,7 @@ supported_modes_gcap_ready (MMBaseModem *_self, self->priv->modem_cdma_evdo_network_supported = TRUE; g_object_notify (G_OBJECT (self), MM_IFACE_MODEM_CDMA_EVDO_NETWORK_SUPPORTED); } - mm_dbg ("Device allows (CDMA) 3G network mode"); + mm_obj_dbg (self, "device allows (CDMA) 3G network mode"); mode |= MM_MODEM_MODE_3G; } /* IS-707 is the 1xRTT family, which we consider as 2G */ @@ -1649,7 +1662,7 @@ supported_modes_gcap_ready (MMBaseModem *_self, self->priv->modem_cdma_cdma1x_network_supported = TRUE; g_object_notify (G_OBJECT (self), MM_IFACE_MODEM_CDMA_CDMA1X_NETWORK_SUPPORTED); } - mm_dbg ("Device allows (CDMA) 2G network mode"); + mm_obj_dbg (self, "device allows (CDMA) 2G network mode"); mode |= MM_MODEM_MODE_2G; } } @@ -1668,16 +1681,16 @@ supported_modes_gcap_ready (MMBaseModem *_self, } if (error) { - mm_dbg ("Generic query of supported CDMA networks failed: '%s'", error->message); + mm_obj_dbg (self, "generic query of supported CDMA networks failed: '%s'", error->message); g_error_free (error); /* Use defaults */ if (self->priv->modem_cdma_cdma1x_network_supported) { - mm_dbg ("Assuming device allows (CDMA) 2G network mode"); + mm_obj_dbg (self, "assuming device allows (CDMA) 2G network mode"); ctx->mode |= MM_MODEM_MODE_2G; } if (self->priv->modem_cdma_evdo_network_supported) { - mm_dbg ("Assuming device allows (CDMA) 3G network mode"); + mm_obj_dbg (self, "assuming device allows (CDMA) 3G network mode"); ctx->mode |= MM_MODEM_MODE_3G; } } @@ -1702,14 +1715,14 @@ supported_modes_ws46_test_ready (MMBroadbandModem *self, response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (error) { - mm_dbg ("Generic query of supported 3GPP networks with WS46=? failed: '%s'", error->message); + mm_obj_dbg (self, "generic query of supported 3GPP networks with WS46=? failed: '%s'", error->message); g_error_free (error); goto out; } modes = mm_3gpp_parse_ws46_test_response (response, &error); if (!modes) { - mm_dbg ("Parsing WS46=? response failed: '%s'", error->message); + mm_obj_dbg (self, "parsing WS46=? response failed: '%s'", error->message); g_error_free (error); goto out; } @@ -1723,7 +1736,7 @@ supported_modes_ws46_test_ready (MMBroadbandModem *self, ctx->mode |= mode; str = mm_modem_mode_build_string_from_mask (mode); - mm_dbg ("Device allows (3GPP) mode combination: %s", str); + mm_obj_dbg (self, "device allows (3GPP) mode combination: %s", str); g_free (str); } @@ -1756,7 +1769,7 @@ supported_modes_cnti_ready (MMBroadbandModem *self, if (g_strstr_len (lower, -1, "gsm") || g_strstr_len (lower, -1, "gprs") || g_strstr_len (lower, -1, "edge")) { - mm_dbg ("Device allows (3GPP) 2G networks"); + mm_obj_dbg (self, "device allows (3GPP) 2G networks"); mode |= MM_MODEM_MODE_2G; } @@ -1764,12 +1777,12 @@ supported_modes_cnti_ready (MMBroadbandModem *self, g_strstr_len (lower, -1, "hsdpa") || g_strstr_len (lower, -1, "hsupa") || g_strstr_len (lower, -1, "hspa+")) { - mm_dbg ("Device allows (3GPP) 3G networks"); + mm_obj_dbg (self, "device allows (3GPP) 3G networks"); mode |= MM_MODEM_MODE_3G; } if (g_strstr_len (lower, -1, "lte")) { - mm_dbg ("Device allows (3GPP) 4G networks"); + mm_obj_dbg (self, "device allows (3GPP) 4G networks"); mode |= MM_MODEM_MODE_4G; } @@ -1777,11 +1790,11 @@ supported_modes_cnti_ready (MMBroadbandModem *self, /* If no expected ID found, log error */ if (mode == MM_MODEM_MODE_NONE) - mm_dbg ("Invalid list of supported networks reported by *CNTI: '%s'", response); + mm_obj_dbg (self, "invalid list of supported networks reported by *CNTI: '%s'", response); else ctx->mode |= mode; } else { - mm_dbg ("Generic query of supported 3GPP networks with *CNTI failed: '%s'", error->message); + mm_obj_dbg (self, "generic query of supported 3GPP networks with *CNTI failed: '%s'", error->message); g_error_free (error); } @@ -1853,7 +1866,7 @@ modem_load_supported_modes (MMIfaceModem *self, LoadSupportedModesContext *ctx; GTask *task; - mm_dbg ("loading supported modes..."); + mm_obj_dbg (self, "loading supported modes..."); ctx = g_new0 (LoadSupportedModesContext, 1); ctx->mode = MM_MODEM_MODE_NONE; @@ -1906,7 +1919,7 @@ supported_ip_families_cgdcont_test_ready (MMBaseModem *self, if (response) { GList *formats, *l; - formats = mm_3gpp_parse_cgdcont_test_response (response, &error); + formats = mm_3gpp_parse_cgdcont_test_response (response, self, &error); for (l = formats; l; l = g_list_next (l)) mask |= ((MM3gppPdpContextFormat *)(l->data))->pdp_type; @@ -1928,7 +1941,7 @@ modem_load_supported_ip_families (MMIfaceModem *self, { GTask *task; - mm_dbg ("loading supported IP families..."); + mm_obj_dbg (self, "loading supported IP families..."); task = g_task_new (self, NULL, callback, user_data); if (mm_iface_modem_is_cdma_only (self)) { @@ -1982,7 +1995,7 @@ qcdm_evdo_pilot_sets_log_handle (MMPortSerialQcdm *port, &pilot_pn, &pilot_energy, &rssi_dbm)) { - mm_dbg ("EVDO active pilot RSSI: %ddBm", rssi_dbm); + mm_obj_dbg (self, "EVDO active pilot RSSI: %ddBm", rssi_dbm); self->priv->evdo_pilot_rssi = rssi_dbm; } @@ -2083,8 +2096,8 @@ signal_quality_csq_ready (MMBroadbandModem *self, * try the other command if the first one fails. */ static const MMBaseModemAtCommand signal_quality_csq_sequence[] = { - { "+CSQ", 3, FALSE, response_processor_string_ignore_at_errors }, - { "+CSQ?", 3, FALSE, response_processor_string_ignore_at_errors }, + { "+CSQ", 3, FALSE, mm_base_modem_response_processor_string_ignore_at_errors }, + { "+CSQ?", 3, FALSE, mm_base_modem_response_processor_string_ignore_at_errors }, { NULL } }; @@ -2134,14 +2147,11 @@ signal_quality_cind_ready (MMBroadbandModem *self, GAsyncResult *res, GTask *task) { - SignalQualityContext *ctx; GError *error = NULL; const gchar *result; GByteArray *indicators; guint quality = 0; - ctx = g_task_get_task_data (task); - result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (error) { g_clear_error (&error); @@ -2150,19 +2160,17 @@ signal_quality_cind_ready (MMBroadbandModem *self, indicators = mm_3gpp_parse_cind_read_response (result, &error); if (!indicators) { - mm_dbg ("(%s) Could not parse CIND signal quality results: %s", - mm_port_get_device (MM_PORT (ctx->at_port)), - error->message); + mm_obj_dbg (self, "could not parse CIND signal quality results: %s", error->message); g_clear_error (&error); goto try_csq; } if (indicators->len < self->priv->modem_cind_indicator_signal_quality) { - mm_dbg ("(%s) Could not parse CIND signal quality results; signal " - "index (%u) outside received range (0-%u)", - mm_port_get_device (MM_PORT (ctx->at_port)), - self->priv->modem_cind_indicator_signal_quality, - indicators->len); + mm_obj_dbg (self, + "could not parse CIND signal quality results; signal " + "index (%u) outside received range (0-%u)", + self->priv->modem_cind_indicator_signal_quality, + indicators->len); } else { quality = g_array_index (indicators, guint8, @@ -2317,7 +2325,7 @@ modem_load_signal_quality (MMIfaceModem *_self, GError *error = NULL; GTask *task; - mm_dbg ("loading signal quality..."); + mm_obj_dbg (self, "loading signal quality..."); ctx = g_new0 (SignalQualityContext, 1); task = g_task_new (self, NULL, callback, user_data); @@ -2348,7 +2356,7 @@ modem_load_signal_quality (MMIfaceModem *_self, } ctx->qcdm_port = NULL; - mm_dbg ("Couldn't open QCDM port: %s", error->message); + mm_obj_dbg (self, "couldn't open QCDM port: %s", error->message); } /* Return the error we got when getting best AT port */ @@ -2408,24 +2416,25 @@ access_tech_context_free (AccessTechContext *ctx) } static AccessTechAndMask * -access_tech_and_mask_new (AccessTechContext *ctx) +access_tech_and_mask_new (MMBroadbandModem *self, + AccessTechContext *ctx) { AccessTechAndMask *tech; MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; guint mask = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; if (ctx->fallback_mask) { - mm_dbg ("Fallback access technology: 0x%08x", ctx->fallback_act); + mm_obj_dbg (self, "fallback access technology: 0x%08x", ctx->fallback_act); act = ctx->fallback_act; mask = ctx->fallback_mask; goto done; } - mm_dbg ("QCDM operating mode: %d", ctx->opmode); - mm_dbg ("QCDM system mode: %d", ctx->sysmode); - mm_dbg ("QCDM hybrid pref: %d", ctx->hybrid); - mm_dbg ("QCDM WCDMA open: %d", ctx->wcdma_open); - mm_dbg ("QCDM EVDO open: %d", ctx->evdo_open); + mm_obj_dbg (self, "QCDM operating mode: %d", ctx->opmode); + mm_obj_dbg (self, "QCDM system mode: %d", ctx->sysmode); + mm_obj_dbg (self, "QCDM hybrid pref: %d", ctx->hybrid); + mm_obj_dbg (self, "QCDM WCDMA open: %d", ctx->wcdma_open); + mm_obj_dbg (self, "QCDM EVDO open: %d", ctx->evdo_open); if (ctx->opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) { switch (ctx->sysmode) { @@ -2481,6 +2490,7 @@ access_tech_qcdm_wcdma_ready (MMPortSerialQcdm *port, GAsyncResult *res, GTask *task) { + MMBroadbandModem *self; AccessTechContext *ctx; QcdmResult *result; gint err = QCDM_SUCCESS; @@ -2495,6 +2505,7 @@ access_tech_qcdm_wcdma_ready (MMPortSerialQcdm *port, return; } + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); /* Parse the response */ @@ -2513,7 +2524,9 @@ access_tech_qcdm_wcdma_ready (MMPortSerialQcdm *port, ctx->wcdma_open = TRUE; } - g_task_return_pointer (task, access_tech_and_mask_new (ctx), g_free); + g_task_return_pointer (task, + access_tech_and_mask_new (MM_BROADBAND_MODEM (self), ctx), + g_free); g_object_unref (task); } @@ -2581,6 +2594,7 @@ access_tech_qcdm_hdr_ready (MMPortSerialQcdm *port, GAsyncResult *res, GTask *task) { + MMBroadbandModem *self; AccessTechContext *ctx; QcdmResult *result; gint err = QCDM_SUCCESS; @@ -2596,7 +2610,8 @@ access_tech_qcdm_hdr_ready (MMPortSerialQcdm *port, return; } - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); /* Parse the response */ result = qcdm_cmd_hdr_subsys_state_info_result ((const gchar *) response->data, @@ -2614,7 +2629,7 @@ access_tech_qcdm_hdr_ready (MMPortSerialQcdm *port, ctx->evdo_open = TRUE; } - g_task_return_pointer (task, access_tech_and_mask_new (ctx), g_free); + g_task_return_pointer (task, access_tech_and_mask_new (self, ctx), g_free); g_object_unref (task); } @@ -2697,9 +2712,9 @@ access_tech_from_cdma_registration_state (MMBroadbandModem *self, ctx->fallback_mask = MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK; } - mm_dbg ("EVDO registration: %d", self->priv->modem_cdma_evdo_registration_state); - mm_dbg ("CDMA1x registration: %d", self->priv->modem_cdma_cdma1x_registration_state); - mm_dbg ("Fallback access tech: 0x%08x", ctx->fallback_act); + mm_obj_dbg (self, "EVDO registration: %d", self->priv->modem_cdma_evdo_registration_state); + mm_obj_dbg (self, "CDMA1x registration: %d", self->priv->modem_cdma_cdma1x_registration_state); + mm_obj_dbg (self, "fallback access tech: 0x%08x", ctx->fallback_act); } static void @@ -2727,7 +2742,7 @@ modem_load_access_technologies (MMIfaceModem *self, if (mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) { g_object_ref (ctx->port); - mm_dbg ("loading access technologies via QCDM..."); + mm_obj_dbg (self, "loading access technologies via QCDM..."); /* FIXME: we may want to run both the CDMA and 3GPP in sequence to ensure * that a multi-mode device that's in CDMA-mode but still has 3GPP capabilities @@ -2768,7 +2783,7 @@ modem_load_access_technologies (MMIfaceModem *self, } ctx->port = NULL; - mm_dbg ("Couldn't open QCDM port: %s", error->message); + mm_obj_dbg (self, "couldn't open QCDM port: %s", error->message); g_clear_error (&error); } @@ -2778,7 +2793,9 @@ modem_load_access_technologies (MMIfaceModem *self, * guess access technologies from the registration information. */ access_tech_from_cdma_registration_state (MM_BROADBAND_MODEM (self), ctx); - g_task_return_pointer (task, access_tech_and_mask_new (ctx), g_free); + g_task_return_pointer (task, + access_tech_and_mask_new (MM_BROADBAND_MODEM (self), ctx), + g_free); } else { g_task_return_new_error (task, MM_CORE_ERROR, @@ -2818,7 +2835,7 @@ bearer_report_disconnected (MMBaseBearer *bearer, if (mm_base_bearer_get_status (bearer) == MM_BEARER_STATUS_DISCONNECTED) return; - mm_info ("Bearer %s: explicitly disconnected", mm_base_bearer_get_path (bearer)); + mm_obj_info (bearer, "explicitly disconnected"); mm_base_bearer_report_connection_status (bearer, MM_BEARER_CONNECTION_STATUS_DISCONNECTED); } @@ -2845,13 +2862,13 @@ cgev_process_detach (MMBroadbandModem *self, MM3gppCgev type) { if (type == MM_3GPP_CGEV_NW_DETACH) { - mm_info ("network forced PS detach: all contexts have been deactivated"); + mm_obj_info (self, "network forced PS detach: all contexts have been deactivated"); bearer_list_report_disconnections (self, 0); return; } if (type == MM_3GPP_CGEV_ME_DETACH) { - mm_info ("mobile equipment forced PS detach: all contexts have been deactivated"); + mm_obj_info (self, "mobile equipment forced PS detach: all contexts have been deactivated"); bearer_list_report_disconnections (self, 0); return; } @@ -2868,24 +2885,24 @@ cgev_process_primary (MMBroadbandModem *self, guint cid = 0; if (!mm_3gpp_parse_cgev_indication_primary (str, type, &cid, &error)) { - mm_warn ("couldn't parse cid info from +CGEV indication '%s': %s", str, error->message); + mm_obj_warn (self, "couldn't parse cid info from +CGEV indication '%s': %s", str, error->message); g_error_free (error); return; } switch (type) { case MM_3GPP_CGEV_NW_ACT_PRIMARY: - mm_info ("network request to activate context (cid %u)", cid); + mm_obj_info (self, "network request to activate context (cid %u)", cid); break; case MM_3GPP_CGEV_ME_ACT_PRIMARY: - mm_info ("mobile equipment request to activate context (cid %u)", cid); + mm_obj_info (self, "mobile equipment request to activate context (cid %u)", cid); break; case MM_3GPP_CGEV_NW_DEACT_PRIMARY: - mm_info ("network request to deactivate context (cid %u)", cid); + mm_obj_info (self, "network request to deactivate context (cid %u)", cid); bearer_list_report_disconnections (self, cid); break; case MM_3GPP_CGEV_ME_DEACT_PRIMARY: - mm_info ("mobile equipment request to deactivate context (cid %u)", cid); + mm_obj_info (self, "mobile equipment request to deactivate context (cid %u)", cid); bearer_list_report_disconnections (self, cid); break; case MM_3GPP_CGEV_UNKNOWN: @@ -2919,24 +2936,24 @@ cgev_process_secondary (MMBroadbandModem *self, guint cid = 0; if (!mm_3gpp_parse_cgev_indication_secondary (str, type, &p_cid, &cid, NULL, &error)) { - mm_warn ("couldn't parse p_cid/cid info from +CGEV indication '%s': %s", str, error->message); + mm_obj_warn (self, "couldn't parse p_cid/cid info from +CGEV indication '%s': %s", str, error->message); g_error_free (error); return; } switch (type) { case MM_3GPP_CGEV_NW_ACT_SECONDARY: - mm_info ("network request to activate secondary context (cid %u, primary cid %u)", cid, p_cid); + mm_obj_info (self, "network request to activate secondary context (cid %u, primary cid %u)", cid, p_cid); break; case MM_3GPP_CGEV_ME_ACT_SECONDARY: - mm_info ("mobile equipment request to activate secondary context (cid %u, primary cid %u)", cid, p_cid); + mm_obj_info (self, "mobile equipment request to activate secondary context (cid %u, primary cid %u)", cid, p_cid); break; case MM_3GPP_CGEV_NW_DEACT_SECONDARY: - mm_info ("network request to deactivate secondary context (cid %u, primary cid %u)", cid, p_cid); + mm_obj_info (self, "network request to deactivate secondary context (cid %u, primary cid %u)", cid, p_cid); bearer_list_report_disconnections (self, cid); break; case MM_3GPP_CGEV_ME_DEACT_SECONDARY: - mm_info ("mobile equipment request to deactivate secondary context (cid %u, primary cid %u)", cid, p_cid); + mm_obj_info (self, "mobile equipment request to deactivate secondary context (cid %u, primary cid %u)", cid, p_cid); bearer_list_report_disconnections (self, cid); break; case MM_3GPP_CGEV_UNKNOWN: @@ -2971,35 +2988,35 @@ cgev_process_pdp (MMBroadbandModem *self, guint cid = 0; if (!mm_3gpp_parse_cgev_indication_pdp (str, type, &pdp_type, &pdp_addr, &cid, &error)) { - mm_warn ("couldn't parse PDP info from +CGEV indication '%s': %s", str, error->message); + mm_obj_warn (self, "couldn't parse PDP info from +CGEV indication '%s': %s", str, error->message); g_error_free (error); return; } switch (type) { case MM_3GPP_CGEV_REJECT: - mm_info ("network request to activate context (type %s, address %s) has been automatically rejected", pdp_type, pdp_addr); + mm_obj_info (self, "network request to activate context (type %s, address %s) has been automatically rejected", pdp_type, pdp_addr); break; case MM_3GPP_CGEV_NW_REACT: /* NOTE: we don't currently notify about automatic reconnections like this one */ if (cid) - mm_info ("network request to reactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); + mm_obj_info (self, "network request to reactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); else - mm_info ("network request to reactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); + mm_obj_info (self, "network request to reactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); break; case MM_3GPP_CGEV_NW_DEACT_PDP: if (cid) { - mm_info ("network request to deactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); + mm_obj_info (self, "network request to deactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); bearer_list_report_disconnections (self, cid); } else - mm_info ("network request to deactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); + mm_obj_info (self, "network request to deactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); break; case MM_3GPP_CGEV_ME_DEACT_PDP: if (cid) { - mm_info ("mobile equipment request to deactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); + mm_obj_info (self, "mobile equipment request to deactivate context (type %s, address %s, cid %u)", pdp_type, pdp_addr, cid); bearer_list_report_disconnections (self, cid); } else - mm_info ("mobile equipment request to deactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); + mm_obj_info (self, "mobile equipment request to deactivate context (type %s, address %s, cid unknown)", pdp_type, pdp_addr); break; case MM_3GPP_CGEV_UNKNOWN: case MM_3GPP_CGEV_NW_DETACH: @@ -3070,7 +3087,7 @@ cgev_received (MMPortSerialAt *port, break; case MM_3GPP_CGEV_UNKNOWN: default: - mm_dbg ("unhandled +CGEV indication: %s", str); + mm_obj_dbg (self, "unhandled +CGEV indication: %s", str); break; } @@ -3095,9 +3112,9 @@ set_cgev_unsolicited_events_handlers (MMBroadbandModem *self, continue; /* Set/unset unsolicited CGEV event handler */ - mm_dbg ("(%s) %s 3GPP +CGEV unsolicited events handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s 3GPP +CGEV unsolicited events handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], cgev_regex, @@ -3116,7 +3133,7 @@ ciev_signal_received (MMBroadbandModem *self, guint quality; if (!mm_get_uint_from_match_info (match_info, 2, &quality)) { - mm_dbg ("Couldn't parse signal quality value from +CIEV"); + mm_obj_dbg (self, "couldn't parse signal quality value from +CIEV"); return; } @@ -3171,9 +3188,9 @@ set_ciev_unsolicited_events_handlers (MMBroadbandModem *self, continue; /* Set/unset unsolicited CIEV event handler */ - mm_dbg ("(%s) %s 3GPP +CIEV unsolicited events handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s 3GPP +CIEV unsolicited events handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], ciev_regex, @@ -3214,12 +3231,13 @@ cgerep_format_check_ready (MMBroadbandModem *self, result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!result) { - mm_dbg ("+CGEREP check failed, marking packet domain event reporting as unsupported: '%s'", error->message); + mm_obj_dbg (self, "+CGEREP check failed: %s", error->message); + mm_obj_dbg (self, "packet domain event reporting is unsupported"); g_error_free (error); goto out; } - mm_dbg ("Modem supports packet domain event reporting"); + mm_obj_dbg (self, "packet domain event reporting is supported"); self->priv->modem_cgerep_supported = TRUE; out: @@ -3239,18 +3257,19 @@ cmer_format_check_ready (MMBroadbandModem *self, gchar *aux; result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); - if (error || !mm_3gpp_parse_cmer_test_response (result, &supported_modes, &supported_inds, &error)) { - mm_dbg ("+CMER check failed, marking indications as unsupported: '%s'", error->message); + if (error || !mm_3gpp_parse_cmer_test_response (result, self, &supported_modes, &supported_inds, &error)) { + mm_obj_dbg (self, "+CMER check failed: %s", error->message); + mm_obj_dbg (self, "generic indications are unsupported"); g_error_free (error); goto out; } aux = mm_3gpp_cmer_mode_build_string_from_mask (supported_modes); - mm_dbg ("Supported +CMER modes: %s", aux); + mm_obj_dbg (self, "supported +CMER modes: %s", aux); g_free (aux); aux = mm_3gpp_cmer_ind_build_string_from_mask (supported_inds); - mm_dbg ("Supported +CMER indication settings: %s", aux); + mm_obj_dbg (self, "supported +CMER indication settings: %s", aux); g_free (aux); /* Flag +CMER supported values */ @@ -3263,14 +3282,14 @@ cmer_format_check_ready (MMBroadbandModem *self, self->priv->modem_cmer_enable_mode = MM_3GPP_CMER_MODE_DISCARD_URCS_IF_LINK_RESERVED; aux = mm_3gpp_cmer_mode_build_string_from_mask (self->priv->modem_cmer_enable_mode); - mm_dbg ("+CMER enable mode: %s", aux); + mm_obj_dbg (self, "+CMER enable mode: %s", aux); g_free (aux); if (supported_modes & MM_3GPP_CMER_MODE_DISCARD_URCS) self->priv->modem_cmer_disable_mode = MM_3GPP_CMER_MODE_DISCARD_URCS; aux = mm_3gpp_cmer_mode_build_string_from_mask (self->priv->modem_cmer_disable_mode); - mm_dbg ("+CMER disable mode: %s", aux); + mm_obj_dbg (self, "+CMER disable mode: %s", aux); g_free (aux); if (supported_inds & MM_3GPP_CMER_IND_ENABLE_NOT_CAUSED_BY_CIND) @@ -3279,7 +3298,7 @@ cmer_format_check_ready (MMBroadbandModem *self, self->priv->modem_cmer_ind = MM_3GPP_CMER_IND_ENABLE_ALL; aux = mm_3gpp_cmer_ind_build_string_from_mask (self->priv->modem_cmer_ind); - mm_dbg ("+CMER indication setting: %s", aux); + mm_obj_dbg (self, "+CMER indication setting: %s", aux); g_free (aux); out: @@ -3301,7 +3320,8 @@ cind_format_check_ready (MMBroadbandModem *self, if (error || !(indicators = mm_3gpp_parse_cind_test_response (result, &error))) { /* unsupported indications */ - mm_dbg ("+CIND check failed, marking indications as unsupported: '%s'", error->message); + mm_obj_dbg (self, "+CIND check failed: %s", error->message); + mm_obj_dbg (self, "generic indications are unsupported"); g_error_free (error); /* go on with remaining checks */ check_and_setup_3gpp_urc_support (task); @@ -3319,11 +3339,10 @@ cind_format_check_ready (MMBroadbandModem *self, self->priv->modem_cind_min_signal_quality = mm_3gpp_cind_response_get_min (r); self->priv->modem_cind_max_signal_quality = mm_3gpp_cind_response_get_max (r); - mm_dbg ("Modem supports signal quality indications via CIND at index '%u'" - "(min: %u, max: %u)", - self->priv->modem_cind_indicator_signal_quality, - self->priv->modem_cind_min_signal_quality, - self->priv->modem_cind_max_signal_quality); + mm_obj_dbg (self, "signal quality indications via CIND are supported at index '%u' (min: %u, max: %u)", + self->priv->modem_cind_indicator_signal_quality, + self->priv->modem_cind_min_signal_quality, + self->priv->modem_cind_max_signal_quality); } else self->priv->modem_cind_indicator_signal_quality = CIND_INDICATOR_INVALID; @@ -3331,8 +3350,8 @@ cind_format_check_ready (MMBroadbandModem *self, r = g_hash_table_lookup (indicators, "roam"); if (r) { self->priv->modem_cind_indicator_roaming = mm_3gpp_cind_response_get_index (r); - mm_dbg ("Modem supports roaming indications via CIND at index '%u'", - self->priv->modem_cind_indicator_roaming); + mm_obj_dbg (self, "roaming indications via CIND are supported at index '%u'", + self->priv->modem_cind_indicator_roaming); } else self->priv->modem_cind_indicator_roaming = CIND_INDICATOR_INVALID; @@ -3340,8 +3359,8 @@ cind_format_check_ready (MMBroadbandModem *self, r = g_hash_table_lookup (indicators, "service"); if (r) { self->priv->modem_cind_indicator_service = mm_3gpp_cind_response_get_index (r); - mm_dbg ("Modem supports service indications via CIND at index '%u'", - self->priv->modem_cind_indicator_service); + mm_obj_dbg (self, "service indications via CIND are supported at index '%u'", + self->priv->modem_cind_indicator_service); } else self->priv->modem_cind_indicator_service = CIND_INDICATOR_INVALID; @@ -3365,7 +3384,7 @@ check_and_setup_3gpp_urc_support (GTask *task) /* Check support for +CIEV indications, managed with +CIND/+CMER */ if (!self->priv->modem_cind_disabled && !self->priv->modem_cind_support_checked) { - mm_dbg ("Checking indicator support..."); + mm_obj_dbg (self, "checking indicator support..."); self->priv->modem_cind_support_checked = TRUE; mm_base_modem_at_command (MM_BASE_MODEM (self), "+CIND=?", @@ -3378,7 +3397,7 @@ check_and_setup_3gpp_urc_support (GTask *task) /* Check support for +CGEV indications, managed with +CGEREP */ if (!self->priv->modem_cgerep_support_checked) { - mm_dbg ("Checking packet domain event reporting..."); + mm_obj_dbg (self, "checking packet domain event reporting..."); self->priv->modem_cgerep_support_checked = TRUE; mm_base_modem_at_command (MM_BASE_MODEM (self), "+CGEREP=?", @@ -3471,9 +3490,9 @@ unsolicited_events_setup_ready (MMBroadbandModem *self, ctx = g_task_get_task_data (task); if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error)) { - mm_dbg ("Couldn't %s event reporting: '%s'", - ctx->enable ? "enable" : "disable", - error->message); + mm_obj_dbg (self, "couldn't %s event reporting: '%s'", + ctx->enable ? "enable" : "disable", + error->message); g_error_free (error); } @@ -3494,28 +3513,28 @@ run_unsolicited_events_setup (GTask *task) /* CMER on primary port */ if (!ctx->cmer_primary_done && ctx->cmer_command && ctx->primary && !self->priv->modem_cind_disabled) { - mm_dbg ("%s +CIND event reporting in primary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CIND event reporting in primary port...", ctx->enable ? "enabling" : "disabling"); ctx->cmer_primary_done = TRUE; command = ctx->cmer_command; port = ctx->primary; } /* CMER on secondary port */ else if (!ctx->cmer_secondary_done && ctx->cmer_command && ctx->secondary && !self->priv->modem_cind_disabled) { - mm_dbg ("%s +CIND event reporting in secondary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CIND event reporting in secondary port...", ctx->enable ? "enabling" : "disabling"); ctx->cmer_secondary_done = TRUE; command = ctx->cmer_command; port = ctx->secondary; } /* CGEREP on primary port */ else if (!ctx->cgerep_primary_done && ctx->cgerep_command && ctx->primary) { - mm_dbg ("%s +CGEV event reporting in primary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CGEV event reporting in primary port...", ctx->enable ? "enabling" : "disabling"); ctx->cgerep_primary_done = TRUE; command = ctx->cgerep_command; port = ctx->primary; } /* CGEREP on secondary port */ else if (!ctx->cgerep_secondary_done && ctx->cgerep_command && ctx->secondary) { - mm_dbg ("%s +CGEV event reporting in secondary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CGEV event reporting in secondary port...", ctx->enable ? "enabling" : "disabling"); ctx->cgerep_secondary_done = TRUE; port = ctx->secondary; command = ctx->cgerep_command; @@ -3796,7 +3815,7 @@ modem_load_supported_charsets (MMIfaceModem *self, /* CDMA-only modems don't need this */ if (mm_iface_modem_is_cdma_only (self)) { - mm_dbg ("Skipping supported charset loading in CDMA-only modem..."); + mm_obj_dbg (self, "skipping supported charset loading in CDMA-only modem..."); g_task_return_int (task, MM_MODEM_CHARSET_UNKNOWN); g_object_unref (task); return; @@ -3845,7 +3864,7 @@ ifc_test_ready (MMBaseModem *_self, goto out; /* Parse response */ - flow_control_supported = mm_parse_ifc_test_response (response, &error); + flow_control_supported = mm_parse_ifc_test_response (response, self, &error); if (flow_control_supported == MM_FLOW_CONTROL_UNKNOWN) goto out; flow_control_supported_str = mm_flow_control_build_string_from_mask (flow_control_supported); @@ -3872,7 +3891,7 @@ ifc_test_ready (MMBaseModem *_self, return; } - mm_dbg ("Flow control settings explicitly requested (%s)", flow_control_requested_str); + mm_obj_dbg (self, "flow control settings explicitly requested: %s", flow_control_requested_str); flow_control_selected = flow_control_requested; flow_control_selected_str = flow_control_requested_str; } else { @@ -3891,7 +3910,7 @@ ifc_test_ready (MMBaseModem *_self, else g_assert_not_reached (); flow_control_selected_str = mm_flow_control_build_string_from_mask (flow_control_selected); - mm_dbg ("Flow control settings automatically selected (%s)", flow_control_selected_str); + mm_obj_dbg (self, "flow control settings automatically selected: %s", flow_control_selected_str); } /* Select flow control for all connections */ @@ -3921,7 +3940,7 @@ ifc_test_ready (MMBaseModem *_self, /* Ignore errors */ if (error) { - mm_dbg ("couldn't load supported flow control methods: %s", error->message); + mm_obj_dbg (self, "couldn't load supported flow control methods: %s", error->message); g_error_free (error); } @@ -3995,13 +4014,13 @@ modem_load_power_state (MMIfaceModem *self, /* CDMA-only modems don't need this */ if (mm_iface_modem_is_cdma_only (self)) { - mm_dbg ("Assuming full power state in CDMA-only modem..."); + mm_obj_dbg (self, "assuming full power state in CDMA-only modem..."); g_task_return_int (task, MM_MODEM_POWER_STATE_ON); g_object_unref (task); return; } - mm_dbg ("loading power state..."); + mm_obj_dbg (self, "loading power state..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CFUN?", 3, @@ -4033,7 +4052,7 @@ modem_power_up (MMIfaceModem *self, /* CDMA-only modems don't need this */ if (mm_iface_modem_is_cdma_only (self)) - mm_dbg ("Skipping Power-up in CDMA-only modem..."); + mm_obj_dbg (self, "skipping power-up in CDMA-only modem..."); else mm_base_modem_at_command (MM_BASE_MODEM (self), "+CFUN=1", @@ -4095,22 +4114,23 @@ load_sim_identifier_ready (MMBaseSim *sim, } if (ctx->retries > 0) { - mm_warn ("could not load SIM identifier: %s (%d retries left)", - error->message, ctx->retries); + mm_obj_warn (self, "could not load SIM identifier: %s (%d retries left)", + error->message, ctx->retries); --ctx->retries; g_clear_error (&error); g_timeout_add_seconds (1, (GSourceFunc) load_sim_identifier, task); return; } - mm_warn ("could not load SIM identifier: %s", error->message); + mm_obj_warn (self, "could not load SIM identifier: %s", error->message); g_task_return_error (task, error); goto out; } if (g_strcmp0 (current_simid, cached_simid) != 0) { - mm_info ("sim identifier has changed: possible SIM swap during power down/low"); - mm_broadband_modem_update_sim_hot_swap_detected (self); + mm_obj_info (self, "sim identifier has changed: %s -> %s - possible SIM swap", + cached_simid, current_simid); + mm_broadband_modem_sim_hot_swap_detected (self); } g_task_return_boolean (task, TRUE); @@ -4135,13 +4155,14 @@ load_sim_identifier (GTask *task) static void modem_check_for_sim_swap (MMIfaceModem *self, + const gchar *iccid, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; SimSwapContext *ctx; - mm_dbg ("Checking if SIM was swapped..."); + mm_obj_dbg (self, "checking if SIM was swapped..."); task = g_task_new (self, NULL, callback, user_data); ctx = g_slice_new0 (SimSwapContext); @@ -4152,10 +4173,42 @@ modem_check_for_sim_swap (MMIfaceModem *self, MM_IFACE_MODEM_SIM, &ctx->sim, NULL); if (!ctx->sim) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "could not acquire sim object"); + MMModemState modem_state; + + modem_state = MM_MODEM_STATE_UNKNOWN; + g_object_get (self, + MM_IFACE_MODEM_STATE, &modem_state, + NULL); + + if (modem_state == MM_MODEM_STATE_FAILED) { + mm_obj_info (self, "new SIM detected, handle as SIM hot-swap"); + mm_broadband_modem_sim_hot_swap_detected (MM_BROADBAND_MODEM (self)); + g_task_return_boolean (task, TRUE); + } else { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "could not acquire sim object"); + } + g_object_unref (task); + return; + } + + /* We may or may not get the new SIM identifier (iccid). In case + * we've got it, the load_sim_identifier phase can be skipped. */ + if (iccid) { + const gchar *cached_simid; + + cached_simid = mm_gdbus_sim_get_sim_identifier (MM_GDBUS_SIM (ctx->sim)); + if (!cached_simid || g_strcmp0 (iccid, cached_simid) != 0) { + mm_obj_info (self, "detected ICCID change (%s -> %s), handle as SIM hot-swap", + cached_simid ? cached_simid : "", + iccid); + mm_broadband_modem_sim_hot_swap_detected (MM_BROADBAND_MODEM (self)); + } else + mm_obj_dbg (self, "ICCID not changed"); + + g_task_return_boolean (task, TRUE); g_object_unref (task); return; } @@ -4217,7 +4270,7 @@ modem_3gpp_load_imei_finish (MMIfaceModem3gpp *self, result = mm_strip_tag (result, "+CGSN:"); mm_parse_gsn (result, &imei, NULL, NULL); - mm_dbg ("loaded IMEI: %s", imei); + mm_obj_dbg (self, "loaded IMEI: %s", imei); return imei; } @@ -4226,7 +4279,7 @@ modem_3gpp_load_imei (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading IMEI..."); + mm_obj_dbg (self, "loading IMEI..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CGSN", 3, @@ -4360,7 +4413,7 @@ clck_test_ready (MMBaseModem *self, gchar *str; str = mm_modem_3gpp_facility_build_string_from_mask (MM_BROADBAND_MODEM (self)->priv->modem_3gpp_ignored_facility_locks); - mm_dbg ("Ignoring facility locks: '%s'", str); + mm_obj_dbg (self, "ignoring facility locks: '%s'", str); g_free (str); ctx->facilities &= ~MM_BROADBAND_MODEM (self)->priv->modem_3gpp_ignored_facility_locks; @@ -4386,7 +4439,7 @@ modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, g_free); - mm_dbg ("loading enabled facility locks..."); + mm_obj_dbg (self, "loading enabled facility locks..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CLCK=?", 3, @@ -4418,9 +4471,9 @@ modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *self, error)) return NULL; - mm_3gpp_normalize_operator (&operator_code, MM_BROADBAND_MODEM (self)->priv->modem_current_charset); + mm_3gpp_normalize_operator (&operator_code, MM_BROADBAND_MODEM (self)->priv->modem_current_charset, self); if (operator_code) - mm_dbg ("loaded Operator Code: %s", operator_code); + mm_obj_dbg (self, "loaded Operator Code: %s", operator_code); return operator_code; } @@ -4429,7 +4482,7 @@ modem_3gpp_load_operator_code (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading Operator Code..."); + mm_obj_dbg (self, "loading Operator Code..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+COPS=3,2", 3, FALSE, NULL, NULL); mm_base_modem_at_command (MM_BASE_MODEM (self), "+COPS?", 3, FALSE, callback, user_data); } @@ -4457,9 +4510,9 @@ modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *self, error)) return NULL; - mm_3gpp_normalize_operator (&operator_name, MM_BROADBAND_MODEM (self)->priv->modem_current_charset); + mm_3gpp_normalize_operator (&operator_name, MM_BROADBAND_MODEM (self)->priv->modem_current_charset, self); if (operator_name) - mm_dbg ("loaded Operator Name: %s", operator_name); + mm_obj_dbg (self, "loaded Operator Name: %s", operator_name); return operator_name; } @@ -4468,7 +4521,7 @@ modem_3gpp_load_operator_name (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading Operator Name..."); + mm_obj_dbg (self, "loading Operator Name..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+COPS=3,0", 3, FALSE, NULL, NULL); mm_base_modem_at_command (MM_BASE_MODEM (self), "+COPS?", 3, FALSE, callback, user_data); } @@ -4496,7 +4549,7 @@ modem_3gpp_load_eps_ue_mode_operation (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading UE mode of operation for EPS..."); + mm_obj_dbg (self, "loading UE mode of operation for EPS..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+CEMODE?", 3, @@ -4524,7 +4577,7 @@ modem_3gpp_set_eps_ue_mode_operation (MMIfaceModem3gpp *self, { gchar *cmd; - mm_dbg ("updating UE mode of operation for EPS..."); + mm_obj_dbg (self, "updating UE mode of operation for EPS..."); cmd = mm_3gpp_build_cemode_set_request (mode); mm_base_modem_at_command (MM_BASE_MODEM (self), cmd, @@ -4556,18 +4609,21 @@ registration_state_changed (MMPortSerialAt *port, MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; gboolean cgreg = FALSE; gboolean cereg = FALSE; + gboolean c5greg = FALSE; GError *error = NULL; if (!mm_3gpp_parse_creg_response (match_info, + self, &state, &lac, &cell_id, &act, &cgreg, &cereg, + &c5greg, &error)) { - mm_warn ("error parsing unsolicited registration: %s", - error && error->message ? error->message : "(unknown)"); + mm_obj_warn (self, "error parsing unsolicited registration: %s", + error && error->message ? error->message : "(unknown)"); g_clear_error (&error); return; } @@ -4575,7 +4631,7 @@ registration_state_changed (MMPortSerialAt *port, /* Report new registration state and fix LAC/TAC. * According to 3GPP TS 27.007: * - If CREG reports 7 (LTE) then the field contains TAC - * - CEREG always reports TAC + * - CEREG/C5GREG always reports TAC */ if (cgreg) mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), state); @@ -4583,6 +4639,10 @@ registration_state_changed (MMPortSerialAt *port, tac = lac; lac = 0; mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), state); + } else if (c5greg) { + tac = lac; + lac = 0; + mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), state); } else { if (act == MM_MODEM_ACCESS_TECHNOLOGY_LTE) { tac = lac; @@ -4623,8 +4683,8 @@ modem_3gpp_setup_unsolicited_registration_events (MMIfaceModem3gpp *self, if (!ports[i]) continue; - mm_dbg ("(%s) setting up 3GPP unsolicited registration messages handlers", - mm_port_get_device (MM_PORT (ports[i]))); + mm_obj_dbg (self, "setting up 3GPP unsolicited registration messages handlers in %s", + mm_port_get_device (MM_PORT (ports[i]))); for (j = 0; j < array->len; j++) { mm_port_serial_at_add_unsolicited_msg_handler ( MM_PORT_SERIAL_AT (ports[i]), @@ -4672,9 +4732,8 @@ modem_3gpp_cleanup_unsolicited_registration_events (MMIfaceModem3gpp *self, if (!ports[i]) continue; - mm_dbg ("(%s) cleaning up unsolicited registration messages handlers", - mm_port_get_device (MM_PORT (ports[i]))); - + mm_obj_dbg (self, "cleaning up unsolicited registration messages handlers in %s", + mm_port_get_device (MM_PORT (ports[i]))); for (j = 0; j < array->len; j++) { mm_port_serial_at_add_unsolicited_msg_handler ( MM_PORT_SERIAL_AT (ports[i]), @@ -4705,7 +4764,7 @@ modem_3gpp_scan_networks_finish (MMIfaceModem3gpp *self, if (!result) return NULL; - return mm_3gpp_parse_cops_test_response (result, MM_BROADBAND_MODEM (self)->priv->modem_current_charset, error); + return mm_3gpp_parse_cops_test_response (result, MM_BROADBAND_MODEM (self)->priv->modem_current_charset, self, error); } static void @@ -4747,27 +4806,37 @@ cops_set_ready (MMBaseModem *self, } static void -cops_ascii_set_ready (MMBaseModem *self, +cops_ascii_set_ready (MMBaseModem *_self, GAsyncResult *res, GTask *task) { - GError *error = NULL; + MMBroadbandModem *self = MM_BROADBAND_MODEM (_self); + g_autoptr(GError) error = NULL; - if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (self), res, &error)) { + if (!mm_base_modem_at_command_full_finish (_self, res, &error)) { /* If it failed with an unsupported error, retry with current modem charset */ if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED)) { - gchar *operator_id; - gchar *operator_id_current_charset; + g_autoptr(GError) enc_error = NULL; + g_autofree gchar *operator_id_enc = NULL; + gchar *operator_id; + /* try to encode to current charset */ operator_id = g_task_get_task_data (task); - operator_id_current_charset = mm_broadband_modem_take_and_convert_to_current_charset (MM_BROADBAND_MODEM (self), g_strdup (operator_id)); + operator_id_enc = mm_modem_charset_str_from_utf8 (operator_id, self->priv->modem_current_charset, FALSE, &enc_error); + if (!operator_id_enc) { + mm_obj_dbg (self, "couldn't convert operator id to current charset: %s", enc_error->message); + g_task_return_error (task, g_steal_pointer (&error)); + g_object_unref (task); + return; + } - if (g_strcmp0 (operator_id, operator_id_current_charset) != 0) { - gchar *command; + /* retry only if encoded string is different to the non-encoded one */ + if (g_strcmp0 (operator_id, operator_id_enc) != 0) { + g_autofree gchar *command = NULL; - command = g_strdup_printf ("+COPS=1,2,\"%s\"", operator_id_current_charset); - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL), + command = g_strdup_printf ("+COPS=1,2,\"%s\"", operator_id_enc); + mm_base_modem_at_command_full (_self, + mm_base_modem_peek_best_at_port (_self, NULL), command, 120, FALSE, @@ -4775,16 +4844,10 @@ cops_ascii_set_ready (MMBaseModem *self, g_task_get_cancellable (task), (GAsyncReadyCallback)cops_set_ready, task); - g_error_free (error); - g_free (operator_id_current_charset); - g_free (command); return; } - /* operator id string would be the same on the current charset, - * so fallback and return the not supported error */ - g_free (operator_id_current_charset); } - g_task_return_error (task, error); + g_task_return_error (task, g_steal_pointer (&error)); } else g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -4840,46 +4903,65 @@ modem_3gpp_register_in_network (MMIfaceModem3gpp *self, /* Registration checks (3GPP interface) */ typedef struct { - gboolean cs_supported; - gboolean ps_supported; - gboolean eps_supported; + gboolean is_cs_supported; + gboolean is_ps_supported; + gboolean is_eps_supported; + gboolean is_5gs_supported; gboolean run_cs; gboolean run_ps; gboolean run_eps; + gboolean run_5gs; gboolean running_cs; gboolean running_ps; gboolean running_eps; - GError *cs_error; - GError *ps_error; - GError *eps_error; + gboolean running_5gs; + GError *error_cs; + GError *error_ps; + GError *error_eps; + GError *error_5gs; } RunRegistrationChecksContext; static void run_registration_checks_context_free (RunRegistrationChecksContext *ctx) { - if (ctx->cs_error) - g_error_free (ctx->cs_error); - if (ctx->ps_error) - g_error_free (ctx->ps_error); - if (ctx->eps_error) - g_error_free (ctx->eps_error); + g_clear_error (&ctx->error_cs); + g_clear_error (&ctx->error_ps); + g_clear_error (&ctx->error_eps); + g_clear_error (&ctx->error_5gs); g_free (ctx); } static gboolean -modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) +modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void run_registration_checks_context_step (GTask *task); +static void +run_registration_checks_context_set_error (RunRegistrationChecksContext *ctx, + GError *error) +{ + g_assert (error != NULL); + if (ctx->running_cs) + ctx->error_cs = error; + else if (ctx->running_ps) + ctx->error_ps = error; + else if (ctx->running_eps) + ctx->error_eps = error; + else if (ctx->running_5gs) + ctx->error_5gs = error; + else + g_assert_not_reached (); +} + static void registration_status_check_ready (MMBroadbandModem *self, - GAsyncResult *res, - GTask *task) + GAsyncResult *res, + GTask *task) { RunRegistrationChecksContext *ctx; const gchar *response; @@ -4887,31 +4969,23 @@ registration_status_check_ready (MMBroadbandModem *self, GMatchInfo *match_info = NULL; guint i; gboolean parsed; - gboolean cgreg; - gboolean cereg; - MMModem3gppRegistrationState state; - MMModemAccessTechnology act; - gulong lac; - gulong tac; - gulong cid; + gboolean cgreg = FALSE; + gboolean cereg = FALSE; + gboolean c5greg = FALSE; + MMModem3gppRegistrationState state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + gulong lac = 0; + gulong tac = 0; + gulong cid = 0; ctx = g_task_get_task_data (task); /* Only one must be running */ - g_assert ((ctx->running_cs ? 1 : 0) + - (ctx->running_ps ? 1 : 0) + - (ctx->running_eps ? 1 : 0) == 1); + g_assert ((ctx->running_cs + ctx->running_ps + ctx->running_eps + ctx->running_5gs) == 1); response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (!response) { - g_assert (error != NULL); - if (ctx->running_cs) - ctx->cs_error = error; - else if (ctx->running_ps) - ctx->ps_error = error; - else - ctx->eps_error = error; - + run_registration_checks_context_set_error (ctx, error); run_registration_checks_context_step (task); return; } @@ -4929,8 +5003,7 @@ registration_status_check_ready (MMBroadbandModem *self, for (i = 0; i < self->priv->modem_3gpp_registration_regex->len; i++) { - if (g_regex_match ((GRegex *)g_ptr_array_index ( - self->priv->modem_3gpp_registration_regex, i), + if (g_regex_match ((GRegex *)g_ptr_array_index (self->priv->modem_3gpp_registration_regex, i), response, 0, &match_info)) @@ -4944,31 +5017,20 @@ registration_status_check_ready (MMBroadbandModem *self, MM_CORE_ERROR_FAILED, "Unknown registration status response: '%s'", response); - if (ctx->running_cs) - ctx->cs_error = error; - else if (ctx->running_ps) - ctx->ps_error = error; - else - ctx->eps_error = error; - + run_registration_checks_context_set_error (ctx, error); run_registration_checks_context_step (task); return; } - cgreg = FALSE; - cereg = FALSE; - state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; - act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - tac = 0; - lac = 0; - cid = 0; parsed = mm_3gpp_parse_creg_response (match_info, + self, &state, &lac, &cid, &act, &cgreg, &cereg, + &c5greg, &error); g_match_info_free (match_info); @@ -4978,12 +5040,7 @@ registration_status_check_ready (MMBroadbandModem *self, MM_CORE_ERROR_FAILED, "Error parsing registration response: '%s'", response); - if (ctx->running_cs) - ctx->cs_error = error; - else if (ctx->running_ps) - ctx->ps_error = error; - else - ctx->eps_error = error; + run_registration_checks_context_set_error (ctx, error); run_registration_checks_context_step (task); return; } @@ -4995,27 +5052,43 @@ registration_status_check_ready (MMBroadbandModem *self, */ if (cgreg) { if (ctx->running_cs) - mm_dbg ("Got PS registration state when checking CS registration state"); + mm_obj_dbg (self, "got PS registration state when checking CS registration state"); else if (ctx->running_eps) - mm_dbg ("Got PS registration state when checking EPS registration state"); + mm_obj_dbg (self, "got PS registration state when checking EPS registration state"); + else if (ctx->running_5gs) + mm_obj_dbg (self, "got PS registration state when checking 5GS registration state"); mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), state); } else if (cereg) { tac = lac; lac = 0; if (ctx->running_cs) - mm_dbg ("Got EPS registration state when checking CS registration state"); + mm_obj_dbg (self, "got EPS registration state when checking CS registration state"); else if (ctx->running_ps) - mm_dbg ("Got EPS registration state when checking PS registration state"); + mm_obj_dbg (self, "got EPS registration state when checking PS registration state"); + else if (ctx->running_5gs) + mm_obj_dbg (self, "got EPS registration state when checking 5GS registration state"); mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), state); + } else if (c5greg) { + tac = lac; + lac = 0; + if (ctx->running_cs) + mm_obj_dbg (self, "got 5GS registration state when checking CS registration state"); + else if (ctx->running_ps) + mm_obj_dbg (self, "got 5GS registration state when checking PS registration state"); + else if (ctx->running_eps) + mm_obj_dbg (self, "got 5GS registration state when checking EPS registration state"); + mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), state); } else { if (act == MM_MODEM_ACCESS_TECHNOLOGY_LTE) { tac = lac; lac = 0; } if (ctx->running_ps) - mm_dbg ("Got CS registration state when checking PS registration state"); + mm_obj_dbg (self, "got CS registration state when checking PS registration state"); else if (ctx->running_eps) - mm_dbg ("Got CS registration state when checking EPS registration state"); + mm_obj_dbg (self, "got CS registration state when checking EPS registration state"); + else if (ctx->running_5gs) + mm_obj_dbg (self, "got CS registration state when checking 5GS registration state"); mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), state); } @@ -5038,6 +5111,7 @@ run_registration_checks_context_step (GTask *task) ctx->running_cs = FALSE; ctx->running_ps = FALSE; ctx->running_eps = FALSE; + ctx->running_5gs = FALSE; if (ctx->run_cs) { ctx->running_cs = TRUE; @@ -5078,22 +5152,35 @@ run_registration_checks_context_step (GTask *task) return; } + if (ctx->run_5gs) { + ctx->running_5gs = TRUE; + ctx->run_5gs = FALSE; + /* Check current 5GS-registration state. */ + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+C5GREG?", + 10, + FALSE, + (GAsyncReadyCallback)registration_status_check_ready, + task); + return; + } + /* If all run checks returned errors we fail */ - if ((ctx->cs_supported || ctx->ps_supported || ctx->eps_supported) && - (!ctx->cs_supported || ctx->cs_error) && - (!ctx->ps_supported || ctx->ps_error) && - (!ctx->eps_supported || ctx->eps_error)) { - /* Prefer the EPS, and then PS error if any */ - if (ctx->eps_error) { - g_propagate_error (&error, ctx->eps_error); - ctx->eps_error = NULL; - } else if (ctx->ps_error) { - g_propagate_error (&error, ctx->ps_error); - ctx->ps_error = NULL; - } else if (ctx->cs_error) { - g_propagate_error (&error, ctx->cs_error); - ctx->cs_error = NULL; - } else + if ((ctx->is_cs_supported || ctx->is_ps_supported || ctx->is_eps_supported || ctx->is_5gs_supported) && + (!ctx->is_cs_supported || ctx->error_cs) && + (!ctx->is_ps_supported || ctx->error_ps) && + (!ctx->is_eps_supported || ctx->error_eps) && + (!ctx->is_5gs_supported || ctx->error_5gs)) { + /* When reporting errors, prefer the 5GS, then EPS, then PS, then CS */ + if (ctx->error_5gs) + error = g_steal_pointer (&ctx->error_5gs); + else if (ctx->error_eps) + error = g_steal_pointer (&ctx->error_eps); + else if (ctx->error_ps) + error = g_steal_pointer (&ctx->error_ps); + else if (ctx->error_cs) + error = g_steal_pointer (&ctx->error_cs); + else g_assert_not_reached (); } @@ -5105,23 +5192,26 @@ run_registration_checks_context_step (GTask *task) } static void -modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, - GAsyncReadyCallback callback, - gpointer user_data) +modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, + gboolean is_cs_supported, + gboolean is_ps_supported, + gboolean is_eps_supported, + gboolean is_5gs_supported, + GAsyncReadyCallback callback, + gpointer user_data) { RunRegistrationChecksContext *ctx; GTask *task; ctx = g_new0 (RunRegistrationChecksContext, 1); - ctx->cs_supported = cs_supported; - ctx->ps_supported = ps_supported; - ctx->eps_supported = eps_supported; - ctx->run_cs = cs_supported; - ctx->run_ps = ps_supported; - ctx->run_eps = eps_supported; + ctx->is_cs_supported = is_cs_supported; + ctx->is_ps_supported = is_ps_supported; + ctx->is_eps_supported = is_eps_supported; + ctx->is_5gs_supported = is_5gs_supported; + ctx->run_cs = is_cs_supported; + ctx->run_ps = is_ps_supported; + ctx->run_eps = is_eps_supported; + ctx->run_5gs = is_5gs_supported; task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)run_registration_checks_context_free); @@ -5214,23 +5304,27 @@ modem_3gpp_enable_disable_unsolicited_registration_events_finish (MMIfaceModem3g return g_task_propagate_boolean (G_TASK (res), error); } -static gboolean -parse_registration_setup_reply (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, +static MMBaseModemAtResponseProcessorResult +parse_registration_setup_reply (MMBaseModem *self, + gpointer none, + const gchar *command, + const gchar *response, + gboolean last_command, const GError *error, - GVariant **result, - GError **result_error) + GVariant **result, + GError **result_error) { + *result_error = NULL; + /* If error, try next command */ - if (error) - return FALSE; + if (error) { + *result = NULL; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; + } /* Set COMMAND as result! */ *result = g_variant_new_string (command); - return TRUE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } static const MMBaseModemAtCommand cs_registration_sequence[] = { @@ -5301,9 +5395,9 @@ unsolicited_registration_events_sequence_ready (MMBroadbandModem *self, mm_base_modem_at_command_full_finish (MM_BASE_MODEM (self), res, &error); if (error) { - mm_dbg ("%s unsolicited registration events in secondary port failed: '%s'", - ctx->enable ? "Enabling" : "Disabling", - error->message); + mm_obj_dbg (self, "%s unsolicited registration events in secondary port failed: %s", + ctx->enable ? "enabling" : "disabling", + error->message); /* Keep errors reported */ if (ctx->running_cs && !ctx->cs_error) ctx->cs_error = error; @@ -5341,9 +5435,9 @@ unsolicited_registration_events_sequence_ready (MMBroadbandModem *self, error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "AT sequence failed"); - mm_dbg ("%s unsolicited registration events in primary port failed: '%s'", - ctx->enable ? "Enabling" : "Disabling", - error->message); + mm_obj_dbg (self, "%s unsolicited registration events in primary port failed: %s", + ctx->enable ? "enabling" : "disabling", + error->message); /* Keep errors reported */ if (ctx->running_cs) ctx->cs_error = error; @@ -5619,7 +5713,7 @@ ussd_send_command_ready (MMBaseModem *_self, response = mm_base_modem_at_command_finish (_self, res, &error); if (error) { /* Some immediate error happened when sending the USSD request */ - mm_dbg ("Error sending USSD request: '%s'", error->message); + mm_obj_dbg (self, "error sending USSD request: '%s'", error->message); g_error_free (error); if (self->priv->pending_ussd_action) { @@ -5629,17 +5723,17 @@ ussd_send_command_ready (MMBaseModem *_self, } if (!self->priv->pending_ussd_action) { - mm_dbg ("USSD operation finished already via URCs"); + mm_obj_dbg (self, "USSD operation finished already via URCs"); return; } /* Cache the hint for the next time we send something */ ctx = g_task_get_task_data (self->priv->pending_ussd_action); if (!self->priv->use_unencoded_ussd && ctx->current_is_unencoded) { - mm_dbg ("Will assume we want unencoded USSD commands"); + mm_obj_dbg (self, "will assume we want unencoded USSD commands"); self->priv->use_unencoded_ussd = TRUE; } else if (self->priv->use_unencoded_ussd && !ctx->current_is_unencoded) { - mm_dbg ("Will assume we want encoded USSD commands"); + mm_obj_dbg (self, "will assume we want encoded USSD commands"); self->priv->use_unencoded_ussd = FALSE; } @@ -5793,48 +5887,53 @@ modem_3gpp_ussd_send (MMIfaceModem3gppUssd *_self, /* USSD Encode/Decode (3GPP/USSD interface) */ static gchar * -modem_3gpp_ussd_encode (MMIfaceModem3gppUssd *self, - const gchar *command, - guint *scheme, - GError **error) +modem_3gpp_ussd_encode (MMIfaceModem3gppUssd *_self, + const gchar *command, + guint *scheme, + GError **error) { - MMBroadbandModem *broadband = MM_BROADBAND_MODEM (self); - GByteArray *ussd_command; - gchar *hex = NULL; - - ussd_command = g_byte_array_new (); + MMBroadbandModem *self = MM_BROADBAND_MODEM (_self); + g_autoptr(GByteArray) ussd_command = NULL; /* Encode to the current charset (as per AT+CSCS, which is what most modems * (except for Huawei it seems) will ask for. */ - if (mm_modem_charset_byte_array_append (ussd_command, - command, - FALSE, - broadband->priv->modem_current_charset)) { - /* The scheme value does NOT represent the encoding used to encode the string - * we're giving. This scheme reflects the encoding that the modem should use when - * sending the data out to the network. We're hardcoding this to GSM-7 because - * USSD commands fit well in GSM-7, unlike USSD responses that may contain code - * points that may only be encoded in UCS-2. */ - *scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT; - /* convert to hex representation */ - hex = mm_utils_bin2hexstr (ussd_command->data, ussd_command->len); + ussd_command = mm_modem_charset_bytearray_from_utf8 (command, self->priv->modem_current_charset, FALSE, error); + if (!ussd_command) { + g_prefix_error (error, "Failed to encode USSD command: "); + return NULL; } - g_byte_array_free (ussd_command, TRUE); + /* The scheme value does NOT represent the encoding used to encode the string + * we're giving. This scheme reflects the encoding that the modem should use when + * sending the data out to the network. We're hardcoding this to GSM-7 because + * USSD commands fit well in GSM-7, unlike USSD responses that may contain code + * points that may only be encoded in UCS-2. */ + *scheme = MM_MODEM_GSM_USSD_SCHEME_7BIT; - return hex; + /* convert to hex representation */ + return (gchar *) mm_utils_bin2hexstr (ussd_command->data, ussd_command->len); } static gchar * -modem_3gpp_ussd_decode (MMIfaceModem3gppUssd *self, - const gchar *reply, - GError **error) -{ - MMBroadbandModem *broadband = MM_BROADBAND_MODEM (self); +modem_3gpp_ussd_decode (MMIfaceModem3gppUssd *self, + const gchar *reply, + GError **error) +{ + MMBroadbandModem *broadband = MM_BROADBAND_MODEM (self); + guint8 *bin = NULL; + gsize bin_len = 0; + g_autoptr(GByteArray) barray = NULL; + + bin = (guint8 *) mm_utils_hexstr2bin (reply, -1, &bin_len, error); + if (!bin) { + g_prefix_error (error, "Couldn't convert HEX string to binary: "); + return NULL; + } + barray = g_byte_array_new_take (bin, bin_len); /* Decode from current charset (as per AT+CSCS, which is what most modems * (except for Huawei it seems) will ask for. */ - return mm_modem_charset_hex_to_utf8 (reply, broadband->priv->modem_current_charset); + return mm_modem_charset_bytearray_to_utf8 (barray, broadband->priv->modem_current_charset, FALSE, error); } /*****************************************************************************/ @@ -5984,7 +6083,7 @@ cusd_process_string (MMBroadbandModem *self, /* If no pending task, just report the error */ if (error) { - mm_warn ("Invalid USSD message: %s", error->message); + mm_obj_warn (self, "invalid USSD message: %s", error->message); g_error_free (error); } @@ -5998,7 +6097,7 @@ cusd_received (MMPortSerialAt *port, { gchar *str; - mm_dbg ("Unsolicited USSD URC received"); + mm_obj_dbg (self, "unsolicited USSD URC received"); str = g_match_info_fetch (info, 1); cusd_process_string (self, str); g_free (str); @@ -6024,9 +6123,9 @@ set_unsolicited_result_code_handlers (MMIfaceModem3gppUssd *self, if (!ports[i]) continue; /* Set/unset unsolicited CUSD event handler */ - mm_dbg ("(%s) %s unsolicited result code handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s unsolicited result code handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], cusd_regex, @@ -6291,13 +6390,10 @@ cpms_format_check_ready (MMBroadbandModem *self, if (!mm_3gpp_parse_cpms_test_response (response, &result->mem1, &result->mem2, - &result->mem3)) { + &result->mem3, + &error)) { supported_storages_result_free (result); - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't parse supported storages reply: '%s'", - response); + g_task_return_error (task, error); g_object_unref (task); return; } @@ -6366,14 +6462,14 @@ cpms_query_ready (MMBroadbandModem *self, self->priv->current_sms_mem1_storage = mem1; self->priv->current_sms_mem2_storage = mem2; - mm_dbg ("Current storages initialized:"); + mm_obj_dbg (self, "current storages initialized:"); aux = mm_common_build_sms_storages_string (&mem1, 1); - mm_dbg (" mem1 (list/read/delete) storages: '%s'", aux); + mm_obj_dbg (self, " mem1 (list/read/delete) storages: '%s'", aux); g_free (aux); aux = mm_common_build_sms_storages_string (&mem2, 1); - mm_dbg (" mem2 (write/send) storages: '%s'", aux); + mm_obj_dbg (self, " mem2 (write/send) storages: '%s'", aux); g_free (aux); g_task_return_boolean (task, TRUE); @@ -6532,8 +6628,8 @@ mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self, self->priv->current_sms_mem1_storage = mem1; self->priv->mem1_storage_locked = TRUE; } else if (self->priv->current_sms_mem1_storage != MM_SMS_STORAGE_UNKNOWN) { - mm_dbg ("Given sms mem1 storage is unknown. Using current sms mem1 storage value '%s' instead", - mm_sms_storage_get_string (self->priv->current_sms_mem1_storage)); + mm_obj_dbg (self, "given sms mem1 storage is unknown. Using current sms mem1 storage value '%s' instead", + mm_sms_storage_get_string (self->priv->current_sms_mem1_storage)); } else { g_task_return_new_error (task, MM_CORE_ERROR, @@ -6557,9 +6653,8 @@ mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self, g_assert (mem1_str != NULL); /* We don't touch 'mem3' here */ - mm_dbg ("Locking SMS storages to: mem1 (%s), mem2 (%s)...", - mem1_str, - mem2_str ? mem2_str : "none"); + mm_obj_dbg (self, "locking SMS storages to: mem1 (%s), mem2 (%s)...", + mem1_str, mem2_str ? mem2_str : "none"); if (mem2_str) cmd = g_strdup_printf ("+CPMS=\"%s\",\"%s\"", mem1_str, mem2_str); @@ -6668,13 +6763,12 @@ cmgf_set_ready (MMBroadbandModem *self, mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); if (error) { - mm_dbg ("Failed to set preferred SMS mode: '%s'; assuming text mode'", - error->message); + mm_obj_dbg (self, "failed to set preferred SMS mode: %s; assuming text mode'", error->message); g_error_free (error); self->priv->modem_messaging_sms_pdu_mode = FALSE; } else - mm_dbg ("Successfully set preferred SMS mode: '%s'", - self->priv->modem_messaging_sms_pdu_mode ? "PDU" : "text"); + mm_obj_dbg (self, "successfully set preferred SMS mode: '%s'", + self->priv->modem_messaging_sms_pdu_mode ? "PDU" : "text"); g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -6713,8 +6807,7 @@ cmgf_format_check_ready (MMBroadbandModem *self, &sms_pdu_supported, &sms_text_supported, &error)) { - mm_dbg ("Failed to query supported SMS modes: '%s'", - error->message); + mm_obj_dbg (self, "failed to query supported SMS modes: %s", error->message); g_error_free (error); } @@ -6722,11 +6815,11 @@ cmgf_format_check_ready (MMBroadbandModem *self, self->priv->modem_messaging_sms_pdu_mode = TRUE; if (!sms_pdu_supported) { if (sms_text_supported) { - mm_dbg ("PDU mode not supported, will try to use Text mode"); + mm_obj_dbg (self, "PDU mode not supported, will try to use Text mode"); self->priv->modem_messaging_sms_pdu_mode = FALSE; } else - mm_dbg ("Neither PDU nor Text modes are reported as supported; " - "will anyway default to PDU mode"); + mm_obj_dbg (self, "neither PDU nor Text modes are reported as supported; " + "will anyway default to PDU mode"); } self->priv->sms_supported_modes_checked = TRUE; @@ -6792,8 +6885,7 @@ sms_part_ready (MMBroadbandModem *self, if (error) { /* We're really ignoring this error afterwards, as we don't have a callback * passed to the async operation, so just log the error here. */ - mm_warn ("Couldn't retrieve SMS part: '%s'", - error->message); + mm_obj_warn (self, "couldn't retrieve SMS part: '%s'", error->message); g_task_return_error (task, error); g_object_unref (task); return; @@ -6803,23 +6895,22 @@ sms_part_ready (MMBroadbandModem *self, info = mm_3gpp_parse_cmgr_read_response (response, ctx->idx, &error); if (!info) { - mm_warn ("Couldn't parse SMS part: '%s'", - error->message); + mm_obj_warn (self, "couldn't parse SMS part: '%s'", error->message); g_task_return_error (task, error); g_object_unref (task); return; } - part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, self, &error); if (part) { - mm_dbg ("Correctly parsed PDU (%d)", ctx->idx); + mm_obj_dbg (self, "correctly parsed PDU (%d)", ctx->idx); mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), part, MM_SMS_STATE_RECEIVED, self->priv->modem_messaging_sms_default_storage); } else { /* Don't treat the error as critical */ - mm_dbg ("Error parsing PDU (%d): %s", ctx->idx, error->message); + mm_obj_dbg (self, "error parsing PDU (%d): %s", ctx->idx, error->message); g_error_free (error); } @@ -6878,7 +6969,7 @@ cmti_received (MMPortSerialAt *port, str = mm_get_string_unquoted_from_match_info (info, 1); storage = mm_common_get_sms_storage_from_string (str, NULL); if (storage == MM_SMS_STORAGE_UNKNOWN) { - mm_dbg ("Skipping CMTI indication, unknown storage '%s' reported", str); + mm_obj_dbg (self, "skipping CMTI indication, unknown storage '%s' reported", str); g_free (str); return; } @@ -6888,7 +6979,7 @@ cmti_received (MMPortSerialAt *port, if (mm_sms_list_has_part (self->priv->modem_messaging_sms_list, storage, idx)) { - mm_dbg ("Skipping CMTI indication, part already processed"); + mm_obj_dbg (self, "skipping CMTI indication, part already processed"); return; } @@ -6916,7 +7007,7 @@ cds_received (MMPortSerialAt *port, guint length; gchar *pdu; - mm_dbg ("Got new non-stored message indication"); + mm_obj_dbg (self, "got new non-stored message indication"); if (!mm_get_uint_from_match_info (info, 1, &length)) return; @@ -6925,16 +7016,16 @@ cds_received (MMPortSerialAt *port, if (!pdu) return; - part = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, pdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, pdu, self, &error); if (part) { - mm_dbg ("Correctly parsed non-stored PDU"); + mm_obj_dbg (self, "correctly parsed non-stored PDU"); mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), part, MM_SMS_STATE_RECEIVED, MM_SMS_STORAGE_UNKNOWN); } else { /* Don't treat the error as critical */ - mm_dbg ("Error parsing non-stored PDU: %s", error->message); + mm_obj_dbg (self, "error parsing non-stored PDU: %s", error->message); g_error_free (error); } } @@ -6962,9 +7053,9 @@ set_messaging_unsolicited_events_handlers (MMIfaceModemMessaging *self, continue; /* Set/unset unsolicited CMTI event handler */ - mm_dbg ("(%s) %s messaging unsolicited events handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s messaging unsolicited events handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], cmti_regex, @@ -7014,28 +7105,31 @@ modem_messaging_enable_unsolicited_events_finish (MMIfaceModemMessaging *self, return g_task_propagate_boolean (G_TASK (res), error); } -static gboolean -cnmi_response_processor (MMBaseModem *self, - gpointer none, - const gchar *command, - const gchar *response, - gboolean last_command, - const GError *error, - GVariant **result, - GError **result_error) +static MMBaseModemAtResponseProcessorResult +cnmi_response_processor (MMBaseModem *self, + gpointer none, + const gchar *command, + const gchar *response, + gboolean last_command, + const GError *error, + GVariant **result, + GError **result_error) { + *result = NULL; + *result_error = NULL; + if (error) { /* If we get a not-supported error and we're not in the last command, we * won't set 'result_error', so we'll keep on the sequence */ - if (!g_error_matches (error, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_NOT_SUPPORTED) || - last_command) + if (!g_error_matches (error, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_NOT_SUPPORTED) || last_command) { *result_error = g_error_copy (error); + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE; + } - return FALSE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE; } - *result = NULL; - return TRUE; + return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS; } static const MMBaseModemAtCommand cnmi_sequence[] = { @@ -7065,14 +7159,14 @@ modem_messaging_enable_unsolicited_events_secondary_ready (MMBaseModem *self, /* Since the secondary is not required, we don't propagate the error anywhere */ mm_base_modem_at_sequence_full_finish (MM_BASE_MODEM (self), res, NULL, &inner_error); if (inner_error) { - mm_dbg ("(%s) Unable to enable messaging unsolicited events on modem secondary: %s", - mm_port_get_device (MM_PORT (secondary)), - inner_error->message); + mm_obj_dbg (self, "failed to enable messaging unsolicited events on secondary port %s: %s", + mm_port_get_device (MM_PORT (secondary)), + inner_error->message); g_error_free (inner_error); } - mm_dbg ("(%s) Messaging unsolicited events enabled on secondary", - mm_port_get_device (MM_PORT (secondary))); + mm_obj_dbg (self, "messaging unsolicited events enabled on secondary port %s", + mm_port_get_device (MM_PORT (secondary))); g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -7097,13 +7191,13 @@ modem_messaging_enable_unsolicited_events_primary_ready (MMBaseModem *self, return; } - mm_dbg ("(%s) Messaging unsolicited events enabled on primary", - mm_port_get_device (MM_PORT (primary))); + mm_obj_dbg (self, "messaging unsolicited events enabled on primary port %s", + mm_port_get_device (MM_PORT (primary))); /* Try to enable unsolicited events for secondary port */ if (secondary) { - mm_dbg ("(%s) Enabling messaging unsolicited events on secondary port", - mm_port_get_device (MM_PORT (secondary))); + mm_obj_dbg (self, "enabling messaging unsolicited events on secondary port %s", + mm_port_get_device (MM_PORT (secondary))); mm_base_modem_at_sequence_full ( MM_BASE_MODEM (self), secondary, @@ -7132,8 +7226,8 @@ modem_messaging_enable_unsolicited_events (MMIfaceModemMessaging *self, primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); /* Enable unsolicited events for primary port */ - mm_dbg ("(%s) Enabling messaging unsolicited events on primary port", - mm_port_get_device (MM_PORT (primary))); + mm_obj_dbg (self, "enabling messaging unsolicited events on primary port %s", + mm_port_get_device (MM_PORT (primary))); mm_base_modem_at_sequence_full ( MM_BASE_MODEM (self), primary, @@ -7227,72 +7321,82 @@ sms_text_part_list_ready (MMBroadbandModem *self, ctx = g_task_get_task_data (task); while (g_match_info_matches (match_info)) { - MMSmsPart *part; - guint matches, idx; - gchar *number, *timestamp, *text, *ucs2_text, *stat; - gsize ucs2_len = 0; - GByteArray *raw; + MMSmsPart *part; + guint matches; + guint idx; + g_autofree gchar *number_enc = NULL; + g_autofree gchar *number = NULL; + g_autofree gchar *timestamp = NULL; + g_autofree gchar *text_enc = NULL; + g_autofree gchar *text = NULL; + g_autofree gchar *stat = NULL; + g_autoptr(GByteArray) raw = NULL; + g_autoptr(GError) inner_error = NULL; matches = g_match_info_get_match_count (match_info); if (matches != 7) { - mm_dbg ("Failed to match entire CMGL response (count %d)", matches); + mm_obj_dbg (self, "failed to match entire CMGL response (count %d)", matches); goto next; } if (!mm_get_uint_from_match_info (match_info, 1, &idx)) { - mm_dbg ("Failed to convert message index"); + mm_obj_dbg (self, "failed to convert message index"); goto next; } /* Get part state */ stat = mm_get_string_unquoted_from_match_info (match_info, 2); if (!stat) { - mm_dbg ("Failed to get part status"); + mm_obj_dbg (self, "failed to get part status"); goto next; } /* Get and parse number */ - number = mm_get_string_unquoted_from_match_info (match_info, 3); + number_enc = mm_get_string_unquoted_from_match_info (match_info, 3); + if (!number_enc) { + mm_obj_dbg (self, "failed to get message sender number"); + goto next; + } + number = mm_modem_charset_str_to_utf8 (number_enc, -1, self->priv->modem_current_charset, FALSE, &inner_error); if (!number) { - mm_dbg ("Failed to get message sender number"); - g_free (stat); + mm_obj_dbg (self, "failed to convert message sender number to UTF-8: %s", inner_error->message); goto next; } - number = mm_broadband_modem_take_and_convert_to_utf8 (MM_BROADBAND_MODEM (self), - number); - /* Get and parse timestamp (always expected in ASCII) */ timestamp = mm_get_string_unquoted_from_match_info (match_info, 5); + if (timestamp && !g_str_is_ascii (timestamp)) { + mm_obj_dbg (self, "failed to parse input timestamp as ASCII"); + goto next; + } /* Get and parse text */ - text = mm_broadband_modem_take_and_convert_to_utf8 (MM_BROADBAND_MODEM (self), - g_match_info_fetch (match_info, 6)); + text_enc = g_match_info_fetch (match_info, 6); + text = mm_modem_charset_str_to_utf8 (text_enc, -1, self->priv->modem_current_charset, FALSE, &inner_error); + if (!text) { + mm_obj_dbg (self, "failed to convert message text to UTF-8: %s", inner_error->message); + goto next; + } /* The raw SMS data can only be GSM, UCS2, or unknown (8-bit), so we * need to convert to UCS2 here. */ - ucs2_text = g_convert (text, -1, "UCS-2BE//TRANSLIT", "UTF-8", NULL, &ucs2_len, NULL); - g_assert (ucs2_text); - raw = g_byte_array_sized_new (ucs2_len); - g_byte_array_append (raw, (const guint8 *) ucs2_text, ucs2_len); - g_free (ucs2_text); + raw = mm_modem_charset_bytearray_from_utf8 (text, MM_MODEM_CHARSET_UCS2, FALSE, NULL); + g_assert (raw); /* all take() methods pass ownership of the value as well */ - part = mm_sms_part_new (idx, - sms_pdu_type_from_str (stat)); - mm_sms_part_take_number (part, number); - mm_sms_part_take_timestamp (part, timestamp); - mm_sms_part_take_text (part, text); - mm_sms_part_take_data (part, raw); + part = mm_sms_part_new (idx, sms_pdu_type_from_str (stat)); + mm_sms_part_take_number (part, g_steal_pointer (&number)); + mm_sms_part_take_timestamp (part, g_steal_pointer (×tamp)); + mm_sms_part_take_text (part, g_steal_pointer (&text)); + mm_sms_part_take_data (part, g_steal_pointer (&raw)); mm_sms_part_set_class (part, -1); - mm_dbg ("Correctly parsed SMS list entry (%d)", idx); + mm_obj_dbg (self, "correctly parsed SMS list entry (%d)", idx); mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), part, sms_state_from_str (stat), ctx->list_storage); - g_free (stat); next: g_match_info_next (match_info, NULL); } @@ -7355,16 +7459,16 @@ sms_pdu_part_list_ready (MMBroadbandModem *self, MM3gppPduInfo *info = l->data; MMSmsPart *part; - part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, self, &error); if (part) { - mm_dbg ("Correctly parsed PDU (%d)", info->index); + mm_obj_dbg (self, "correctly parsed PDU (%d)", info->index); mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self), part, sms_state_from_index (info->status), ctx->list_storage); } else { /* Don't treat the error as critical */ - mm_dbg ("Error parsing PDU (%d): %s", info->index, error->message); + mm_obj_dbg (self, "error parsing PDU (%d): %s", info->index, error->message); g_clear_error (&error); } } @@ -7422,8 +7526,7 @@ modem_messaging_load_initial_sms_parts (MMIfaceModemMessaging *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, g_free); - mm_dbg ("Listing SMS parts in storage '%s'", - mm_sms_storage_get_string (storage)); + mm_obj_dbg (self, "listing SMS parts in storage '%s'", mm_sms_storage_get_string (storage)); /* First, request to set the proper storage to read from */ mm_broadband_modem_lock_sms_storages (MM_BROADBAND_MODEM (self), @@ -7561,7 +7664,7 @@ modem_voice_load_call_list_finish (MMIfaceModemVoice *self, } static void -clcc_ready (MMBaseModem *modem, +clcc_ready (MMBaseModem *self, GAsyncResult *res, GTask *task) { @@ -7569,8 +7672,8 @@ clcc_ready (MMBaseModem *modem, GError *error = NULL; GList *call_info_list = NULL; - response = mm_base_modem_at_command_finish (modem, res, &error); - if (!response || !mm_3gpp_parse_clcc_response (response, &call_info_list, &error)) + response = mm_base_modem_at_command_finish (self, res, &error); + if (!response || !mm_3gpp_parse_clcc_response (response, self, &call_info_list, &error)) g_task_return_error (task, error); else g_task_return_pointer (task, call_info_list, (GDestroyNotify)mm_3gpp_call_info_list_free); @@ -7618,7 +7721,7 @@ in_call_event_received (MMPortSerialAt *port, call_info.number = NULL; str = g_match_info_fetch (info, 1); - mm_dbg ("Call terminated: %s", str); + mm_obj_dbg (self, "call terminated: %s", str); g_free (str); mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info); @@ -7644,9 +7747,9 @@ set_voice_in_call_unsolicited_events_handlers (MMBroadbandModem *self, if (!ports[i]) continue; - mm_dbg ("(%s) %s voice in-call unsolicited events handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s voice in-call unsolicited events handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], in_call_event_regex, @@ -7671,7 +7774,7 @@ modem_voice_setup_in_call_unsolicited_events (MMIfaceModemVoice *_self, if (!self->priv->in_call_ports_ctx) { PortsContext *ctx; - mm_dbg ("Setting up in-call ports context"); + mm_obj_dbg (self, "setting up in-call ports context"); ctx = ports_context_new (); if (!ports_context_open (self, ctx, FALSE, TRUE, FALSE, &error)) { ports_context_unref (ctx); @@ -7681,7 +7784,7 @@ modem_voice_setup_in_call_unsolicited_events (MMIfaceModemVoice *_self, self->priv->in_call_ports_ctx = ctx; } } else - mm_dbg ("In-call ports context already set up"); + mm_obj_dbg (self, "in-call ports context already set up"); task = g_task_new (self, NULL, callback, user_data); if (error) @@ -7701,11 +7804,11 @@ modem_voice_cleanup_in_call_unsolicited_events (MMIfaceModemVoice *_self, self = MM_BROADBAND_MODEM (_self); if (self->priv->in_call_ports_ctx) { - mm_dbg ("Cleaning up in-call ports context"); + mm_obj_dbg (self, "cleaning up in-call ports context"); set_voice_in_call_unsolicited_events_handlers (self, self->priv->in_call_ports_ctx, FALSE); g_clear_pointer (&self->priv->in_call_ports_ctx, (GDestroyNotify) ports_context_unref); } else - mm_dbg ("In-call ports context already cleaned up"); + mm_obj_dbg (self, "in-call ports context already cleaned up"); task = g_task_new (self, NULL, callback, user_data); g_task_return_boolean (task, TRUE); @@ -7735,7 +7838,7 @@ ccwa_received (MMPortSerialAt *port, call_info.state = MM_CALL_STATE_WAITING; call_info.number = mm_get_string_unquoted_from_match_info (info, 1); - mm_dbg ("Call waiting (%s)", call_info.number); + mm_obj_dbg (self, "call waiting (%s)", call_info.number); mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info); g_free (call_info.number); @@ -7753,7 +7856,7 @@ ring_received (MMPortSerialAt *port, call_info.state = MM_CALL_STATE_RINGING_IN; call_info.number = NULL; - mm_dbg ("Ringing"); + mm_obj_dbg (self, "ringing"); mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info); } @@ -7767,7 +7870,7 @@ cring_received (MMPortSerialAt *port, /* We could have "VOICE" or "DATA". Now consider only "VOICE" */ str = mm_get_string_unquoted_from_match_info (info, 1); - mm_dbg ("Ringing (%s)", str); + mm_obj_dbg (self, "ringing (%s)", str); g_free (str); call_info.index = 0; @@ -7790,7 +7893,7 @@ clip_received (MMPortSerialAt *port, call_info.state = MM_CALL_STATE_RINGING_IN; call_info.number = mm_get_string_unquoted_from_match_info (info, 1); - mm_dbg ("Ringing (%s)", call_info.number); + mm_obj_dbg (self, "ringing (%s)", call_info.number); mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info); g_free (call_info.number); @@ -7823,9 +7926,9 @@ set_voice_unsolicited_events_handlers (MMIfaceModemVoice *self, continue; /* Set/unset unsolicited CMTI event handler */ - mm_dbg ("(%s) %s voice unsolicited events handlers", - mm_port_get_device (MM_PORT (ports[i])), - enable ? "Setting" : "Removing"); + mm_obj_dbg (self, "%s voice unsolicited events handlers in %s", + enable ? "setting" : "removing", + mm_port_get_device (MM_PORT (ports[i]))); mm_port_serial_at_add_unsolicited_msg_handler ( ports[i], cring_regex, @@ -7928,9 +8031,9 @@ voice_unsolicited_events_setup_ready (MMBroadbandModem *self, ctx = g_task_get_task_data (task); if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error)) { - mm_dbg ("Couldn't %s voice event reporting: '%s'", - ctx->enable ? "enable" : "disable", - error->message); + mm_obj_dbg (self, "couldn't %s voice event reporting: '%s'", + ctx->enable ? "enable" : "disable", + error->message); g_error_free (error); } @@ -7951,42 +8054,42 @@ run_voice_unsolicited_events_setup (GTask *task) /* CLIP on primary port */ if (!ctx->clip_primary_done && ctx->clip_command && ctx->primary) { - mm_dbg ("%s +CLIP calling line reporting in primary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CLIP calling line reporting in primary port...", ctx->enable ? "enabling" : "disabling"); ctx->clip_primary_done = TRUE; command = ctx->clip_command; port = ctx->primary; } /* CLIP on secondary port */ else if (!ctx->clip_secondary_done && ctx->clip_command && ctx->secondary) { - mm_dbg ("%s +CLIP calling line reporting in secondary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CLIP calling line reporting in secondary port...", ctx->enable ? "enabling" : "disabling"); ctx->clip_secondary_done = TRUE; command = ctx->clip_command; port = ctx->secondary; } /* CRC on primary port */ else if (!ctx->crc_primary_done && ctx->crc_command && ctx->primary) { - mm_dbg ("%s +CRC extended format of incoming call indications in primary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CRC extended format of incoming call indications in primary port...", ctx->enable ? "enabling" : "disabling"); ctx->crc_primary_done = TRUE; command = ctx->crc_command; port = ctx->primary; } /* CRC on secondary port */ else if (!ctx->crc_secondary_done && ctx->crc_command && ctx->secondary) { - mm_dbg ("%s +CRC extended format of incoming call indications in secondary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CRC extended format of incoming call indications in secondary port...", ctx->enable ? "enabling" : "disabling"); ctx->crc_secondary_done = TRUE; command = ctx->crc_command; port = ctx->secondary; } /* CCWA on primary port */ else if (!ctx->ccwa_primary_done && ctx->ccwa_command && ctx->primary) { - mm_dbg ("%s +CCWA call waiting indications in primary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CCWA call waiting indications in primary port...", ctx->enable ? "enabling" : "disabling"); ctx->ccwa_primary_done = TRUE; command = ctx->ccwa_command; port = ctx->primary; } /* CCWA on secondary port */ else if (!ctx->ccwa_secondary_done && ctx->ccwa_command && ctx->secondary) { - mm_dbg ("%s +CCWA call waiting indications in secondary port...", ctx->enable ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s +CCWA call waiting indications in secondary port...", ctx->enable ? "enabling" : "disabling"); ctx->ccwa_secondary_done = TRUE; command = ctx->ccwa_command; port = ctx->secondary; @@ -8310,7 +8413,7 @@ modem_voice_call_waiting_query_finish (MMIfaceModemVoice *self, if (!response) return FALSE; - return mm_3gpp_parse_ccwa_service_query_response (response, status, error); + return mm_3gpp_parse_ccwa_service_query_response (response, self, status, error); } static void @@ -8346,7 +8449,7 @@ modem_cdma_load_esn_finish (MMIfaceModemCdma *self, result = mm_strip_tag (result, "+GSN:"); mm_parse_gsn (result, NULL, NULL, &esn); - mm_dbg ("loaded ESN: %s", esn); + mm_obj_dbg (self, "loaded ESN: %s", esn); return esn; } @@ -8355,7 +8458,7 @@ modem_cdma_load_esn (MMIfaceModemCdma *self, GAsyncReadyCallback callback, gpointer user_data) { - mm_dbg ("loading ESN..."); + mm_obj_dbg (self, "loading ESN..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+GSN", 3, @@ -8381,7 +8484,7 @@ modem_cdma_load_meid_finish (MMIfaceModemCdma *self, result = mm_strip_tag (result, "+GSN:"); mm_parse_gsn (result, NULL, &meid, NULL); - mm_dbg ("loaded MEID: %s", meid); + mm_obj_dbg (self, "loaded MEID: %s", meid); return meid; } @@ -8391,7 +8494,7 @@ modem_cdma_load_meid (MMIfaceModemCdma *self, gpointer user_data) { /* Some devices return both the MEID and the ESN in the +GSN response */ - mm_dbg ("loading MEID..."); + mm_obj_dbg (self, "loading MEID..."); mm_base_modem_at_command (MM_BASE_MODEM (self), "+GSN", 3, @@ -9011,6 +9114,7 @@ qcdm_cdma_status_ready (MMPortSerialQcdm *port, GAsyncResult *res, GTask *task) { + MMBroadbandModem *self; QcdmResult *result = NULL; guint32 sid = MM_MODEM_CDMA_SID_UNKNOWN; guint32 nid = MM_MODEM_CDMA_NID_UNKNOWN; @@ -9019,9 +9123,11 @@ qcdm_cdma_status_ready (MMPortSerialQcdm *port, GError *error = NULL; GByteArray *response; + self = g_task_get_source_object (task); + response = mm_port_serial_qcdm_command_finish (port, res, &error); if (error) { - mm_dbg ("Failed to get cdma status: %s", error->message); + mm_obj_dbg (self, "failed to get cdma status: %s", error->message); g_clear_error (&error); /* Fall back to AT+CSS */ @@ -9034,7 +9140,7 @@ qcdm_cdma_status_ready (MMPortSerialQcdm *port, &err); if (!result) { if (err != QCDM_SUCCESS) - mm_dbg ("Failed to parse cdma status command result: %d", err); + mm_obj_dbg (self, "failed to parse cdma status command result: %d", err); g_byte_array_unref (response); /* Fall back to AT+CSS */ @@ -9055,9 +9161,9 @@ qcdm_cdma_status_ready (MMPortSerialQcdm *port, nid = MM_MODEM_CDMA_NID_UNKNOWN; } - mm_dbg ("CDMA 1x Status RX state: %d", rxstate); - mm_dbg ("CDMA 1x Status SID: %d", sid); - mm_dbg ("CDMA 1x Status NID: %d", nid); + mm_obj_dbg (self, "CDMA 1x Status RX state: %d", rxstate); + mm_obj_dbg (self, "CDMA 1x Status SID: %d", sid); + mm_obj_dbg (self, "CDMA 1x Status NID: %d", nid); cdma1x_serving_system_complete_and_free (task, sid, @@ -9086,7 +9192,7 @@ modem_cdma_get_cdma1x_serving_system (MMIfaceModemCdma *self, } if (!mm_port_serial_open (MM_PORT_SERIAL (qcdm), &error)) { - mm_dbg ("Failed to open QCDM port for serving-system request: %s", error->message); + mm_obj_dbg (self, "failed to open QCDM port for serving-system request: %s", error->message); g_error_free (error); /* Fall back to AT+CSS */ @@ -9258,7 +9364,7 @@ speri_ready (MMIfaceModemCdma *self, response = mm_strip_tag (response, "$SPERI:"); if (!response || !mm_cdma_parse_eri (response, &roaming, NULL, NULL)) { - mm_warn ("Couldn't parse SPERI response '%s'", response); + mm_obj_warn (self, "couldn't parse SPERI response '%s'", response); g_task_return_pointer (task, detailed_registration_state_result_new (ctx), g_free); @@ -9416,7 +9522,7 @@ setup_registration_checks_results_new (MMBroadbandModem *self, /* Skip QCDM steps if no QCDM port */ if (!ctx->has_qcdm_port) { - mm_dbg ("Will skip all QCDM-based registration checks"); + mm_obj_dbg (self, "will skip all QCDM-based registration checks"); results->skip_qcdm_call_manager_step = TRUE; results->skip_qcdm_hdr_step = TRUE; } @@ -9430,14 +9536,12 @@ setup_registration_checks_results_new (MMBroadbandModem *self, * for the specific step, or subclass this setup and return * FALSE themselves. */ if (ctx->has_sprint_commands) { - mm_dbg ("Will skip CDMA1x Serving System check, " - "we do have Sprint commands"); + mm_obj_dbg (self, "will skip CDMA1x Serving System check, we do have Sprint commands"); results->skip_at_cdma1x_serving_system_step = TRUE; } else { /* If there aren't Sprint specific commands, and the detailed * registration state getter wasn't subclassed, skip the step */ - mm_dbg ("Will skip generic detailed registration check, we " - "don't have Sprint commands"); + mm_obj_dbg (self, "will skip generic detailed registration check, we don't have Sprint commands"); results->skip_detailed_registration_state = TRUE; } } @@ -9640,7 +9744,7 @@ run_cdma_registration_checks_ready (MMBroadbandModem *self, mm_iface_modem_cdma_run_registration_checks_finish (MM_IFACE_MODEM_CDMA (self), res, &error); if (error) { - mm_dbg ("CDMA registration check failed: '%s'", error->message); + mm_obj_dbg (self, "CDMA registration check failed: %s", error->message); mm_iface_modem_cdma_update_cdma1x_registration_state ( MM_IFACE_MODEM_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN, @@ -9661,10 +9765,9 @@ run_cdma_registration_checks_ready (MMBroadbandModem *self, /* If we got registered in at least one CDMA network, end registration checks */ if (REG_IS_DONE (self->priv->modem_cdma_cdma1x_registration_state) || REG_IS_DONE (self->priv->modem_cdma_evdo_registration_state)) { - mm_dbg ("Modem is currently registered in a CDMA network " - "(CDMA1x: '%s', EV-DO: '%s')", - REG_IS_DONE (self->priv->modem_cdma_cdma1x_registration_state) ? "yes" : "no", - REG_IS_DONE (self->priv->modem_cdma_evdo_registration_state) ? "yes" : "no"); + mm_obj_dbg (self, "registered in a CDMA network (CDMA1x: '%s', EV-DO: '%s')", + REG_IS_DONE (self->priv->modem_cdma_cdma1x_registration_state) ? "yes" : "no", + REG_IS_DONE (self->priv->modem_cdma_evdo_registration_state) ? "yes" : "no"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -9672,7 +9775,7 @@ run_cdma_registration_checks_ready (MMBroadbandModem *self, /* Don't spend too much time waiting to get registered */ if (g_timer_elapsed (ctx->timer, NULL) > ctx->max_registration_time) { - mm_dbg ("CDMA registration check timed out"); + mm_obj_dbg (self, "CDMA registration check timed out"); mm_iface_modem_cdma_update_cdma1x_registration_state ( MM_IFACE_MODEM_CDMA (self), MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN, @@ -9684,14 +9787,14 @@ run_cdma_registration_checks_ready (MMBroadbandModem *self, mm_iface_modem_cdma_update_access_technologies ( MM_IFACE_MODEM_CDMA (self), MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); - error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT); + error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, self); g_task_return_error (task, error); g_object_unref (task); return; } /* Check again in a few seconds. */ - mm_dbg ("Modem not yet registered in a CDMA network... will recheck soon"); + mm_obj_dbg (self, "not yet registered in a CDMA network... will recheck soon"); g_timeout_add_seconds (3, (GSourceFunc)run_cdma_registration_checks_again, task); @@ -9942,19 +10045,22 @@ modem_signal_load_values_finish (MMIfaceModemSignal *self, MMSignal **gsm, MMSignal **umts, MMSignal **lte, + MMSignal **nr5g, GError **error) { const gchar *response; response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response || !mm_3gpp_cesq_response_to_signal_info (response, gsm, umts, lte, error)) + if (!response || !mm_3gpp_cesq_response_to_signal_info (response, self, gsm, umts, lte, error)) return FALSE; - /* No 3GPP2 support */ if (cdma) *cdma = NULL; if (evdo) *evdo = NULL; + if (nr5g) + *nr5g = NULL; + return TRUE; } @@ -10237,7 +10343,7 @@ enabling_modem_init_ready (MMBroadbandModem *self, self->priv->modem_init_run = TRUE; /* After the modem init sequence, give a 500ms period for the modem to settle */ - mm_dbg ("Giving some time to settle the modem..."); + mm_obj_dbg (self, "giving some time to settle the modem..."); g_timeout_add (500, (GSourceFunc)enabling_after_modem_init_timeout, task); } @@ -10261,7 +10367,7 @@ enabling_flash_done (MMPortSerial *port, ctx = g_task_get_task_data (task); if (ctx->modem_init_required) { - mm_dbg ("Running modem initialization sequence..."); + mm_obj_dbg (self, "running initialization sequence..."); MM_BROADBAND_MODEM_GET_CLASS (self)->enabling_modem_init (self, (GAsyncReadyCallback)enabling_modem_init_ready, task); @@ -10290,13 +10396,13 @@ enabling_started (MMBroadbandModem *self, * did it (i.e. don't reinitialize if the modem got disabled and enabled * again) */ if (self->priv->modem_init_run) - mm_dbg ("Skipping modem initialization: not first enabling"); + mm_obj_dbg (self, "skipping initialization: not first enabling"); else if (mm_base_modem_get_hotplugged (MM_BASE_MODEM (self))) { self->priv->modem_init_run = TRUE; - mm_dbg ("Skipping modem initialization: device hotplugged"); + mm_obj_dbg (self, "skipping initialization: device hotplugged"); } else if (!MM_BROADBAND_MODEM_GET_CLASS (self)->enabling_modem_init || !MM_BROADBAND_MODEM_GET_CLASS (self)->enabling_modem_init_finish) - mm_dbg ("Skipping modem initialization: not required"); + mm_obj_dbg (self, "skipping initialization: not required"); else ctx->modem_init_required = TRUE; @@ -10312,7 +10418,7 @@ enabling_started (MMBroadbandModem *self, } /* Ports were correctly opened, now flash the primary port */ - mm_dbg ("Flashing primary AT port before enabling..."); + mm_obj_dbg (self, "flashing primary AT port before enabling..."); mm_port_serial_flash (MM_PORT_SERIAL (ctx->ports->primary), 100, FALSE, @@ -10330,11 +10436,11 @@ modem_3gpp_run_registration_checks_ready (MMIfaceModem3gpp *self, GError *error = NULL; if (!mm_iface_modem_3gpp_run_registration_checks_finish (self, res, &error)) { - mm_warn ("Initial 3GPP registration check failed: %s", error->message); + mm_obj_warn (self, "initial 3GPP registration check failed: %s", error->message); g_error_free (error); return; } - mm_dbg ("Initial 3GPP registration checks finished"); + mm_obj_dbg (self, "initial 3GPP registration checks finished"); } static void @@ -10344,11 +10450,11 @@ modem_cdma_run_registration_checks_ready (MMIfaceModemCdma *self, GError *error = NULL; if (!mm_iface_modem_cdma_run_registration_checks_finish (self, res, &error)) { - mm_warn ("Initial CDMA registration check failed: %s", error->message); + mm_obj_warn (self, "initial CDMA registration check failed: %s", error->message); g_error_free (error); return; } - mm_dbg ("Initial CDMA registration checks finished"); + mm_obj_dbg (self, "initial CDMA registration checks finished"); } static gboolean @@ -10376,9 +10482,13 @@ schedule_initial_registration_checks (MMBroadbandModem *self) /*****************************************************************************/ typedef enum { + /* When user requests a disable operation, the process starts here */ DISABLING_STEP_FIRST, DISABLING_STEP_WAIT_FOR_FINAL_STATE, DISABLING_STEP_DISCONNECT_BEARERS, + /* When the disabling is launched due to a failed enable, the process + * starts here */ + DISABLING_STEP_FIRST_AFTER_ENABLE_FAILED, DISABLING_STEP_IFACE_SIMPLE, DISABLING_STEP_IFACE_FIRMWARE, DISABLING_STEP_IFACE_VOICE, @@ -10396,9 +10506,10 @@ typedef enum { typedef struct { MMBroadbandModem *self; - DisablingStep step; - MMModemState previous_state; - gboolean disabled; + gboolean state_updates; + DisablingStep step; + MMModemState previous_state; + gboolean disabled; } DisablingContext; static void disabling_step (GTask *task); @@ -10410,19 +10521,22 @@ disabling_context_free (DisablingContext *ctx) if (MM_BROADBAND_MODEM_GET_CLASS (ctx->self)->disabling_stopped && !MM_BROADBAND_MODEM_GET_CLASS (ctx->self)->disabling_stopped (ctx->self, &error)) { - mm_warn ("Error when stopping the disabling sequence: %s", error->message); + mm_obj_warn (ctx->self, "error when stopping the disabling sequence: %s", error->message); g_error_free (error); } - if (ctx->disabled) - mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), - MM_MODEM_STATE_DISABLED, - MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED); - else if (ctx->previous_state != MM_MODEM_STATE_DISABLED) { - /* Fallback to previous state */ - mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), - ctx->previous_state, - MM_MODEM_STATE_CHANGE_REASON_UNKNOWN); + /* Only perform state updates if we're asked to do so */ + if (ctx->state_updates) { + if (ctx->disabled) + mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED); + else if (ctx->previous_state != MM_MODEM_STATE_DISABLED) { + /* Fallback to previous state */ + mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), + ctx->previous_state, + MM_MODEM_STATE_CHANGE_REASON_UNKNOWN); + } } g_object_unref (ctx->self); @@ -10430,42 +10544,34 @@ disabling_context_free (DisablingContext *ctx) } static gboolean -disable_finish (MMBaseModem *self, - GAsyncResult *res, - GError **error) +common_disable_finish (MMBroadbandModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } #undef INTERFACE_DISABLE_READY_FN -#define INTERFACE_DISABLE_READY_FN(NAME,TYPE,FATAL_ERRORS) \ - static void \ - NAME##_disable_ready (MMBroadbandModem *self, \ - GAsyncResult *result, \ - GTask *task) \ - { \ - DisablingContext *ctx; \ - GError *error = NULL; \ - \ - if (!mm_##NAME##_disable_finish (TYPE (self), \ - result, \ - &error)) { \ - if (FATAL_ERRORS) { \ - g_task_return_error (task, error); \ - g_object_unref (task); \ - return; \ - } \ - \ - mm_dbg ("Couldn't disable interface: '%s'", \ - error->message); \ - g_error_free (error); \ - return; \ - } \ - \ - /* Go on to next step */ \ - ctx = g_task_get_task_data (task); \ - ctx->step++; \ - disabling_step (task); \ +#define INTERFACE_DISABLE_READY_FN(NAME,TYPE,WARN_ERRORS) \ + static void \ + NAME##_disable_ready (MMBroadbandModem *self, \ + GAsyncResult *result, \ + GTask *task) \ + { \ + DisablingContext *ctx; \ + g_autoptr(GError) error = NULL; \ + \ + if (!mm_##NAME##_disable_finish (TYPE (self), result, &error)) { \ + if (WARN_ERRORS) \ + mm_obj_warn (self, "couldn't disable interface: %s", error->message); \ + else \ + mm_obj_dbg (self, "couldn't disable interface: %s", error->message); \ + } \ + \ + /* Go on to next step */ \ + ctx = g_task_get_task_data (task); \ + ctx->step++; \ + disabling_step (task); \ } INTERFACE_DISABLE_READY_FN (iface_modem, MM_IFACE_MODEM, TRUE) @@ -10543,6 +10649,7 @@ disabling_wait_for_final_state_ready (MMIfaceModem *self, /* We're in a final state now, go on */ + g_assert (ctx->state_updates); mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), MM_MODEM_STATE_DISABLING, MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED); @@ -10556,11 +10663,6 @@ disabling_step (GTask *task) { DisablingContext *ctx; - /* Don't run new steps if we're cancelled */ - if (g_task_return_error_if_cancelled (task)) { - g_object_unref (task); - return; - } ctx = g_task_get_task_data (task); switch (ctx->step) { @@ -10569,6 +10671,11 @@ disabling_step (GTask *task) /* fall through */ case DISABLING_STEP_WAIT_FOR_FINAL_STATE: + /* cancellability allowed at this point */ + if (g_task_return_error_if_cancelled (task)) { + g_object_unref (task); + return; + } mm_iface_modem_wait_for_final_state (MM_IFACE_MODEM (ctx->self), MM_MODEM_STATE_UNKNOWN, /* just any */ (GAsyncReadyCallback)disabling_wait_for_final_state_ready, @@ -10576,6 +10683,11 @@ disabling_step (GTask *task) return; case DISABLING_STEP_DISCONNECT_BEARERS: + /* cancellability allowed at this point */ + if (g_task_return_error_if_cancelled (task)) { + g_object_unref (task); + return; + } if (ctx->self->priv->modem_bearer_list) { mm_bearer_list_disconnect_all_bearers ( ctx->self->priv->modem_bearer_list, @@ -10586,6 +10698,14 @@ disabling_step (GTask *task) ctx->step++; /* fall through */ + case DISABLING_STEP_FIRST_AFTER_ENABLE_FAILED: + /* From this point onwards, the disabling sequence will NEVER fail, all + * errors will be treated as non-fatal, including a possible task + * cancellation. */ + g_task_set_check_cancellable (task, FALSE); + ctx->step++; + /* fall through */ + case DISABLING_STEP_IFACE_SIMPLE: ctx->step++; /* fall through */ @@ -10596,8 +10716,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_VOICE: if (ctx->self->priv->modem_voice_dbus_skeleton) { - mm_dbg ("Modem has voice capabilities, disabling the Voice interface..."); - /* Disabling the Modem Voice interface */ + mm_obj_dbg (ctx->self, "modem has voice capabilities, disabling the Voice interface..."); mm_iface_modem_voice_disable (MM_IFACE_MODEM_VOICE (ctx->self), (GAsyncReadyCallback)iface_modem_voice_disable_ready, task); @@ -10608,8 +10727,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_SIGNAL: if (ctx->self->priv->modem_signal_dbus_skeleton) { - mm_dbg ("Modem has extended signal reporting capabilities, disabling the Signal interface..."); - /* Disabling the Modem Signal interface */ + mm_obj_dbg (ctx->self, "modem has extended signal reporting capabilities, disabling the Signal interface..."); mm_iface_modem_signal_disable (MM_IFACE_MODEM_SIGNAL (ctx->self), (GAsyncReadyCallback)iface_modem_signal_disable_ready, task); @@ -10620,8 +10738,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_OMA: if (ctx->self->priv->modem_oma_dbus_skeleton) { - mm_dbg ("Modem has OMA capabilities, disabling the OMA interface..."); - /* Disabling the Modem Oma interface */ + mm_obj_dbg (ctx->self, "modem has OMA capabilities, disabling the OMA interface..."); mm_iface_modem_oma_disable (MM_IFACE_MODEM_OMA (ctx->self), (GAsyncReadyCallback)iface_modem_oma_disable_ready, task); @@ -10632,8 +10749,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_TIME: if (ctx->self->priv->modem_time_dbus_skeleton) { - mm_dbg ("Modem has time capabilities, disabling the Time interface..."); - /* Disabling the Modem Time interface */ + mm_obj_dbg (ctx->self, "modem has time capabilities, disabling the Time interface..."); mm_iface_modem_time_disable (MM_IFACE_MODEM_TIME (ctx->self), (GAsyncReadyCallback)iface_modem_time_disable_ready, task); @@ -10644,8 +10760,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_MESSAGING: if (ctx->self->priv->modem_messaging_dbus_skeleton) { - mm_dbg ("Modem has messaging capabilities, disabling the Messaging interface..."); - /* Disabling the Modem Messaging interface */ + mm_obj_dbg (ctx->self, "modem has messaging capabilities, disabling the Messaging interface..."); mm_iface_modem_messaging_disable (MM_IFACE_MODEM_MESSAGING (ctx->self), (GAsyncReadyCallback)iface_modem_messaging_disable_ready, task); @@ -10656,8 +10771,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_LOCATION: if (ctx->self->priv->modem_location_dbus_skeleton) { - mm_dbg ("Modem has location capabilities, disabling the Location interface..."); - /* Disabling the Modem Location interface */ + mm_obj_dbg (ctx->self, "modem has location capabilities, disabling the Location interface..."); mm_iface_modem_location_disable (MM_IFACE_MODEM_LOCATION (ctx->self), (GAsyncReadyCallback)iface_modem_location_disable_ready, task); @@ -10668,8 +10782,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_CDMA: if (ctx->self->priv->modem_cdma_dbus_skeleton) { - mm_dbg ("Modem has CDMA capabilities, disabling the Modem CDMA interface..."); - /* Disabling the Modem CDMA interface */ + mm_obj_dbg (ctx->self, "modem has CDMA capabilities, disabling the Modem CDMA interface..."); mm_iface_modem_cdma_disable (MM_IFACE_MODEM_CDMA (ctx->self), (GAsyncReadyCallback)iface_modem_cdma_disable_ready, task); @@ -10680,8 +10793,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_3GPP_USSD: if (ctx->self->priv->modem_3gpp_ussd_dbus_skeleton) { - mm_dbg ("Modem has 3GPP/USSD capabilities, disabling the Modem 3GPP/USSD interface..."); - /* Disabling the Modem 3GPP USSD interface */ + mm_obj_dbg (ctx->self, "modem has 3GPP/USSD capabilities, disabling the Modem 3GPP/USSD interface..."); mm_iface_modem_3gpp_ussd_disable (MM_IFACE_MODEM_3GPP_USSD (ctx->self), (GAsyncReadyCallback)iface_modem_3gpp_ussd_disable_ready, task); @@ -10692,8 +10804,7 @@ disabling_step (GTask *task) case DISABLING_STEP_IFACE_3GPP: if (ctx->self->priv->modem_3gpp_dbus_skeleton) { - mm_dbg ("Modem has 3GPP capabilities, disabling the Modem 3GPP interface..."); - /* Disabling the Modem 3GPP interface */ + mm_obj_dbg (ctx->self, "modem has 3GPP capabilities, disabling the Modem 3GPP interface..."); mm_iface_modem_3gpp_disable (MM_IFACE_MODEM_3GPP (ctx->self), (GAsyncReadyCallback)iface_modem_3gpp_disable_ready, task); @@ -10706,7 +10817,7 @@ disabling_step (GTask *task) /* This skeleton may be NULL when mm_base_modem_disable() gets called at * the same time as modem object disposal. */ if (ctx->self->priv->modem_dbus_skeleton) { - /* Disabling the Modem interface */ + mm_obj_dbg (ctx->self, "disabling the Modem interface..."); mm_iface_modem_disable (MM_IFACE_MODEM (ctx->self), (GAsyncReadyCallback)iface_modem_disable_ready, task); @@ -10716,8 +10827,8 @@ disabling_step (GTask *task) /* fall through */ case DISABLING_STEP_LAST: - ctx->disabled = TRUE; /* All disabled without errors! */ + ctx->disabled = TRUE; g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -10730,17 +10841,20 @@ disabling_step (GTask *task) } static void -disable (MMBaseModem *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +common_disable (MMBroadbandModem *self, + gboolean state_updates, + DisablingStep first_step, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { DisablingContext *ctx; - GTask *task; + GTask *task; ctx = g_new0 (DisablingContext, 1); ctx->self = g_object_ref (self); - ctx->step = DISABLING_STEP_FIRST; + ctx->state_updates = state_updates; + ctx->step = first_step; task = g_task_new (self, cancellable, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)disabling_context_free); @@ -10748,6 +10862,55 @@ disable (MMBaseModem *self, disabling_step (task); } +/* Implicit disabling after failed enable */ + +static gboolean +enable_failed_finish (MMBroadbandModem *self, + GAsyncResult *res, + GError **error) +{ + /* The implicit disabling should never ever fail */ + g_assert (common_disable_finish (self, res, NULL)); + return TRUE; +} + +static void +enable_failed (MMBroadbandModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_disable (self, + FALSE, /* don't perform state updates */ + DISABLING_STEP_FIRST_AFTER_ENABLE_FAILED, + NULL, /* no cancellable */ + callback, + user_data); +} + +/* User-requested disable operation */ + +static gboolean +disable_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error) +{ + return common_disable_finish (MM_BROADBAND_MODEM (self), res, error); +} + +static void +disable (MMBaseModem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + common_disable (MM_BROADBAND_MODEM (self), + TRUE, /* perform state updates */ + DISABLING_STEP_FIRST, + cancellable, + callback, + user_data); +} + /*****************************************************************************/ typedef enum { @@ -10771,9 +10934,10 @@ typedef enum { typedef struct { MMBroadbandModem *self; - EnablingStep step; - MMModemState previous_state; - gboolean enabled; + EnablingStep step; + MMModemState previous_state; + gboolean enabled; + GError *saved_error; } EnablingContext; static void enabling_step (GTask *task); @@ -10781,6 +10945,8 @@ static void enabling_step (GTask *task); static void enabling_context_free (EnablingContext *ctx) { + g_assert (!ctx->saved_error); + if (ctx->enabled) mm_iface_modem_update_state (MM_IFACE_MODEM (ctx->self), MM_MODEM_STATE_ENABLED, @@ -10804,34 +10970,51 @@ enable_finish (MMBaseModem *self, return g_task_propagate_boolean (G_TASK (res), error); } +static void +enable_failed_ready (MMBroadbandModem *self, + GAsyncResult *res, + GTask *task) +{ + EnablingContext *ctx; + + ctx = g_task_get_task_data (task); + + /* The disabling run after a failed enable will never fail */ + g_assert (enable_failed_finish (self, res, NULL)); + + g_assert (ctx->saved_error); + g_task_return_error (task, g_steal_pointer (&ctx->saved_error)); + g_object_unref (task); +} + #undef INTERFACE_ENABLE_READY_FN -#define INTERFACE_ENABLE_READY_FN(NAME,TYPE,FATAL_ERRORS) \ - static void \ - NAME##_enable_ready (MMBroadbandModem *self, \ - GAsyncResult *result, \ - GTask *task) \ - { \ - EnablingContext *ctx; \ - GError *error = NULL; \ - \ - if (!mm_##NAME##_enable_finish (TYPE (self), \ - result, \ - &error)) { \ - if (FATAL_ERRORS) { \ - g_task_return_error (task, error); \ - g_object_unref (task); \ - return; \ - } \ - \ - mm_dbg ("Couldn't enable interface: '%s'", \ - error->message); \ - g_error_free (error); \ - } \ - \ - /* Go on to next step */ \ - ctx = g_task_get_task_data (task); \ - ctx->step++; \ - enabling_step (task); \ +#define INTERFACE_ENABLE_READY_FN(NAME,TYPE,FATAL_ERRORS) \ + static void \ + NAME##_enable_ready (MMBroadbandModem *self, \ + GAsyncResult *result, \ + GTask *task) \ + { \ + EnablingContext *ctx; \ + g_autoptr(GError) error = NULL; \ + \ + ctx = g_task_get_task_data (task); \ + \ + if (!mm_##NAME##_enable_finish (TYPE (self), result, &error)) { \ + if (FATAL_ERRORS) { \ + mm_obj_warn (self, "couldn't enable interface: '%s'", error->message); \ + g_assert (!ctx->saved_error); \ + ctx->saved_error = g_steal_pointer (&error); \ + mm_obj_dbg (self, "running implicit disable after failed enable..."); \ + enable_failed (self, (GAsyncReadyCallback) enable_failed_ready, task); \ + return; \ + } \ + \ + mm_obj_dbg (self, "couldn't enable interface: '%s'", error->message); \ + } \ + \ + /* Go on to next step */ \ + ctx->step++; \ + enabling_step (task); \ } INTERFACE_ENABLE_READY_FN (iface_modem, MM_IFACE_MODEM, TRUE) @@ -10936,6 +11119,9 @@ enabling_step (GTask *task) /* fall through */ case ENABLING_STEP_IFACE_MODEM: + /* From now on, the failure to enable one of the mandatory interfaces + * will trigger the implicit disabling process */ + g_assert (ctx->self->priv->modem_dbus_skeleton != NULL); /* Enabling the Modem interface */ mm_iface_modem_enable (MM_IFACE_MODEM (ctx->self), @@ -10946,7 +11132,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_3GPP: if (ctx->self->priv->modem_3gpp_dbus_skeleton) { - mm_dbg ("Modem has 3GPP capabilities, enabling the Modem 3GPP interface..."); + mm_obj_dbg (ctx->self, "modem has 3GPP capabilities, enabling the Modem 3GPP interface..."); /* Enabling the Modem 3GPP interface */ mm_iface_modem_3gpp_enable (MM_IFACE_MODEM_3GPP (ctx->self), g_task_get_cancellable (task), @@ -10959,7 +11145,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_3GPP_USSD: if (ctx->self->priv->modem_3gpp_ussd_dbus_skeleton) { - mm_dbg ("Modem has 3GPP/USSD capabilities, enabling the Modem 3GPP/USSD interface..."); + mm_obj_dbg (ctx->self, "modem has 3GPP/USSD capabilities, enabling the Modem 3GPP/USSD interface..."); mm_iface_modem_3gpp_ussd_enable (MM_IFACE_MODEM_3GPP_USSD (ctx->self), (GAsyncReadyCallback)iface_modem_3gpp_ussd_enable_ready, task); @@ -10970,7 +11156,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_CDMA: if (ctx->self->priv->modem_cdma_dbus_skeleton) { - mm_dbg ("Modem has CDMA capabilities, enabling the Modem CDMA interface..."); + mm_obj_dbg (ctx->self, "modem has CDMA capabilities, enabling the Modem CDMA interface..."); /* Enabling the Modem CDMA interface */ mm_iface_modem_cdma_enable (MM_IFACE_MODEM_CDMA (ctx->self), g_task_get_cancellable (task), @@ -10983,7 +11169,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_LOCATION: if (ctx->self->priv->modem_location_dbus_skeleton) { - mm_dbg ("Modem has location capabilities, enabling the Location interface..."); + mm_obj_dbg (ctx->self, "modem has location capabilities, enabling the Location interface..."); /* Enabling the Modem Location interface */ mm_iface_modem_location_enable (MM_IFACE_MODEM_LOCATION (ctx->self), g_task_get_cancellable (task), @@ -10996,7 +11182,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_MESSAGING: if (ctx->self->priv->modem_messaging_dbus_skeleton) { - mm_dbg ("Modem has messaging capabilities, enabling the Messaging interface..."); + mm_obj_dbg (ctx->self, "modem has messaging capabilities, enabling the Messaging interface..."); /* Enabling the Modem Messaging interface */ mm_iface_modem_messaging_enable (MM_IFACE_MODEM_MESSAGING (ctx->self), g_task_get_cancellable (task), @@ -11009,7 +11195,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_TIME: if (ctx->self->priv->modem_time_dbus_skeleton) { - mm_dbg ("Modem has time capabilities, enabling the Time interface..."); + mm_obj_dbg (ctx->self, "modem has time capabilities, enabling the Time interface..."); /* Enabling the Modem Time interface */ mm_iface_modem_time_enable (MM_IFACE_MODEM_TIME (ctx->self), g_task_get_cancellable (task), @@ -11022,7 +11208,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_SIGNAL: if (ctx->self->priv->modem_signal_dbus_skeleton) { - mm_dbg ("Modem has extended signal reporting capabilities, enabling the Signal interface..."); + mm_obj_dbg (ctx->self, "modem has extended signal reporting capabilities, enabling the Signal interface..."); /* Enabling the Modem Signal interface */ mm_iface_modem_signal_enable (MM_IFACE_MODEM_SIGNAL (ctx->self), g_task_get_cancellable (task), @@ -11035,7 +11221,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_OMA: if (ctx->self->priv->modem_oma_dbus_skeleton) { - mm_dbg ("Modem has OMA capabilities, enabling the OMA interface..."); + mm_obj_dbg (ctx->self, "modem has OMA capabilities, enabling the OMA interface..."); /* Enabling the Modem Oma interface */ mm_iface_modem_oma_enable (MM_IFACE_MODEM_OMA (ctx->self), g_task_get_cancellable (task), @@ -11048,7 +11234,7 @@ enabling_step (GTask *task) case ENABLING_STEP_IFACE_VOICE: if (ctx->self->priv->modem_voice_dbus_skeleton) { - mm_dbg ("Modem has voice capabilities, enabling the Voice interface..."); + mm_obj_dbg (ctx->self, "modem has voice capabilities, enabling the Voice interface..."); /* Enabling the Modem Voice interface */ mm_iface_modem_voice_enable (MM_IFACE_MODEM_VOICE (ctx->self), g_task_get_cancellable (task), @@ -11198,7 +11384,7 @@ initialize_context_free (InitializeContext *ctx) if (ctx->ports_ctx && MM_BROADBAND_MODEM_GET_CLASS (ctx->self)->initialization_stopped && !MM_BROADBAND_MODEM_GET_CLASS (ctx->self)->initialization_stopped (ctx->self, ctx->ports_ctx, &error)) { - mm_warn ("Error when stopping the initialization sequence: %s", error->message); + mm_obj_warn (ctx->self, "error when stopping the initialization sequence: %s", error->message); g_error_free (error); } @@ -11228,7 +11414,7 @@ initialization_started_ready (MMBroadbandModem *self, /* May return NULL without error */ ports_ctx = MM_BROADBAND_MODEM_GET_CLASS (self)->initialization_started_finish (self, result, &error); if (error) { - mm_warn ("Couldn't start initialization: %s", error->message); + mm_obj_warn (self, "couldn't start initialization: %s", error->message); g_error_free (error); /* There is no Modem interface yet, so just update the variable directly */ @@ -11264,7 +11450,7 @@ iface_modem_initialize_ready (MMBroadbandModem *self, MMModemStateFailedReason failed_reason = MM_MODEM_STATE_FAILED_REASON_UNKNOWN; /* Report the new FAILED state */ - mm_warn ("Modem couldn't be initialized: %s", error->message); + mm_obj_warn (self, "modem couldn't be initialized: %s", error->message); if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, @@ -11323,8 +11509,8 @@ iface_modem_initialize_ready (MMBroadbandModem *self, \ if (!mm_##NAME##_initialize_finish (TYPE (self), result, &error)) { \ if (FATAL_ERRORS) { \ - mm_warn ("Couldn't initialize interface: '%s'", \ - error->message); \ + mm_obj_warn (self, "couldn't initialize interface: '%s'", \ + error->message); \ g_error_free (error); \ \ /* Report the new FAILED state */ \ @@ -11337,8 +11523,8 @@ iface_modem_initialize_ready (MMBroadbandModem *self, return; \ } \ \ - mm_dbg ("Couldn't initialize interface: '%s'", \ - error->message); \ + mm_obj_dbg (self, "couldn't initialize interface: '%s'", \ + error->message); \ /* Just shutdown this interface */ \ mm_##NAME##_shutdown (TYPE (self)); \ g_error_free (error); \ @@ -11528,15 +11714,16 @@ initialize_step (GTask *task) if (is_sim_hot_swap_supported) { if (!is_sim_hot_swap_configured) { - mm_warn ("SIM hot swap supported but not configured. Skipping opening ports"); + mm_obj_warn (ctx->self, "SIM hot swap supported but not configured. Skipping opening ports"); } else { PortsContext *ports; GError *error = NULL; - mm_dbg ("Creating ports context for SIM hot swap"); + mm_obj_dbg (ctx->self, "creating ports context for SIM hot swap"); ports = ports_context_new (); if (!ports_context_open (ctx->self, ports, FALSE, FALSE, FALSE, &error)) { - mm_warn ("Couldn't open ports during Modem SIM hot swap enabling: %s", error? error->message : "unknown reason"); + mm_obj_warn (ctx->self, "couldn't open ports during Modem SIM hot swap enabling: %s", + error ? error->message : "unknown reason"); g_error_free (error); } else { ctx->self->priv->sim_hot_swap_ports_ctx = ports_context_ref (ports); @@ -11546,7 +11733,7 @@ initialize_step (GTask *task) } } } else - mm_dbg ("Ports context for SIM hot swap already available"); + mm_obj_dbg (ctx->self, "ports context for SIM hot swap already available"); ctx->step++; /* fall through */ @@ -11584,13 +11771,13 @@ initialize_step (GTask *task) if (reason == MM_MODEM_STATE_FAILED_REASON_SIM_MISSING) { if (!is_sim_hot_swap_supported) { - mm_dbg ("SIM is missing, but this modem does not support SIM hot swap."); + mm_obj_dbg (ctx->self, "SIM is missing, but this modem does not support SIM hot swap."); } else if (!is_sim_hot_swap_configured) { - mm_warn ("SIM is missing, but SIM hot swap could not be configured."); + mm_obj_warn (ctx->self, "SIM is missing, but SIM hot swap could not be configured."); } else if (!ctx->self->priv->sim_hot_swap_ports_ctx) { - mm_err ("SIM is missing and SIM hot swap is configured, but ports are not opened."); + mm_obj_err (ctx->self, "SIM is missing and SIM hot swap is configured, but ports are not opened."); } else { - mm_dbg ("SIM is missing, but SIM hot swap is enabled. Waiting for SIM..."); + mm_obj_dbg (ctx->self, "SIM is missing, but SIM hot swap is enabled; waiting for SIM..."); error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, "Modem is unusable due to SIM missing, " @@ -11723,43 +11910,31 @@ initialize (MMBaseModem *self, /*****************************************************************************/ -gchar * -mm_broadband_modem_take_and_convert_to_utf8 (MMBroadbandModem *self, - gchar *str) -{ - /* should only be used AFTER current charset is set */ - if (self->priv->modem_current_charset == MM_MODEM_CHARSET_UNKNOWN) - return str; - - return mm_charset_take_and_convert_to_utf8 (str, - self->priv->modem_current_charset); -} - -gchar * -mm_broadband_modem_take_and_convert_to_current_charset (MMBroadbandModem *self, - gchar *str) -{ - /* should only be used AFTER current charset is set */ - if (self->priv->modem_current_charset == MM_MODEM_CHARSET_UNKNOWN) - return str; - - return mm_utf8_take_and_convert_to_charset (str, self->priv->modem_current_charset); -} - MMModemCharset mm_broadband_modem_get_current_charset (MMBroadbandModem *self) { return self->priv->modem_current_charset; } +/*****************************************************************************/ + gchar * -mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, - const gchar *ati, - const gchar *ati1) -{ +mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, + const gchar *ati, + const gchar *ati1, + GError **error) +{ + /* do nothing if device has gone already */ + if (!self->priv->modem_dbus_skeleton) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Modem interface skeleton unavailable"); + return NULL; + } + return (mm_create_device_identifier ( mm_base_modem_get_vendor_id (MM_BASE_MODEM (self)), mm_base_modem_get_product_id (MM_BASE_MODEM (self)), + self, ati, ati1, mm_gdbus_modem_get_equipment_identifier ( @@ -11772,36 +11947,18 @@ mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, MM_GDBUS_MODEM (self->priv->modem_dbus_skeleton)))); } - /*****************************************************************************/ -static void -after_hotswap_event_disable_ready (MMBaseModem *self, - GAsyncResult *res, - gpointer user_data) -{ - GError *error = NULL; - mm_base_modem_disable_finish (self, res, &error); - if (error) { - mm_err ("Disable modem error: %s", error->message); - g_error_free (error); - } else { - mm_base_modem_set_valid (self, FALSE); - } -} void -mm_broadband_modem_update_sim_hot_swap_detected (MMBroadbandModem *self) +mm_broadband_modem_sim_hot_swap_detected (MMBroadbandModem *self) { if (self->priv->sim_hot_swap_ports_ctx) { - mm_dbg ("Releasing SIM hot swap ports context"); + mm_obj_dbg (self, "releasing SIM hot swap ports context"); ports_context_unref (self->priv->sim_hot_swap_ports_ctx); self->priv->sim_hot_swap_ports_ctx = NULL; } - mm_base_modem_set_reprobe (MM_BASE_MODEM (self), TRUE); - mm_base_modem_disable (MM_BASE_MODEM (self), - (GAsyncReadyCallback) after_hotswap_event_disable_ready, - NULL); + mm_base_modem_process_sim_event (MM_BASE_MODEM (self)); } /*****************************************************************************/ @@ -11883,6 +12040,10 @@ set_property (GObject *object, g_clear_object (&self->priv->modem_sim); self->priv->modem_sim = g_value_dup_object (value); break; + case PROP_MODEM_SIM_SLOTS: + g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref); + self->priv->modem_sim_slots = g_value_dup_boxed (value); + break; case PROP_MODEM_BEARER_LIST: g_clear_object (&self->priv->modem_bearer_list); self->priv->modem_bearer_list = g_value_dup_object (value); @@ -11902,6 +12063,9 @@ set_property (GObject *object, case PROP_MODEM_3GPP_EPS_NETWORK_SUPPORTED: self->priv->modem_3gpp_eps_network_supported = g_value_get_boolean (value); break; + case PROP_MODEM_3GPP_5GS_NETWORK_SUPPORTED: + self->priv->modem_3gpp_5gs_network_supported = g_value_get_boolean (value); + break; case PROP_MODEM_3GPP_IGNORED_FACILITY_LOCKS: self->priv->modem_3gpp_ignored_facility_locks = g_value_get_flags (value); break; @@ -11960,6 +12124,9 @@ set_property (GObject *object, case PROP_MODEM_CARRIER_CONFIG_MAPPING: self->priv->carrier_config_mapping = g_value_dup_string (value); break; + case PROP_MODEM_FIRMWARE_IGNORE_CARRIER: + self->priv->modem_firmware_ignore_carrier = g_value_get_boolean (value); + break; case PROP_FLOW_CONTROL: self->priv->flow_control = g_value_get_flags (value); break; @@ -12020,6 +12187,9 @@ get_property (GObject *object, case PROP_MODEM_SIM: g_value_set_object (value, self->priv->modem_sim); break; + case PROP_MODEM_SIM_SLOTS: + g_value_set_boxed (value, self->priv->modem_sim_slots); + break; case PROP_MODEM_BEARER_LIST: g_value_set_object (value, self->priv->modem_bearer_list); break; @@ -12038,6 +12208,9 @@ get_property (GObject *object, case PROP_MODEM_3GPP_EPS_NETWORK_SUPPORTED: g_value_set_boolean (value, self->priv->modem_3gpp_eps_network_supported); break; + case PROP_MODEM_3GPP_5GS_NETWORK_SUPPORTED: + g_value_set_boolean (value, self->priv->modem_3gpp_5gs_network_supported); + break; case PROP_MODEM_3GPP_IGNORED_FACILITY_LOCKS: g_value_set_flags (value, self->priv->modem_3gpp_ignored_facility_locks); break; @@ -12092,6 +12265,9 @@ get_property (GObject *object, case PROP_MODEM_CARRIER_CONFIG_MAPPING: g_value_set_string (value, self->priv->carrier_config_mapping); break; + case PROP_MODEM_FIRMWARE_IGNORE_CARRIER: + g_value_set_boolean (value, self->priv->modem_firmware_ignore_carrier); + break; case PROP_FLOW_CONTROL: g_value_set_flags (value, self->priv->flow_control); break; @@ -12118,6 +12294,7 @@ mm_broadband_modem_init (MMBroadbandModem *self) self->priv->modem_3gpp_cs_network_supported = TRUE; self->priv->modem_3gpp_ps_network_supported = TRUE; self->priv->modem_3gpp_eps_network_supported = FALSE; + self->priv->modem_3gpp_5gs_network_supported = FALSE; self->priv->modem_3gpp_ignored_facility_locks = MM_MODEM_3GPP_FACILITY_NONE; self->priv->modem_cdma_cdma1x_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; self->priv->modem_cdma_evdo_registration_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; @@ -12220,6 +12397,7 @@ dispose (GObject *object) g_clear_object (&self->priv->modem_3gpp_initial_eps_bearer); g_clear_object (&self->priv->modem_sim); + g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref); g_clear_object (&self->priv->modem_bearer_list); g_clear_object (&self->priv->modem_messaging_sms_list); g_clear_object (&self->priv->modem_voice_call_list); @@ -12581,6 +12759,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) PROP_MODEM_SIM, MM_IFACE_MODEM_SIM); + g_object_class_override_property (object_class, + PROP_MODEM_SIM_SLOTS, + MM_IFACE_MODEM_SIM_SLOTS); + g_object_class_override_property (object_class, PROP_MODEM_BEARER_LIST, MM_IFACE_MODEM_BEARER_LIST); @@ -12605,6 +12787,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) PROP_MODEM_3GPP_EPS_NETWORK_SUPPORTED, MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED); + g_object_class_override_property (object_class, + PROP_MODEM_3GPP_5GS_NETWORK_SUPPORTED, + MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED); + g_object_class_override_property (object_class, PROP_MODEM_3GPP_IGNORED_FACILITY_LOCKS, MM_IFACE_MODEM_3GPP_IGNORED_FACILITY_LOCKS); @@ -12677,6 +12863,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) PROP_MODEM_CARRIER_CONFIG_MAPPING, MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING); + g_object_class_override_property (object_class, + PROP_MODEM_FIRMWARE_IGNORE_CARRIER, + MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER); + properties[PROP_FLOW_CONTROL] = g_param_spec_flags (MM_BROADBAND_MODEM_FLOW_CONTROL, "Flow control", diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h index 8042f509..2ba05799 100644 --- a/src/mm-broadband-modem.h +++ b/src/mm-broadband-modem.h @@ -92,6 +92,7 @@ struct _MMBroadbandModemClass { }; GType mm_broadband_modem_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBroadbandModem, g_object_unref) MMBroadbandModem *mm_broadband_modem_new (const gchar *device, const gchar **drivers, @@ -99,25 +100,14 @@ MMBroadbandModem *mm_broadband_modem_new (const gchar *device, guint16 vendor_id, guint16 product_id); -/* Convert the given string, which comes in the charset currently set in the - * modem, to UTF-8. Given in the API so that subclasses can also use it directly. - */ -gchar *mm_broadband_modem_take_and_convert_to_utf8 (MMBroadbandModem *self, - gchar *str); - -/* Convert the given string, which comes in UTF-8, to the charset currently set - * in the modem. Given in the API so that subclasses can also use it directly. - */ -gchar *mm_broadband_modem_take_and_convert_to_current_charset (MMBroadbandModem *self, - gchar *str); - MMModemCharset mm_broadband_modem_get_current_charset (MMBroadbandModem *self); /* Create a unique device identifier string using the ATI and ATI1 replies and some * additional internal info */ -gchar *mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, - const gchar *ati, - const gchar *ati1); +gchar *mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, + const gchar *ati, + const gchar *ati1, + GError **error); /* Locking/unlocking SMS storages */ void mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self, @@ -132,6 +122,6 @@ void mm_broadband_modem_unlock_sms_storages (MMBroadbandModem *self, gboolean mem1, gboolean mem2); /* Helper to update SIM hot swap */ -void mm_broadband_modem_update_sim_hot_swap_detected (MMBroadbandModem *self); +void mm_broadband_modem_sim_hot_swap_detected (MMBroadbandModem *self); #endif /* MM_BROADBAND_MODEM_H */ diff --git a/src/mm-call-list.h b/src/mm-call-list.h index 3f85d1d4..1183129e 100644 --- a/src/mm-call-list.h +++ b/src/mm-call-list.h @@ -55,6 +55,7 @@ struct _MMCallListClass { }; GType mm_call_list_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMCallList, g_object_unref) MMCallList *mm_call_list_new (MMBaseModem *modem); diff --git a/src/mm-charsets.c b/src/mm-charsets.c index a5c70165..5430e253 100644 --- a/src/mm-charsets.c +++ b/src/mm-charsets.c @@ -11,6 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2020 Aleksander Morgado */ #include @@ -26,227 +27,77 @@ #include "mm-charsets.h" #include "mm-log.h" -typedef struct { - const char *gsm_name; - const char *other_name; - const char *iconv_from_name; - const char *iconv_to_name; - MMModemCharset charset; -} CharsetEntry; - -static CharsetEntry charset_map[] = { - { "UTF-8", "UTF8", "UTF-8", "UTF-8//TRANSLIT", MM_MODEM_CHARSET_UTF8 }, - { "UCS2", NULL, "UCS-2BE", "UCS-2BE//TRANSLIT", MM_MODEM_CHARSET_UCS2 }, - { "IRA", "ASCII", "ASCII", "ASCII//TRANSLIT", MM_MODEM_CHARSET_IRA }, - { "GSM", NULL, NULL, NULL, MM_MODEM_CHARSET_GSM }, - { "8859-1", NULL, "ISO8859-1", "ISO8859-1//TRANSLIT", MM_MODEM_CHARSET_8859_1 }, - { "PCCP437", "CP437", "CP437", "CP437//TRANSLIT", MM_MODEM_CHARSET_PCCP437 }, - { "PCDN", "CP850", "CP850", "CP850//TRANSLIT", MM_MODEM_CHARSET_PCDN }, - { "HEX", NULL, NULL, NULL, MM_MODEM_CHARSET_HEX }, - { NULL, NULL, NULL, NULL, MM_MODEM_CHARSET_UNKNOWN } -}; - -const char * -mm_modem_charset_to_string (MMModemCharset charset) -{ - CharsetEntry *iter = &charset_map[0]; +/* Common fallback character when transliteration is enabled */ +static const gchar *translit_fallback = "?"; - g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); +/******************************************************************************/ +/* Expected charset settings */ - while (iter->gsm_name) { - if (iter->charset == charset) - return iter->gsm_name; - iter++; - } - g_warn_if_reached (); - return NULL; -} +typedef struct { + MMModemCharset charset; + const gchar *gsm_name; + const gchar *other_name; + const gchar *iconv_name; +} CharsetSettings; + +static const CharsetSettings charset_settings[] = { + { MM_MODEM_CHARSET_UTF8, "UTF-8", "UTF8", "UTF-8" }, + { MM_MODEM_CHARSET_UCS2, "UCS2", NULL, "UCS-2BE" }, + { MM_MODEM_CHARSET_IRA, "IRA", "ASCII", "ASCII" }, + { MM_MODEM_CHARSET_GSM, "GSM", NULL, NULL }, + { MM_MODEM_CHARSET_8859_1, "8859-1", NULL, "ISO8859-1" }, + { MM_MODEM_CHARSET_PCCP437, "PCCP437", "CP437", "CP437" }, + { MM_MODEM_CHARSET_PCDN, "PCDN", "CP850", "CP850" }, + { MM_MODEM_CHARSET_UTF16, "UTF-16", "UTF16", "UTF-16BE" }, +}; MMModemCharset -mm_modem_charset_from_string (const char *string) +mm_modem_charset_from_string (const gchar *string) { - CharsetEntry *iter = &charset_map[0]; + guint i; g_return_val_if_fail (string != NULL, MM_MODEM_CHARSET_UNKNOWN); - while (iter->gsm_name) { - if (strcasestr (string, iter->gsm_name)) - return iter->charset; - if (iter->other_name && strcasestr (string, iter->other_name)) - return iter->charset; - iter++; + for (i = 0; i < G_N_ELEMENTS (charset_settings); i++) { + if (strcasestr (string, charset_settings[i].gsm_name)) + return charset_settings[i].charset; + if (charset_settings[i].other_name && strcasestr (string, charset_settings[i].other_name)) + return charset_settings[i].charset; } return MM_MODEM_CHARSET_UNKNOWN; } -static const char * -charset_iconv_to (MMModemCharset charset) +static const CharsetSettings * +lookup_charset_settings (MMModemCharset charset) { - CharsetEntry *iter = &charset_map[0]; - - g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); - - while (iter->gsm_name) { - if (iter->charset == charset) - return iter->iconv_to_name; - iter++; - } - g_warn_if_reached (); - return NULL; -} - -static const char * -charset_iconv_from (MMModemCharset charset) -{ - CharsetEntry *iter = &charset_map[0]; + guint i; g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); - - while (iter->gsm_name) { - if (iter->charset == charset) - return iter->iconv_from_name; - iter++; + for (i = 0; i < G_N_ELEMENTS (charset_settings); i++) { + if (charset_settings[i].charset == charset) + return &charset_settings[i]; } g_warn_if_reached (); return NULL; } -gboolean -mm_modem_charset_byte_array_append (GByteArray *array, - const char *utf8, - gboolean quoted, - MMModemCharset charset) -{ - const char *iconv_to; - char *converted; - GError *error = NULL; - gsize written = 0; - - g_return_val_if_fail (array != NULL, FALSE); - g_return_val_if_fail (utf8 != NULL, FALSE); - - iconv_to = charset_iconv_to (charset); - g_return_val_if_fail (iconv_to != NULL, FALSE); - - converted = g_convert (utf8, -1, iconv_to, "UTF-8", NULL, &written, &error); - if (!converted) { - if (error) { - mm_warn ("failed to convert '%s' to %s character set: (%d) %s", - utf8, iconv_to, error->code, error->message); - g_error_free (error); - } - return FALSE; - } - - if (quoted) - g_byte_array_append (array, (const guint8 *) "\"", 1); - g_byte_array_append (array, (const guint8 *) converted, written); - if (quoted) - g_byte_array_append (array, (const guint8 *) "\"", 1); - - g_free (converted); - return TRUE; -} - -gchar * -mm_modem_charset_byte_array_to_utf8 (GByteArray *array, - MMModemCharset charset) -{ - char *converted; - const char *iconv_from; - GError *error = NULL; - - g_return_val_if_fail (array != NULL, NULL); - g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); - - iconv_from = charset_iconv_from (charset); - g_return_val_if_fail (iconv_from != NULL, FALSE); - - converted = g_convert ((const gchar *)array->data, array->len, - "UTF-8//TRANSLIT", iconv_from, - NULL, NULL, &error); - if (!converted || error) { - g_clear_error (&error); - converted = NULL; - } - - return converted; -} - -char * -mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset) +const gchar * +mm_modem_charset_to_string (MMModemCharset charset) { - char *unconverted, *converted; - const char *iconv_from; - gsize unconverted_len = 0; - GError *error = NULL; - - g_return_val_if_fail (src != NULL, NULL); - g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); + const CharsetSettings *settings; - iconv_from = charset_iconv_from (charset); - g_return_val_if_fail (iconv_from != NULL, FALSE); - - unconverted = mm_utils_hexstr2bin (src, &unconverted_len); - if (!unconverted) - return NULL; - - if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA) - return unconverted; - - converted = g_convert (unconverted, unconverted_len, - "UTF-8//TRANSLIT", iconv_from, - NULL, NULL, &error); - if (!converted || error) { - g_clear_error (&error); - converted = NULL; - } - - g_free (unconverted); - - return converted; -} - -char * -mm_modem_charset_utf8_to_hex (const char *src, MMModemCharset charset) -{ - gsize converted_len = 0; - char *converted; - const char *iconv_to; - GError *error = NULL; - gchar *hex; - - g_return_val_if_fail (src != NULL, NULL); - g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL); - - iconv_to = charset_iconv_from (charset); - g_return_val_if_fail (iconv_to != NULL, FALSE); - - if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA) - return g_strdup (src); - - converted = g_convert (src, strlen (src), - iconv_to, "UTF-8//TRANSLIT", - NULL, &converted_len, &error); - if (!converted || error) { - g_clear_error (&error); - g_free (converted); - return NULL; - } - - /* Get hex representation of the string */ - hex = mm_utils_bin2hexstr ((guint8 *)converted, converted_len); - g_free (converted); - return hex; + settings = lookup_charset_settings (charset); + return settings ? settings->gsm_name : NULL; } +/******************************************************************************/ /* GSM 03.38 encoding conversion stuff */ #define GSM_DEF_ALPHABET_SIZE 128 #define GSM_EXT_ALPHABET_SIZE 10 typedef struct GsmUtf8Mapping { - gchar chars[3]; + gchar chars[3]; guint8 len; guint8 gsm; /* only used for extended GSM charset */ } GsmUtf8Mapping; @@ -330,7 +181,8 @@ static const GsmUtf8Mapping gsm_def_utf8_alphabet[GSM_DEF_ALPHABET_SIZE] = { }; static guint8 -gsm_def_char_to_utf8 (const guint8 gsm, guint8 out_utf8[2]) +gsm_def_char_to_utf8 (const guint8 gsm, + guint8 out_utf8[2]) { g_return_val_if_fail (gsm < GSM_DEF_ALPHABET_SIZE, 0); memcpy (&out_utf8[0], &gsm_def_utf8_alphabet[gsm].chars[0], gsm_def_utf8_alphabet[gsm].len); @@ -338,9 +190,11 @@ gsm_def_char_to_utf8 (const guint8 gsm, guint8 out_utf8[2]) } static gboolean -utf8_to_gsm_def_char (const char *utf8, guint32 len, guint8 *out_gsm) +utf8_to_gsm_def_char (const gchar *utf8, + guint32 len, + guint8 *out_gsm) { - int i; + gint i; if (len > 0 && len < 4) { for (i = 0; i < GSM_DEF_ALPHABET_SIZE; i++) { @@ -355,6 +209,22 @@ utf8_to_gsm_def_char (const char *utf8, guint32 len, guint8 *out_gsm) return FALSE; } +static gboolean +translit_gsm_nul_byte (GByteArray *gsm) +{ + guint i; + guint n_replaces = 0; + + for (i = 0; i < gsm->len; i++) { + if (gsm->data[i] == 0x00) { + utf8_to_gsm_def_char (translit_fallback, strlen (translit_fallback), &gsm->data[i]); + n_replaces++; + } + } + + return (n_replaces > 0); +} + #define EONE(a, g) { {a, 0x00, 0x00}, 1, g } #define ETHR(a, b, c, g) { {a, b, c}, 3, g } @@ -377,7 +247,8 @@ static const GsmUtf8Mapping gsm_ext_utf8_alphabet[GSM_EXT_ALPHABET_SIZE] = { #define GSM_ESCAPE_CHAR 0x1b static guint8 -gsm_ext_char_to_utf8 (const guint8 gsm, guint8 out_utf8[3]) +gsm_ext_char_to_utf8 (const guint8 gsm, + guint8 out_utf8[3]) { int i; @@ -391,7 +262,9 @@ gsm_ext_char_to_utf8 (const guint8 gsm, guint8 out_utf8[3]) } static gboolean -utf8_to_gsm_ext_char (const char *utf8, guint32 len, guint8 *out_gsm) +utf8_to_gsm_ext_char (const gchar *utf8, + guint32 len, + guint8 *out_gsm) { int i; @@ -408,11 +281,14 @@ utf8_to_gsm_ext_char (const char *utf8, guint32 len, guint8 *out_gsm) return FALSE; } -guint8 * -mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len) +static guint8 * +charset_gsm_unpacked_to_utf8 (const guint8 *gsm, + guint32 len, + gboolean translit, + GError **error) { - guint i; - GByteArray *utf8; + g_autoptr(GByteArray) utf8 = NULL; + guint i; g_return_val_if_fail (gsm != NULL, NULL); g_return_val_if_fail (len < 4096, NULL); @@ -458,25 +334,36 @@ mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len) if (ulen) g_byte_array_append (utf8, &uchars[0], ulen); - else - g_byte_array_append (utf8, (guint8 *) "?", 1); + else if (translit) + g_byte_array_append (utf8, (guint8 *) translit_fallback, strlen (translit_fallback)); + else { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Invalid conversion from GSM7"); + return NULL; + } } - g_byte_array_append (utf8, (guint8 *) "\0", 1); /* NULL terminator */ - return g_byte_array_free (utf8, FALSE); + /* Always make sure returned string is NUL terminated */ + g_byte_array_append (utf8, (guint8 *) "\0", 1); + return g_byte_array_free (g_steal_pointer (&utf8), FALSE); } -guint8 * -mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len) +static guint8 * +charset_utf8_to_unpacked_gsm (const gchar *utf8, + gboolean translit, + guint32 *out_len, + GError **error) { - GByteArray *gsm; - const char *c = utf8, *next = c; - static const guint8 gesc = GSM_ESCAPE_CHAR; - int i = 0; - - g_return_val_if_fail (utf8 != NULL, NULL); - g_return_val_if_fail (out_len != NULL, NULL); - g_return_val_if_fail (g_utf8_validate (utf8, -1, NULL), NULL); + g_autoptr(GByteArray) gsm = NULL; + const gchar *c; + const gchar *next; + static const guint8 gesc = GSM_ESCAPE_CHAR; + + if (!utf8 || !g_utf8_validate (utf8, -1, NULL)) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Couldn't convert UTF-8 to GSM: input UTF-8 validation failed"); + return NULL; + } /* worst case initial length */ gsm = g_byte_array_sized_new (g_utf8_strlen (utf8, -1) * 2 + 1); @@ -484,10 +371,13 @@ mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len) if (*utf8 == 0x00) { /* Zero-length string */ g_byte_array_append (gsm, (guint8 *) "\0", 1); - *out_len = 0; - return g_byte_array_free (gsm, FALSE); + if (out_len) + *out_len = 0; + return g_byte_array_free (g_steal_pointer (&gsm), FALSE); } + next = utf8; + c = utf8; while (next && *next) { guint8 gch = 0x3f; /* 0x3f == '?' */ @@ -498,19 +388,37 @@ mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len) /* Add the escape char */ g_byte_array_append (gsm, &gesc, 1); g_byte_array_append (gsm, &gch, 1); - } else if (utf8_to_gsm_def_char (c, next - c, &gch)) + } else if (utf8_to_gsm_def_char (c, next - c, &gch)) { + g_byte_array_append (gsm, &gch, 1); + } else if (translit) { + /* add ? */ g_byte_array_append (gsm, &gch, 1); + } else { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Couldn't convert UTF-8 char to GSM"); + return NULL; + } c = next; - i++; } - *out_len = gsm->len; - return g_byte_array_free (gsm, FALSE); + /* Output length doesn't consider terminating NUL byte */ + if (out_len) + *out_len = gsm->len; + + /* Always make sure returned string is NUL terminated */ + g_byte_array_append (gsm, (guint8 *) "\0", 1); + return g_byte_array_free (g_steal_pointer (&gsm), FALSE); } +/******************************************************************************/ +/* Checks to see whether conversion to a target charset may be done without + * any loss. */ + static gboolean -gsm_is_subset (gunichar c, const char *utf8, gsize ulen) +gsm_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { guint8 gsm; @@ -522,25 +430,41 @@ gsm_is_subset (gunichar c, const char *utf8, gsize ulen) } static gboolean -ira_is_subset (gunichar c, const char *utf8, gsize ulen) +ira_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { return (ulen == 1); } static gboolean -ucs2_is_subset (gunichar c, const char *utf8, gsize ulen) +ucs2_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { return (c <= 0xFFFF); } static gboolean -iso88591_is_subset (gunichar c, const char *utf8, gsize ulen) +utf16_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) +{ + return TRUE; +} + +static gboolean +iso88591_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { return (c <= 0xFF); } static gboolean -pccp437_is_subset (gunichar c, const char *utf8, gsize ulen) +pccp437_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { static const gunichar t[] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, @@ -571,7 +495,9 @@ pccp437_is_subset (gunichar c, const char *utf8, gsize ulen) } static gboolean -pcdn_is_subset (gunichar c, const char *utf8, gsize ulen) +pcdn_is_subset (gunichar c, + const gchar *utf8, + gsize ulen) { static const gunichar t[] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, @@ -603,33 +529,27 @@ pcdn_is_subset (gunichar c, const char *utf8, gsize ulen) typedef struct { MMModemCharset cs; - gboolean (*func) (gunichar c, const char *utf8, gsize ulen); - guint charsize; + gboolean (*func) (gunichar c, + const gchar *utf8, + gsize ulen); } SubsetEntry; -SubsetEntry subset_table[] = { - { MM_MODEM_CHARSET_GSM, gsm_is_subset }, - { MM_MODEM_CHARSET_IRA, ira_is_subset }, - { MM_MODEM_CHARSET_UCS2, ucs2_is_subset }, +const SubsetEntry subset_table[] = { + { MM_MODEM_CHARSET_GSM, gsm_is_subset }, + { MM_MODEM_CHARSET_IRA, ira_is_subset }, + { MM_MODEM_CHARSET_UCS2, ucs2_is_subset }, + { MM_MODEM_CHARSET_UTF16, utf16_is_subset }, { MM_MODEM_CHARSET_8859_1, iso88591_is_subset }, - { MM_MODEM_CHARSET_PCCP437, pccp437_is_subset }, - { MM_MODEM_CHARSET_PCDN, pcdn_is_subset }, - { MM_MODEM_CHARSET_UNKNOWN, NULL }, + { MM_MODEM_CHARSET_PCCP437, pccp437_is_subset }, + { MM_MODEM_CHARSET_PCDN, pcdn_is_subset }, }; -/** - * mm_charset_can_covert_to: - * @utf8: UTF-8 valid string. - * @charset: the #MMModemCharset to validate the conversion from @utf8. - * - * Returns: %TRUE if the conversion is possible without errors, %FALSE otherwise. - */ gboolean -mm_charset_can_convert_to (const char *utf8, - MMModemCharset charset) +mm_charset_can_convert_to (const gchar *utf8, + MMModemCharset charset) { - const char *p = utf8; - SubsetEntry *e; + const gchar *p; + guint i; g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, FALSE); g_return_val_if_fail (utf8 != NULL, FALSE); @@ -638,11 +558,13 @@ mm_charset_can_convert_to (const char *utf8, return TRUE; /* Find the charset in our subset table */ - for (e = &subset_table[0]; - e->cs != charset && e->cs != MM_MODEM_CHARSET_UNKNOWN; - e++); - g_return_val_if_fail (e->cs != MM_MODEM_CHARSET_UNKNOWN, FALSE); + for (i = 0; i < G_N_ELEMENTS (subset_table); i++) { + if (subset_table[i].cs == charset) + break; + } + g_return_val_if_fail (i < G_N_ELEMENTS (subset_table), FALSE); + p = utf8; while (*p) { gunichar c; const char *end; @@ -656,7 +578,7 @@ mm_charset_can_convert_to (const char *utf8, while (*++end); } - if (!e->func (c, p, (end - p))) + if (!subset_table[i].func (c, p, (end - p))) return FALSE; p = end; @@ -665,11 +587,14 @@ mm_charset_can_convert_to (const char *utf8, return TRUE; } +/******************************************************************************/ +/* GSM-7 pack/unpack operations */ + guint8 * mm_charset_gsm_unpack (const guint8 *gsm, - guint32 num_septets, - guint8 start_offset, /* in _bits_ */ - guint32 *out_unpacked_len) + guint32 num_septets, + guint8 start_offset, /* in _bits_ */ + guint32 *out_unpacked_len) { GByteArray *unpacked; guint i; @@ -703,9 +628,9 @@ mm_charset_gsm_unpack (const guint8 *gsm, guint8 * mm_charset_gsm_pack (const guint8 *src, - guint32 src_len, - guint8 start_offset, - guint32 *out_packed_len) + guint32 src_len, + guint8 start_offset, + guint32 *out_packed_len) { guint8 *packed; guint octet = 0, lshift, plen; @@ -737,208 +662,265 @@ mm_charset_gsm_pack (const guint8 *src, return packed; } -/* We do all our best to get the given string, which is possibly given in the - * specified charset, to UTF8. It may happen that the given string is really - * the hex representation of the charset-encoded string, so we need to cope with - * that case. */ -gchar * -mm_charset_take_and_convert_to_utf8 (gchar *str, MMModemCharset charset) +/*****************************************************************************/ +/* Main conversion functions */ + +static guint8 * +charset_iconv_from_utf8 (const gchar *utf8, + const CharsetSettings *settings, + gboolean translit, + guint *out_size, + GError **error) { - gchar *utf8 = NULL; + g_autoptr(GError) inner_error = NULL; + gsize bytes_written = 0; + g_autofree guint8 *encoded = NULL; + + encoded = (guint8 *) g_convert (utf8, -1, + settings->iconv_name, "UTF-8", + NULL, &bytes_written, &inner_error); + if (encoded) { + if (out_size) + *out_size = (guint) bytes_written; + return g_steal_pointer (&encoded); + } - if (!str) + if (!translit) { + g_propagate_error (error, g_steal_pointer (&inner_error)); + g_prefix_error (error, "Couldn't convert from UTF-8 to %s: ", settings->gsm_name); return NULL; - - switch (charset) { - case MM_MODEM_CHARSET_UNKNOWN: - g_warn_if_reached (); - utf8 = str; - break; - - case MM_MODEM_CHARSET_HEX: - /* We'll assume that the HEX string is really valid ASCII at the end */ - utf8 = str; - break; - - case MM_MODEM_CHARSET_GSM: - case MM_MODEM_CHARSET_8859_1: - case MM_MODEM_CHARSET_PCCP437: - case MM_MODEM_CHARSET_PCDN: { - const gchar *iconv_from; - GError *error = NULL; - - iconv_from = charset_iconv_from (charset); - utf8 = g_convert (str, strlen (str), - "UTF-8//TRANSLIT", iconv_from, - NULL, NULL, &error); - if (!utf8 || error) { - g_clear_error (&error); - utf8 = NULL; - } - - g_free (str); - break; } - case MM_MODEM_CHARSET_UCS2: { - gsize len; - gboolean possibly_hex = TRUE; - gsize bread = 0, bwritten = 0; + encoded = (guint8 *) g_convert_with_fallback (utf8, -1, + settings->iconv_name, "UTF-8", translit_fallback, + NULL, &bytes_written, error); + if (encoded) { + if (out_size) + *out_size = (guint) bytes_written; + return g_steal_pointer (&encoded); + } - /* If the string comes in hex-UCS-2, len needs to be a multiple of 4 */ - len = strlen (str); - if ((len < 4) || ((len % 4) != 0)) - possibly_hex = FALSE; - else { - const gchar *p = str; + g_prefix_error (error, "Couldn't convert from UTF-8 to %s with translit: ", settings->gsm_name); + return NULL; +} - /* All chars in the string must be hex */ - while (*p && possibly_hex) - possibly_hex = isxdigit (*p++); - } +GByteArray * +mm_modem_charset_bytearray_from_utf8 (const gchar *utf8, + MMModemCharset charset, + gboolean translit, + GError **error) +{ + const CharsetSettings *settings; + guint8 *encoded = NULL; + guint encoded_size = 0; - /* If hex, then we expect hex-encoded UCS-2 */ - if (possibly_hex) { - utf8 = mm_modem_charset_hex_to_utf8 (str, charset); - if (utf8) { - g_free (str); - break; - } - } + settings = lookup_charset_settings (charset); - /* If not hex, then it might be raw UCS-2 (very unlikely) or ASCII/UTF-8 - * (much more likely). Try to convert to UTF-8 and if that fails, use - * the partial conversion length to re-convert the part of the string - * that is UTF-8, if any. - */ - utf8 = g_convert (str, strlen (str), - "UTF-8//TRANSLIT", "UTF-8//TRANSLIT", - &bread, &bwritten, NULL); + if (charset == MM_MODEM_CHARSET_UNKNOWN) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Cannot convert from UTF-8: unknown target charset"); + return NULL; + } - /* Valid conversion, or we didn't get enough valid UTF-8 */ - if (utf8 || (bwritten <= 2)) { - g_free (str); + switch (charset) { + case MM_MODEM_CHARSET_GSM: + encoded = charset_utf8_to_unpacked_gsm (utf8, translit, &encoded_size, error); break; - } + case MM_MODEM_CHARSET_IRA: + case MM_MODEM_CHARSET_8859_1: + case MM_MODEM_CHARSET_UTF8: + case MM_MODEM_CHARSET_UCS2: + case MM_MODEM_CHARSET_PCCP437: + case MM_MODEM_CHARSET_PCDN: + case MM_MODEM_CHARSET_UTF16: + encoded = charset_iconv_from_utf8 (utf8, settings, translit, &encoded_size, error); + break; + case MM_MODEM_CHARSET_UNKNOWN: + default: + g_assert_not_reached (); + } - /* Last try; chop off the original string at the conversion failure - * location and get what we can. - */ - str[bread] = '\0'; - utf8 = g_convert (str, strlen (str), - "UTF-8//TRANSLIT", "UTF-8//TRANSLIT", - NULL, NULL, NULL); - g_free (str); - break; + return g_byte_array_new_take (encoded, encoded_size); +} + +gchar * +mm_modem_charset_str_from_utf8 (const gchar *utf8, + MMModemCharset charset, + gboolean translit, + GError **error) +{ + g_autoptr(GByteArray) bytearray = NULL; + + if (charset == MM_MODEM_CHARSET_UNKNOWN) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Cannot convert from UTF-8: unknown target charset"); + return NULL; } - /* If the given charset is ASCII or UTF8, we really expect the final string - * already here */ - case MM_MODEM_CHARSET_IRA: - case MM_MODEM_CHARSET_UTF8: - utf8 = str; - break; + bytearray = mm_modem_charset_bytearray_from_utf8 (utf8, charset, translit, error); + if (!bytearray) + return NULL; - default: - g_assert_not_reached (); + switch (charset) { + case MM_MODEM_CHARSET_GSM: + /* Note: strings encoded in unpacked GSM-7 can be used as plain + * strings as long as the string doesn't contain character '@', which + * is the one encoded as 0x00. At this point, we perform transliteration + * of the NUL bytes in the GSM-7 bytearray, and we fail the operation + * if one or more replacements were done and transliteration wasn't + * requested */ + if (translit_gsm_nul_byte (bytearray) && !translit) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Cannot convert to GSM-7 string: transliteration required for embedded '@'"); + return NULL; + } + /* fall through */ + case MM_MODEM_CHARSET_IRA: + case MM_MODEM_CHARSET_8859_1: + case MM_MODEM_CHARSET_UTF8: + case MM_MODEM_CHARSET_PCCP437: + case MM_MODEM_CHARSET_PCDN: + return (gchar *) g_byte_array_free (g_steal_pointer (&bytearray), FALSE); + case MM_MODEM_CHARSET_UCS2: + case MM_MODEM_CHARSET_UTF16: + return mm_utils_bin2hexstr (bytearray->data, bytearray->len); + default: + case MM_MODEM_CHARSET_UNKNOWN: + g_assert_not_reached (); } +} - /* Validate UTF-8 always before returning. This result will be exposed in DBus - * very likely... */ - if (utf8 && !g_utf8_validate (utf8, -1, NULL)) { - /* Better return NULL than an invalid UTF-8 string */ - g_free (utf8); - utf8 = NULL; +static gchar * +charset_iconv_to_utf8 (const guint8 *data, + guint32 len, + const CharsetSettings *settings, + gboolean translit, + GError **error) +{ + g_autoptr(GError) inner_error = NULL; + g_autofree gchar *utf8 = NULL; + + utf8 = g_convert ((const gchar *) data, len, + "UTF-8", + settings->iconv_name, + NULL, NULL, &inner_error); + if (utf8) + return g_steal_pointer (&utf8); + + if (!translit) { + g_propagate_error (error, g_steal_pointer (&inner_error)); + g_prefix_error (error, "Couldn't convert from %s to UTF-8: ", settings->gsm_name); + return NULL; } - return utf8; + utf8 = g_convert_with_fallback ((const gchar *) data, len, + "UTF-8", settings->iconv_name, translit_fallback, + NULL, NULL, error); + if (utf8) + return g_steal_pointer (&utf8); + + g_prefix_error (error, "Couldn't convert from %s to UTF-8 with translit: ", settings->gsm_name); + return NULL; } -/* We do all our best to convert the given string, which comes in UTF-8, to the - * specified charset. It may be that the output string needs to be the hex - * representation of the charset-encoded string, so we need to cope with that - * case. */ gchar * -mm_utf8_take_and_convert_to_charset (gchar *str, - MMModemCharset charset) +mm_modem_charset_bytearray_to_utf8 (GByteArray *bytearray, + MMModemCharset charset, + gboolean translit, + GError **error) { - gchar *encoded = NULL; - - if (!str) - return NULL; + const CharsetSettings *settings; + g_autofree gchar *utf8 = NULL; - /* Validate UTF-8 always before converting */ - if (!g_utf8_validate (str, -1, NULL)) { - /* Better return NULL than an invalid encoded string */ - g_free (str); + if (charset == MM_MODEM_CHARSET_UNKNOWN) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Cannot convert from UTF-8: unknown target charset"); return NULL; } - switch (charset) { - case MM_MODEM_CHARSET_UNKNOWN: - g_warn_if_reached (); - encoded = str; - break; - - case MM_MODEM_CHARSET_HEX: - /* FIXME: What encoding is this? */ - g_warn_if_reached (); - encoded = str; - break; - - case MM_MODEM_CHARSET_GSM: - case MM_MODEM_CHARSET_8859_1: - case MM_MODEM_CHARSET_PCCP437: - case MM_MODEM_CHARSET_PCDN: { - const gchar *iconv_to; - GError *error = NULL; - - iconv_to = charset_iconv_from (charset); - encoded = g_convert (str, strlen (str), - iconv_to, "UTF-8", - NULL, NULL, &error); - if (!encoded || error) { - g_clear_error (&error); - encoded = NULL; - } + settings = lookup_charset_settings (charset); - g_free (str); - break; + switch (charset) { + case MM_MODEM_CHARSET_GSM: + utf8 = (gchar *) charset_gsm_unpacked_to_utf8 (bytearray->data, + bytearray->len, + translit, + error); + break; + case MM_MODEM_CHARSET_IRA: + case MM_MODEM_CHARSET_UTF8: + case MM_MODEM_CHARSET_8859_1: + case MM_MODEM_CHARSET_PCCP437: + case MM_MODEM_CHARSET_PCDN: + case MM_MODEM_CHARSET_UCS2: + case MM_MODEM_CHARSET_UTF16: + utf8 = charset_iconv_to_utf8 (bytearray->data, + bytearray->len, + settings, + translit, + error); + break; + case MM_MODEM_CHARSET_UNKNOWN: + default: + g_assert_not_reached (); } - case MM_MODEM_CHARSET_UCS2: { - const gchar *iconv_to; - gsize encoded_len = 0; - GError *error = NULL; - gchar *hex; - - iconv_to = charset_iconv_from (charset); - encoded = g_convert (str, strlen (str), - iconv_to, "UTF-8", - NULL, &encoded_len, &error); - if (!encoded || error) { - g_clear_error (&error); - encoded = NULL; - } + if (utf8 && g_utf8_validate (utf8, -1, NULL)) + return g_steal_pointer (&utf8); + + g_prefix_error (error, "Invalid conversion from %s to UTF-8: ", settings->gsm_name); + return NULL; +} + +gchar * +mm_modem_charset_str_to_utf8 (const gchar *str, + gssize len, + MMModemCharset charset, + gboolean translit, + GError **error) +{ + g_autoptr(GByteArray) bytearray = NULL; - /* Get hex representation of the string */ - hex = mm_utils_bin2hexstr ((guint8 *)encoded, encoded_len); - g_free (encoded); - encoded = hex; - g_free (str); - break; + if (charset == MM_MODEM_CHARSET_UNKNOWN) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Cannot convert from UTF-8: unknown target charset"); + return NULL; } - /* If the given charset is ASCII or UTF8, we really expect the final string - * already here. */ - case MM_MODEM_CHARSET_IRA: - case MM_MODEM_CHARSET_UTF8: - encoded = str; - break; + /* Note: if the input string is GSM-7 encoded and it contains the '@' + * character, using -1 to indicate string length won't work properly, + * as '@' is encoded as 0x00. Whenever possible, if using GSM-7, + * give a proper len value or otherwise use the bytearray_to_utf8() + * method instead. */ + if (len < 0) + len = strlen (str); + + switch (charset) { + case MM_MODEM_CHARSET_GSM: + case MM_MODEM_CHARSET_IRA: + case MM_MODEM_CHARSET_8859_1: + case MM_MODEM_CHARSET_UTF8: + case MM_MODEM_CHARSET_PCCP437: + case MM_MODEM_CHARSET_PCDN: + bytearray = g_byte_array_sized_new (len); + g_byte_array_append (bytearray, (const guint8 *)str, len); + break; + case MM_MODEM_CHARSET_UCS2: + case MM_MODEM_CHARSET_UTF16: { + guint8 *bin = NULL; + gsize bin_len; + + bin = (guint8 *) mm_utils_hexstr2bin (str, len, &bin_len, error); + if (!bin) + return NULL; - default: - g_assert_not_reached (); + bytearray = g_byte_array_new_take (bin, bin_len); + break; + } + case MM_MODEM_CHARSET_UNKNOWN: + default: + g_assert_not_reached (); } - return encoded; + return mm_modem_charset_bytearray_to_utf8 (bytearray, charset, translit, error); } diff --git a/src/mm-charsets.h b/src/mm-charsets.h index 2e3e6f38..6db481cd 100644 --- a/src/mm-charsets.h +++ b/src/mm-charsets.h @@ -18,67 +18,94 @@ #include +/*****************************************************************************************/ + typedef enum { - MM_MODEM_CHARSET_UNKNOWN = 0x00000000, - MM_MODEM_CHARSET_GSM = 0x00000001, - MM_MODEM_CHARSET_IRA = 0x00000002, - MM_MODEM_CHARSET_8859_1 = 0x00000004, - MM_MODEM_CHARSET_UTF8 = 0x00000008, - MM_MODEM_CHARSET_UCS2 = 0x00000010, - MM_MODEM_CHARSET_PCCP437 = 0x00000020, - MM_MODEM_CHARSET_PCDN = 0x00000040, - MM_MODEM_CHARSET_HEX = 0x00000080 + MM_MODEM_CHARSET_UNKNOWN = 0, + MM_MODEM_CHARSET_GSM = 1 << 0, + MM_MODEM_CHARSET_IRA = 1 << 1, + MM_MODEM_CHARSET_8859_1 = 1 << 2, + MM_MODEM_CHARSET_UTF8 = 1 << 3, + MM_MODEM_CHARSET_UCS2 = 1 << 4, + MM_MODEM_CHARSET_PCCP437 = 1 << 5, + MM_MODEM_CHARSET_PCDN = 1 << 6, + MM_MODEM_CHARSET_UTF16 = 1 << 7, } MMModemCharset; -const char *mm_modem_charset_to_string (MMModemCharset charset); - -MMModemCharset mm_modem_charset_from_string (const char *string); - -/* Append the given string to the given byte array but re-encode it - * into the given charset first. The original string is assumed to be - * UTF-8 encoded. - */ -gboolean mm_modem_charset_byte_array_append (GByteArray *array, - const char *utf8, - gboolean quoted, - MMModemCharset charset); - -/* Take a string encoded in the given charset in binary form, and - * convert it to UTF-8. */ -gchar *mm_modem_charset_byte_array_to_utf8 (GByteArray *array, - MMModemCharset charset); - -/* Take a string in hex representation ("00430052" or "A4BE11" for example) - * and convert it from the given character set to UTF-8. - */ -char *mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset); - -/* Take a string in UTF-8 and convert it to the given charset in hex - * representation. - */ -char *mm_modem_charset_utf8_to_hex (const char *src, MMModemCharset charset); - -guint8 *mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len); +const gchar *mm_modem_charset_to_string (MMModemCharset charset); +MMModemCharset mm_modem_charset_from_string (const gchar *string); -guint8 *mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len); +/*****************************************************************************************/ /* Checks whether conversion to the given charset may be done without errors */ -gboolean mm_charset_can_convert_to (const char *utf8, - MMModemCharset charset); +gboolean mm_charset_can_convert_to (const gchar *utf8, + MMModemCharset charset); guint8 *mm_charset_gsm_unpack (const guint8 *gsm, - guint32 num_septets, - guint8 start_offset, /* in bits */ - guint32 *out_unpacked_len); + guint32 num_septets, + guint8 start_offset, /* in bits */ + guint32 *out_unpacked_len); guint8 *mm_charset_gsm_pack (const guint8 *src, - guint32 src_len, - guint8 start_offset, /* in bits */ - guint32 *out_packed_len); + guint32 src_len, + guint8 start_offset, /* in bits */ + guint32 *out_packed_len); + +/*****************************************************************************************/ + +/* + * Convert the given UTF-8 encoded string into the given charset. + * + * The output is given as a bytearray, because the target charset may allow + * embedded NUL bytes (e.g. UTF-16). + * + * The output encoded string is not guaranteed to be NUL-terminated, instead + * the bytearray length itself gives the correct string length. + */ +GByteArray *mm_modem_charset_bytearray_from_utf8 (const gchar *utf8, + MMModemCharset charset, + gboolean translit, + GError **error); + +/* + * Convert the given UTF-8 encoded string into the given charset. + * + * The output is given as a C string, and those charsets that allow + * embedded NUL bytes (e.g. UTF-16) will be hex-encoded. + * + * The output encoded string is guaranteed to be NUL-terminated, and so no + * explicit output length is returned. + */ +gchar *mm_modem_charset_str_from_utf8 (const gchar *utf8, + MMModemCharset charset, + gboolean translit, + GError **error); -gchar *mm_charset_take_and_convert_to_utf8 (gchar *str, MMModemCharset charset); +/* + * Convert into an UTF-8 encoded string the input byte array, which is + * encoded in the given charset. + * + * The output string is guaranteed to be valid UTF-8 and NUL-terminated. + */ +gchar *mm_modem_charset_bytearray_to_utf8 (GByteArray *bytearray, + MMModemCharset charset, + gboolean translit, + GError **error); -gchar *mm_utf8_take_and_convert_to_charset (gchar *str, - MMModemCharset charset); +/* + * Convert into an UTF-8 encoded string the input string, which is + * encoded in the given charset. Those charsets that allow embedded NUL + * bytes (e.g. UTF-16) need to be hex-encoded. + * + * If the input string is NUL-terminated, len may be given as -1; otherwise + * len needs to specify the number of valid bytes in the input string. + * + * The output string is guaranteed to be valid UTF-8 and NUL-terminated. + */ +gchar *mm_modem_charset_str_to_utf8 (const gchar *str, + gssize len, + MMModemCharset charset, + gboolean translit, + GError **error); #endif /* MM_CHARSETS_H */ diff --git a/src/mm-context.c b/src/mm-context.c index 8630be02..6561127e 100644 --- a/src/mm-context.c +++ b/src/mm-context.c @@ -38,7 +38,7 @@ static gboolean help_flag; static gboolean version_flag; static gboolean debug; -static MMFilterRule filter_policy = MM_FILTER_POLICY_DEFAULT; +static MMFilterRule filter_policy = MM_FILTER_POLICY_STRICT; static gboolean no_auto_scan = NO_AUTO_SCAN_DEFAULT; static const gchar *initial_kernel_events; @@ -48,8 +48,8 @@ filter_policy_option_arg (const gchar *option_name, gpointer data, GError **error) { - if (!g_ascii_strcasecmp (value, "default")) { - filter_policy = MM_FILTER_POLICY_DEFAULT; + if (!g_ascii_strcasecmp (value, "legacy")) { + filter_policy = MM_FILTER_POLICY_LEGACY; return TRUE; } @@ -77,7 +77,7 @@ filter_policy_option_arg (const gchar *option_name, static const GOptionEntry entries[] = { { "filter-policy", 0, 0, G_OPTION_ARG_CALLBACK, filter_policy_option_arg, - "Filter policy: one of DEFAULT, WHITELIST-ONLY, STRICT, PARANOID", + "Filter policy: one of LEGACY, WHITELIST-ONLY, STRICT, PARANOID", "[POLICY]" }, { @@ -178,7 +178,7 @@ log_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("log", - "Logging options", + "Logging options:", "Show logging options", NULL, NULL); @@ -222,6 +222,12 @@ mm_context_get_log_relative_timestamps (void) static gboolean test_session; static gboolean test_enable; static gchar *test_plugin_dir; +#if defined WITH_UDEV +static gboolean test_no_udev; +#endif +#if defined WITH_SYSTEMD_SUSPEND_RESUME +static gboolean test_no_suspend_resume; +#endif static const GOptionEntry test_entries[] = { { @@ -239,6 +245,20 @@ static const GOptionEntry test_entries[] = { "Path to look for plugins", "[PATH]" }, +#if defined WITH_UDEV + { + "test-no-udev", 0, 0, G_OPTION_ARG_NONE, &test_no_udev, + "Run without udev support even if available", + NULL + }, +#endif +#if defined WITH_SYSTEMD_SUSPEND_RESUME + { + "test-no-suspend-resume", 0, 0, G_OPTION_ARG_NONE, &test_no_suspend_resume, + "Disable suspend/resume support at runtime even if available", + NULL + }, +#endif { NULL } }; @@ -248,7 +268,7 @@ test_get_option_group (void) GOptionGroup *group; group = g_option_group_new ("test", - "Test options", + "Test options:", "Show Test options", NULL, NULL); @@ -274,14 +294,29 @@ mm_context_get_test_plugin_dir (void) return test_plugin_dir ? test_plugin_dir : PLUGINDIR; } +#if defined WITH_UDEV +gboolean +mm_context_get_test_no_udev (void) +{ + return test_no_udev; +} +#endif + +#if defined WITH_SYSTEMD_SUSPEND_RESUME +gboolean +mm_context_get_test_no_suspend_resume (void) +{ + return test_no_suspend_resume; +} +#endif + /*****************************************************************************/ static void print_version (void) { - g_print ("\n" - "ModemManager " MM_DIST_VERSION "\n" - "Copyright (C) 2008-2020 The ModemManager authors\n" + g_print ("ModemManager " MM_DIST_VERSION "\n" + "Copyright (C) 2008-2021 The ModemManager authors\n" "License GPLv2+: GNU GPL version 2 or later \n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" @@ -346,5 +381,8 @@ mm_context_init (gint argc, g_warning ("error: --initial-kernel-events must be used only if --no-auto-scan is also used"); exit (1); } + /* Force skipping autoscan if running test without udev */ + if (test_no_udev) + no_auto_scan = TRUE; #endif } diff --git a/src/mm-context.h b/src/mm-context.h index ff5f1343..721fee88 100644 --- a/src/mm-context.h +++ b/src/mm-context.h @@ -43,8 +43,14 @@ gboolean mm_context_get_log_timestamps (void); gboolean mm_context_get_log_relative_timestamps (void); /* Testing support */ -gboolean mm_context_get_test_session (void); -gboolean mm_context_get_test_enable (void); -const gchar *mm_context_get_test_plugin_dir (void); +gboolean mm_context_get_test_session (void); +gboolean mm_context_get_test_enable (void); +const gchar *mm_context_get_test_plugin_dir (void); +#if defined WITH_UDEV +gboolean mm_context_get_test_no_udev (void); +#endif +#if defined WITH_SYSTEMD_SUSPEND_RESUME +gboolean mm_context_get_test_no_suspend_resume (void); +#endif #endif /* MM_CONTEXT_H */ diff --git a/src/mm-device.c b/src/mm-device.c index 86baf7c7..d0e31184 100644 --- a/src/mm-device.c +++ b/src/mm-device.c @@ -25,9 +25,12 @@ #include "mm-device.h" #include "mm-plugin.h" -#include "mm-log.h" +#include "mm-log-object.h" -G_DEFINE_TYPE (MMDevice, mm_device, G_TYPE_OBJECT) +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMDevice, mm_device, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -94,32 +97,56 @@ struct _MMDevicePrivate { /*****************************************************************************/ static MMPortProbe * -device_find_probe_with_device (MMDevice *self, - MMKernelDevice *kernel_port, - gboolean lookup_ignored) +probe_list_lookup_by_device (GList *port_probes, + MMKernelDevice *kernel_port) { GList *l; - for (l = self->priv->port_probes; l; l = g_list_next (l)) { + for (l = port_probes; l; l = g_list_next (l)) { MMPortProbe *probe = MM_PORT_PROBE (l->data); if (mm_kernel_device_cmp (mm_port_probe_peek_port (probe), kernel_port)) return probe; } + return NULL; +} - if (!lookup_ignored) - return NULL; +static MMPortProbe * +probe_list_lookup_by_name (GList *port_probes, + const gchar *subsystem, + const gchar *name) +{ + GList *l; - for (l = self->priv->ignored_port_probes; l; l = g_list_next (l)) { - MMPortProbe *probe = MM_PORT_PROBE (l->data); + for (l = port_probes; l; l = g_list_next (l)) { + MMPortProbe *probe = MM_PORT_PROBE (l->data); + MMKernelDevice *probe_device; - if (mm_kernel_device_cmp (mm_port_probe_peek_port (probe), kernel_port)) + probe_device = mm_port_probe_peek_port (probe); + if ((g_strcmp0 (subsystem, mm_kernel_device_get_subsystem (probe_device)) == 0) && + (g_strcmp0 (name, mm_kernel_device_get_name (probe_device)) == 0)) return probe; } - return NULL; } +static MMPortProbe * +device_find_probe_with_device (MMDevice *self, + MMKernelDevice *kernel_port, + gboolean lookup_ignored) +{ + MMPortProbe *probe; + + probe = probe_list_lookup_by_device (self->priv->port_probes, kernel_port); + if (probe) + return probe; + + if (!lookup_ignored) + return NULL; + + return probe_list_lookup_by_device (self->priv->ignored_port_probes, kernel_port); +} + gboolean mm_device_owns_port (MMDevice *self, MMKernelDevice *kernel_port) @@ -127,6 +154,28 @@ mm_device_owns_port (MMDevice *self, return !!device_find_probe_with_device (self, kernel_port, TRUE); } +static MMPortProbe * +device_find_probe_with_name (MMDevice *self, + const gchar *subsystem, + const gchar *name) +{ + MMPortProbe *probe; + + probe = probe_list_lookup_by_name (self->priv->port_probes, subsystem, name); + if (probe) + return probe; + + return probe_list_lookup_by_name (self->priv->ignored_port_probes, subsystem, name); +} + +gboolean +mm_device_owns_port_name (MMDevice *self, + const gchar *subsystem, + const gchar *name) +{ + return !!device_find_probe_with_name (self, subsystem, name); +} + static void add_port_driver (MMDevice *self, MMKernelDevice *kernel_port) @@ -187,12 +236,13 @@ mm_device_grab_port (MMDevice *self, } void -mm_device_release_port (MMDevice *self, - MMKernelDevice *kernel_port) +mm_device_release_port_name (MMDevice *self, + const gchar *subsystem, + const gchar *name) { MMPortProbe *probe; - probe = device_find_probe_with_device (self, kernel_port, TRUE); + probe = device_find_probe_with_name (self, subsystem, name); if (probe) { /* Found, remove from lists and destroy probe */ if (g_list_find (self->priv->port_probes, probe)) @@ -215,10 +265,8 @@ mm_device_ignore_port (MMDevice *self, probe = device_find_probe_with_device (self, kernel_port, FALSE); if (probe) { /* Found, remove from list and add to the ignored list */ - mm_dbg ("[device %s] fully ignoring port '%s/%s' from now on", - self->priv->uid, - mm_kernel_device_get_subsystem (kernel_port), - mm_kernel_device_get_name (kernel_port)); + mm_obj_dbg (self, "fully ignoring port %s from now on", + mm_kernel_device_get_name (kernel_port)); self->priv->port_probes = g_list_remove (self->priv->port_probes, probe); self->priv->ignored_port_probes = g_list_prepend (self->priv->ignored_port_probes, probe); } @@ -240,7 +288,7 @@ unexport_modem (MMDevice *self) g_object_set (self->priv->modem, MM_BASE_MODEM_CONNECTION, NULL, NULL); - mm_dbg ("[device %s] unexported modem from path '%s'", self->priv->uid, path); + mm_obj_dbg (self, "unexported modem from path '%s'", path); g_free (path); } } @@ -251,15 +299,14 @@ static void export_modem (MMDevice *self) { GDBusConnection *connection = NULL; - static guint32 id = 0; - gchar *path; + gchar *path; g_assert (MM_IS_BASE_MODEM (self->priv->modem)); g_assert (G_IS_DBUS_OBJECT_MANAGER (self->priv->object_manager)); /* If modem not yet valid (not fully initialized), don't export it */ if (!mm_base_modem_get_valid (self->priv->modem)) { - mm_dbg ("[device %s] modem not yet fully initialized", self->priv->uid); + mm_obj_dbg (self, "modem not yet fully initialized"); return; } @@ -269,13 +316,13 @@ export_modem (MMDevice *self) NULL); if (path) { g_free (path); - mm_dbg ("[device %s] modem already exported", self->priv->uid); + mm_obj_dbg (self, "modem already exported"); return; } /* No outstanding port tasks, so if the modem is valid we can export it */ - path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", id++); + path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", mm_base_modem_get_dbus_id (self->priv->modem)); g_object_get (self->priv->object_manager, "connection", &connection, NULL); @@ -288,14 +335,13 @@ export_modem (MMDevice *self) g_dbus_object_manager_server_export (self->priv->object_manager, G_DBUS_OBJECT_SKELETON (self->priv->modem)); - mm_dbg ("[device %s] exported modem at path '%s'", self->priv->uid, path); - mm_dbg ("[device %s] plugin: %s", self->priv->uid, mm_base_modem_get_plugin (self->priv->modem)); - mm_dbg ("[device %s] vid:pid: 0x%04X:0x%04X", - self->priv->uid, - (mm_base_modem_get_vendor_id (self->priv->modem) & 0xFFFF), - (mm_base_modem_get_product_id (self->priv->modem) & 0xFFFF)); + mm_obj_dbg (self, " exported modem at path '%s'", path); + mm_obj_dbg (self, " plugin: %s", mm_base_modem_get_plugin (self->priv->modem)); + mm_obj_dbg (self, " vid:pid: 0x%04X:0x%04X", + (mm_base_modem_get_vendor_id (self->priv->modem) & 0xFFFF), + (mm_base_modem_get_product_id (self->priv->modem) & 0xFFFF)); if (self->priv->virtual) - mm_dbg ("[device %s] virtual", self->priv->uid); + mm_obj_dbg (self, " virtual"); g_free (path); } @@ -337,13 +383,14 @@ reprobe (MMDevice *self) { GError *error = NULL; + self->priv->reprobe_id = 0; + + mm_obj_dbg (self, "Reprobing modem..."); if (!mm_device_create_modem (self, &error)) { - mm_warn ("Could not recreate modem for device '%s': %s", - self->priv->uid, - error ? error->message : "unknown"); + mm_obj_warn (self, "could not recreate modem: %s", error->message); g_error_free (error); } else - mm_dbg ("Modem recreated for device '%s'", self->priv->uid); + mm_obj_dbg (self, "modem recreated"); return G_SOURCE_REMOVE; } @@ -366,7 +413,7 @@ modem_valid (MMBaseModem *modem, if (self->priv->modem) export_modem (self); else - mm_dbg ("[device %s] not exporting modem; no longer available", self->priv->uid); + mm_obj_dbg (self, "not exporting modem; no longer available"); } } @@ -391,10 +438,9 @@ mm_device_create_modem (MMDevice *self, return FALSE; } - mm_info ("[device %s] creating modem with plugin '%s' and '%u' ports", - self->priv->uid, - mm_plugin_get_name (self->priv->plugin), - g_list_length (self->priv->port_probes)); + mm_obj_info (self, "creating modem with plugin '%s' and '%u' ports", + mm_plugin_get_name (self->priv->plugin), + g_list_length (self->priv->port_probes)); } else { if (!self->priv->virtual_ports) { g_set_error (error, @@ -404,10 +450,9 @@ mm_device_create_modem (MMDevice *self, return FALSE; } - mm_info ("[device %s] creating virtual modem with plugin '%s' and '%u' ports", - self->priv->uid, - mm_plugin_get_name (self->priv->plugin), - g_strv_length (self->priv->virtual_ports)); + mm_obj_info (self, "creating virtual modem with plugin '%s' and '%u' ports", + mm_plugin_get_name (self->priv->plugin), + g_strv_length (self->priv->virtual_ports)); } self->priv->modem = mm_plugin_create_modem (self->priv->plugin, self, error); @@ -640,6 +685,17 @@ mm_device_is_virtual (MMDevice *self) /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + MMDevice *self; + + self = MM_DEVICE (_self); + return g_strdup_printf ("device %s", self->priv->uid); +} + +/*****************************************************************************/ + MMDevice * mm_device_new (const gchar *uid, gboolean hotplugged, @@ -772,6 +828,12 @@ finalize (GObject *object) G_OBJECT_CLASS (mm_device_parent_class)->finalize (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_device_class_init (MMDeviceClass *klass) { diff --git a/src/mm-device.h b/src/mm-device.h index b7a3285c..00d5977a 100644 --- a/src/mm-device.h +++ b/src/mm-device.h @@ -60,20 +60,26 @@ struct _MMDeviceClass { }; GType mm_device_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMDevice, g_object_unref) MMDevice *mm_device_new (const gchar *uid, gboolean hotplugged, gboolean virtual, GDBusObjectManagerServer *object_manager); -void mm_device_grab_port (MMDevice *self, - MMKernelDevice *kernel_port); -void mm_device_release_port (MMDevice *self, - MMKernelDevice *kernel_port); -gboolean mm_device_owns_port (MMDevice *self, - MMKernelDevice *kernel_port); -void mm_device_ignore_port (MMDevice *self, - MMKernelDevice *kernel_port); +void mm_device_grab_port (MMDevice *self, + MMKernelDevice *kernel_port); +gboolean mm_device_owns_port (MMDevice *self, + MMKernelDevice *kernel_port); +void mm_device_ignore_port (MMDevice *self, + MMKernelDevice *kernel_port); + +gboolean mm_device_owns_port_name (MMDevice *self, + const gchar *subsystem, + const gchar *name); +void mm_device_release_port_name (MMDevice *self, + const gchar *subsystem, + const gchar *name); gboolean mm_device_create_modem (MMDevice *self, GError **error); diff --git a/src/mm-error-helpers.c b/src/mm-error-helpers.c index 7ce32113..57486d8b 100644 --- a/src/mm-error-helpers.c +++ b/src/mm-error-helpers.c @@ -29,7 +29,8 @@ typedef struct { /* --- Connection errors --- */ GError * -mm_connection_error_for_code (MMConnectionError code) +mm_connection_error_for_code (MMConnectionError code, + gpointer log_object) { const gchar *msg; @@ -51,7 +52,7 @@ mm_connection_error_for_code (MMConnectionError code) break; default: - mm_dbg ("Invalid connection error code: %u", code); + mm_obj_dbg (log_object, "invalid connection error code: %u", code); /* uhm... make something up (yes, ok, lie!). */ code = MM_CONNECTION_ERROR_NO_CARRIER; msg = "No carrier"; @@ -149,7 +150,8 @@ static ErrorTable me_errors[] = { }; GError * -mm_mobile_equipment_error_for_code (MMMobileEquipmentError code) +mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, + gpointer log_object) { guint i; @@ -162,14 +164,15 @@ mm_mobile_equipment_error_for_code (MMMobileEquipmentError code) } /* Not found? Then, default */ - mm_dbg ("Invalid mobile equipment error code: %u", (guint)code); + mm_obj_dbg (log_object, "invalid mobile equipment error code: %u", (guint)code); return g_error_new (MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, "Unknown error"); } GError * -mm_mobile_equipment_error_for_string (const gchar *str) +mm_mobile_equipment_error_for_string (const gchar *str, + gpointer log_object) { MMMobileEquipmentError code = MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN; const gchar *msg = NULL; @@ -198,7 +201,7 @@ mm_mobile_equipment_error_for_string (const gchar *str) /* Not found? Then, default */ if (!msg) { - mm_dbg ("Invalid mobile equipment error string: '%s' (%s)", str, buf); + mm_obj_dbg (log_object, "invalid mobile equipment error string: '%s' (%s)", str, buf); code = MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN; msg = "Unknown error"; } @@ -236,7 +239,8 @@ static ErrorTable msg_errors[] = { }; GError * -mm_message_error_for_code (MMMessageError code) +mm_message_error_for_code (MMMessageError code, + gpointer log_object) { guint i; @@ -249,14 +253,15 @@ mm_message_error_for_code (MMMessageError code) } /* Not found? Then, default */ - mm_dbg ("Invalid message error code: %u", (guint)code); + mm_obj_dbg (log_object, "invalid message error code: %u", (guint)code); return g_error_new (MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_UNKNOWN, "Unknown error"); } GError * -mm_message_error_for_string (const gchar *str) +mm_message_error_for_string (const gchar *str, + gpointer log_object) { MMMessageError code = MM_MESSAGE_ERROR_UNKNOWN; const gchar *msg = NULL; @@ -285,7 +290,7 @@ mm_message_error_for_string (const gchar *str) /* Not found? Then, default */ if (!msg) { - mm_dbg ("Invalid message error string: '%s' (%s)", str, buf); + mm_obj_dbg (log_object, "invalid message error string: '%s' (%s)", str, buf); code = MM_MESSAGE_ERROR_UNKNOWN; msg = "Unknown error"; } diff --git a/src/mm-error-helpers.h b/src/mm-error-helpers.h index 379afb24..e99d1662 100644 --- a/src/mm-error-helpers.h +++ b/src/mm-error-helpers.h @@ -23,10 +23,10 @@ #include #include -GError *mm_connection_error_for_code (MMConnectionError code); -GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code); -GError *mm_mobile_equipment_error_for_string (const gchar *str); -GError *mm_message_error_for_code (MMMessageError code); -GError *mm_message_error_for_string (const gchar *str); +GError *mm_connection_error_for_code (MMConnectionError code, gpointer log_object); +GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object); +GError *mm_mobile_equipment_error_for_string (const gchar *str, gpointer log_object); +GError *mm_message_error_for_code (MMMessageError code, gpointer log_object); +GError *mm_message_error_for_string (const gchar *str, gpointer log_object); #endif /* MM_ERROR_HELPERS_H */ diff --git a/src/mm-filter.c b/src/mm-filter.c index 53c18cd2..b82d1264 100644 --- a/src/mm-filter.c +++ b/src/mm-filter.c @@ -21,11 +21,14 @@ #include "mm-daemon-enums-types.h" #include "mm-filter.h" -#include "mm-log.h" +#include "mm-log-object.h" #define FILTER_PORT_MAYBE_FORBIDDEN "maybe-forbidden" -G_DEFINE_TYPE (MMFilter, mm_filter, G_TYPE_OBJECT) +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMFilter, mm_filter, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -36,6 +39,7 @@ enum { struct _MMFilterPrivate { MMFilterRule enabled_rules; GList *plugin_whitelist_tags; + GArray *plugin_whitelist_vendor_ids; GArray *plugin_whitelist_product_ids; }; @@ -46,11 +50,32 @@ mm_filter_register_plugin_whitelist_tag (MMFilter *self, const gchar *tag) { if (!g_list_find_custom (self->priv->plugin_whitelist_tags, tag, (GCompareFunc) g_strcmp0)) { - mm_dbg ("[filter] registered plugin whitelist tag: %s", tag); + mm_obj_dbg (self, "registered plugin whitelist tag: %s", tag); self->priv->plugin_whitelist_tags = g_list_prepend (self->priv->plugin_whitelist_tags, g_strdup (tag)); } } +void +mm_filter_register_plugin_whitelist_vendor_id (MMFilter *self, + guint16 vid) +{ + guint i; + + if (!self->priv->plugin_whitelist_vendor_ids) + self->priv->plugin_whitelist_vendor_ids = g_array_sized_new (FALSE, FALSE, sizeof (guint16), 64); + + for (i = 0; i < self->priv->plugin_whitelist_vendor_ids->len; i++) { + guint16 item; + + item = g_array_index (self->priv->plugin_whitelist_vendor_ids, guint16, i); + if (item == vid) + return; + } + + g_array_append_val (self->priv->plugin_whitelist_vendor_ids, vid); + mm_obj_dbg (self, "registered plugin whitelist vendor id: %04x", vid); +} + void mm_filter_register_plugin_whitelist_product_id (MMFilter *self, guint16 vid, @@ -73,7 +98,7 @@ mm_filter_register_plugin_whitelist_product_id (MMFilter *self, new_item.l = vid; new_item.r = pid; g_array_append_val (self->priv->plugin_whitelist_product_ids, new_item); - mm_dbg ("[filter] registered plugin whitelist product id: %04x:%04x", vid, pid); + mm_obj_dbg (self, "registered plugin whitelist product id: %04x:%04x", vid, pid); } /*****************************************************************************/ @@ -95,14 +120,14 @@ mm_filter_port (MMFilter *self, if ((self->priv->enabled_rules & MM_FILTER_RULE_EXPLICIT_WHITELIST) && (mm_kernel_device_get_global_property_as_boolean (port, ID_MM_DEVICE_PROCESS) || mm_kernel_device_get_property_as_boolean (port, ID_MM_DEVICE_PROCESS))) { - mm_dbg ("[filter] (%s/%s) port allowed: device is whitelisted", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port allowed: device is whitelisted", subsystem, name); return TRUE; } /* If the device is explicitly blacklisted, we ignore every port. */ if ((self->priv->enabled_rules & MM_FILTER_RULE_EXPLICIT_BLACKLIST) && (mm_kernel_device_get_global_property_as_boolean (port, ID_MM_DEVICE_IGNORE))) { - mm_dbg ("[filter] (%s/%s): port filtered: device is blacklisted", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port filtered: device is blacklisted", subsystem, name); return FALSE; } @@ -115,7 +140,7 @@ mm_filter_port (MMFilter *self, for (l = self->priv->plugin_whitelist_tags; l; l = g_list_next (l)) { if (mm_kernel_device_get_global_property_as_boolean (port, (const gchar *)(l->data)) || mm_kernel_device_get_property_as_boolean (port, (const gchar *)(l->data))) { - mm_dbg ("[filter] (%s/%s) port allowed: device is whitelisted by plugin (tag)", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port allowed: device is whitelisted by plugin (tag)", subsystem, name); return TRUE; } } @@ -132,7 +157,21 @@ mm_filter_port (MMFilter *self, item = &g_array_index (self->priv->plugin_whitelist_product_ids, mm_uint16_pair, i); if (item->l == vid && item->r == pid) { - mm_dbg ("[filter] (%s/%s) port allowed: device is whitelisted by plugin (vid/pid)", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port allowed: device is whitelisted by plugin (vid/pid)", subsystem, name); + return TRUE; + } + } + } + + if (vid && self->priv->plugin_whitelist_vendor_ids) { + guint i; + + for (i = 0; i < self->priv->plugin_whitelist_vendor_ids->len; i++) { + guint16 item; + + item = g_array_index (self->priv->plugin_whitelist_vendor_ids, guint16, i); + if (item == vid) { + mm_obj_dbg (self, "(%s/%s) port allowed: device is whitelisted by plugin (vid)", subsystem, name); return TRUE; } } @@ -142,22 +181,35 @@ mm_filter_port (MMFilter *self, /* If this is a virtual device, don't allow it */ if ((self->priv->enabled_rules & MM_FILTER_RULE_VIRTUAL) && (!mm_kernel_device_get_physdev_sysfs_path (port))) { - mm_dbg ("[filter] (%s/%s) port filtered: virtual device", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port filtered: virtual device", subsystem, name); return FALSE; } /* If this is a net device, we always allow it */ if ((self->priv->enabled_rules & MM_FILTER_RULE_NET) && (g_strcmp0 (subsystem, "net") == 0)) { - mm_dbg ("[filter] (%s/%s) port allowed: net device", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port allowed: net device", subsystem, name); return TRUE; } /* If this is a cdc-wdm device, we always allow it */ - if ((self->priv->enabled_rules & MM_FILTER_RULE_CDC_WDM) && - (g_strcmp0 (subsystem, "usb") == 0 || g_strcmp0 (subsystem, "usbmisc") == 0) && - (name && g_str_has_prefix (name, "cdc-wdm"))) { - mm_dbg ("[filter] (%s/%s) port allowed: cdc-wdm device", subsystem, name); + if ((self->priv->enabled_rules & MM_FILTER_RULE_USBMISC) && + (g_strcmp0 (subsystem, "usbmisc") == 0)) { + mm_obj_dbg (self, "(%s/%s) port allowed: usbmisc device", subsystem, name); + return TRUE; + } + + /* If this is a rpmsg channel device, we always allow it */ + if ((self->priv->enabled_rules & MM_FILTER_RULE_RPMSG) && + (g_strcmp0 (subsystem, "rpmsg") == 0)) { + mm_obj_dbg (self, "(%s/%s) port allowed: rpmsg device", subsystem, name); + return TRUE; + } + + /* If this is a wwan port/device, we always allow it */ + if ((self->priv->enabled_rules & MM_FILTER_RULE_WWAN) && + (g_strcmp0 (subsystem, "wwan") == 0)) { + mm_obj_dbg (self, "(%s/%s) port allowed: wwan device", subsystem, name); return TRUE; } @@ -172,7 +224,7 @@ mm_filter_port (MMFilter *self, /* Ignore blacklisted tty devices. */ if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_BLACKLIST) && (mm_kernel_device_get_global_property_as_boolean (port, ID_MM_TTY_BLACKLIST))) { - mm_dbg ("[filter] (%s/%s): port filtered: tty is blacklisted", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port filtered: tty is blacklisted", subsystem, name); return FALSE; } @@ -180,7 +232,7 @@ mm_filter_port (MMFilter *self, * automatic scan. */ if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY) && (!manual_scan && mm_kernel_device_get_global_property_as_boolean (port, ID_MM_TTY_MANUAL_SCAN_ONLY))) { - mm_dbg ("[filter] (%s/%s): port filtered: tty probed only in manual scan", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port filtered: tty probed only in manual scan", subsystem, name); return FALSE; } @@ -190,7 +242,7 @@ mm_filter_port (MMFilter *self, physdev_subsystem = mm_kernel_device_get_physdev_subsystem (port); /* Special rule for XMM7360 main tty port which would be filtered out by the platform driver otherwise */ if (!g_strcmp0 (physdev_subsystem, "pci") && !g_strcmp0 (name, "ttyXMM1")) { - mm_dbg ("[filter] (%s/%s): XMM7360 TTY command port allowed", subsystem, name); + mm_obj_dbg (self, "(%s/%s): XMM7360 TTY command port allowed", subsystem, name); return TRUE; } if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_PLATFORM_DRIVER) && @@ -198,13 +250,13 @@ mm_filter_port (MMFilter *self, !g_strcmp0 (physdev_subsystem, "pci") || !g_strcmp0 (physdev_subsystem, "pnp") || !g_strcmp0 (physdev_subsystem, "sdio"))) { - mm_dbg ("[filter] (%s/%s): port filtered: tty platform driver", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port filtered: tty platform driver", subsystem, name); return FALSE; } /* Default allowed? */ if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_ALLOWED) { - mm_dbg ("[filter] (%s/%s) port allowed", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port allowed", subsystem, name); return TRUE; } @@ -218,7 +270,7 @@ mm_filter_port (MMFilter *self, !g_strcmp0 (driver, "qcaux") || !g_strcmp0 (driver, "nozomi") || !g_strcmp0 (driver, "sierra"))) { - mm_dbg ("[filter] (%s/%s): port allowed: modem-specific kernel driver detected", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port allowed: modem-specific kernel driver detected", subsystem, name); return TRUE; } @@ -251,7 +303,7 @@ mm_filter_port (MMFilter *self, (mm_kernel_device_get_interface_subclass (port) != 2) || (mm_kernel_device_get_interface_protocol (port) < 1) || (mm_kernel_device_get_interface_protocol (port) > 6))) { - mm_dbg ("[filter] (%s/%s): port filtered: cdc-acm interface is not AT-capable", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port filtered: cdc-acm interface is not AT-capable", subsystem, name); return FALSE; } @@ -265,7 +317,7 @@ mm_filter_port (MMFilter *self, } /* Otherwise forbidden */ - mm_dbg ("[filter] (%s/%s) port filtered: forbidden port type", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port filtered: forbidden port type", subsystem, name); return FALSE; } @@ -308,7 +360,7 @@ mm_filter_device_and_port (MMFilter *self, /* Check whether this device holds a NET port in addition to this TTY */ if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_WITH_NET) && device_has_net_port (device)) { - mm_dbg ("[filter] (%s/%s): port allowed: device also exports a net interface", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port allowed: device also exports a net interface", subsystem, name); return TRUE; } @@ -317,11 +369,11 @@ mm_filter_device_and_port (MMFilter *self, if ((self->priv->enabled_rules & MM_FILTER_RULE_TTY_ACM_INTERFACE) && (!g_strcmp0 (driver, "cdc_acm")) && device_has_multiple_ports (device)) { - mm_dbg ("[filter] (%s/%s): port allowed: device exports multiple interfaces", subsystem, name); + mm_obj_dbg (self, "(%s/%s): port allowed: device exports multiple interfaces", subsystem, name); return TRUE; } - mm_dbg ("[filter] (%s/%s) port filtered: forbidden", subsystem, name); + mm_obj_dbg (self, "(%s/%s) port filtered: forbidden", subsystem, name); return FALSE; } @@ -373,6 +425,14 @@ mm_filter_check_rule_enabled (MMFilter *self, /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + return g_strdup ("filter"); +} + +/*****************************************************************************/ + /* If TTY rule enabled, either DEFAULT_ALLOWED or DEFAULT_FORBIDDEN must be set. */ #define VALIDATE_RULE_TTY(rules) (!(rules & MM_FILTER_RULE_TTY) || \ ((rules & (MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN)) && \ @@ -401,29 +461,31 @@ mm_filter_new (MMFilterRule enabled_rules, #define RULE_ENABLED_STR(flag) ((self->priv->enabled_rules & flag) ? "yes" : "no") - mm_dbg ("[filter] created"); - mm_dbg ("[filter] explicit whitelist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_EXPLICIT_WHITELIST)); - mm_dbg ("[filter] explicit blacklist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_EXPLICIT_BLACKLIST)); - mm_dbg ("[filter] plugin whitelist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_PLUGIN_WHITELIST)); - mm_dbg ("[filter] virtual devices forbidden: %s", RULE_ENABLED_STR (MM_FILTER_RULE_VIRTUAL)); - mm_dbg ("[filter] net devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_NET)); - mm_dbg ("[filter] cdc-wdm devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_CDC_WDM)); + mm_obj_dbg (self, "created"); + mm_obj_dbg (self, " explicit whitelist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_EXPLICIT_WHITELIST)); + mm_obj_dbg (self, " explicit blacklist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_EXPLICIT_BLACKLIST)); + mm_obj_dbg (self, " plugin whitelist: %s", RULE_ENABLED_STR (MM_FILTER_RULE_PLUGIN_WHITELIST)); + mm_obj_dbg (self, " virtual devices forbidden: %s", RULE_ENABLED_STR (MM_FILTER_RULE_VIRTUAL)); + mm_obj_dbg (self, " net devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_NET)); + mm_obj_dbg (self, " usbmisc devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_USBMISC)); + mm_obj_dbg (self, " rpmsg devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_RPMSG)); + mm_obj_dbg (self, " wwan devices allowed: %s", RULE_ENABLED_STR (MM_FILTER_RULE_WWAN)); if (self->priv->enabled_rules & MM_FILTER_RULE_TTY) { - mm_dbg ("[filter] tty devices:"); - mm_dbg ("[filter] blacklist applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_BLACKLIST)); - mm_dbg ("[filter] manual scan only applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY)); - mm_dbg ("[filter] platform driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_PLATFORM_DRIVER)); - mm_dbg ("[filter] driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_DRIVER)); - mm_dbg ("[filter] cdc-acm interface check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_ACM_INTERFACE)); - mm_dbg ("[filter] with net check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_WITH_NET)); + mm_obj_dbg (self, " tty devices:"); + mm_obj_dbg (self, " blacklist applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_BLACKLIST)); + mm_obj_dbg (self, " manual scan only applied: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY)); + mm_obj_dbg (self, " platform driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_PLATFORM_DRIVER)); + mm_obj_dbg (self, " driver check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_DRIVER)); + mm_obj_dbg (self, " cdc-acm interface check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_ACM_INTERFACE)); + mm_obj_dbg (self, " with net check: %s", RULE_ENABLED_STR (MM_FILTER_RULE_TTY_WITH_NET)); if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_ALLOWED) - mm_dbg ("[filter] default: allowed"); + mm_obj_dbg (self, " default: allowed"); else if (self->priv->enabled_rules & MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN) - mm_dbg ("[filter] default: forbidden"); + mm_obj_dbg (self, " default: forbidden"); else g_assert_not_reached (); } else - mm_dbg ("[filter] tty devices: no"); + mm_obj_dbg (self, " tty devices: no"); #undef RULE_ENABLED_STR @@ -477,12 +539,19 @@ finalize (GObject *object) { MMFilter *self = MM_FILTER (object); + g_clear_pointer (&self->priv->plugin_whitelist_vendor_ids, g_array_unref); g_clear_pointer (&self->priv->plugin_whitelist_product_ids, g_array_unref); g_list_free_full (self->priv->plugin_whitelist_tags, g_free); G_OBJECT_CLASS (mm_filter_parent_class)->finalize (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_filter_class_init (MMFilterClass *klass) { diff --git a/src/mm-filter.h b/src/mm-filter.h index 0fc4ade9..145f8296 100644 --- a/src/mm-filter.h +++ b/src/mm-filter.h @@ -43,6 +43,7 @@ typedef struct { } MMFilterClass; GType mm_filter_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMFilter, g_object_unref) typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_NONE = 0, @@ -51,16 +52,18 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_PLUGIN_WHITELIST = 1 << 2, MM_FILTER_RULE_VIRTUAL = 1 << 3, MM_FILTER_RULE_NET = 1 << 4, - MM_FILTER_RULE_CDC_WDM = 1 << 5, - MM_FILTER_RULE_TTY = 1 << 6, - MM_FILTER_RULE_TTY_BLACKLIST = 1 << 7, - MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY = 1 << 8, - MM_FILTER_RULE_TTY_PLATFORM_DRIVER = 1 << 9, - MM_FILTER_RULE_TTY_DEFAULT_ALLOWED = 1 << 10, - MM_FILTER_RULE_TTY_DRIVER = 1 << 11, - MM_FILTER_RULE_TTY_ACM_INTERFACE = 1 << 12, - MM_FILTER_RULE_TTY_WITH_NET = 1 << 13, - MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN = 1 << 14, + MM_FILTER_RULE_USBMISC = 1 << 5, + MM_FILTER_RULE_RPMSG = 1 << 6, + MM_FILTER_RULE_TTY = 1 << 7, + MM_FILTER_RULE_TTY_BLACKLIST = 1 << 8, + MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY = 1 << 9, + MM_FILTER_RULE_TTY_PLATFORM_DRIVER = 1 << 10, + MM_FILTER_RULE_TTY_DEFAULT_ALLOWED = 1 << 11, + MM_FILTER_RULE_TTY_DRIVER = 1 << 12, + MM_FILTER_RULE_TTY_ACM_INTERFACE = 1 << 13, + MM_FILTER_RULE_TTY_WITH_NET = 1 << 14, + MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN = 1 << 15, + MM_FILTER_RULE_WWAN = 1 << 16, } MMFilterRule; #define MM_FILTER_RULE_ALL \ @@ -69,7 +72,8 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_PLUGIN_WHITELIST | \ MM_FILTER_RULE_VIRTUAL | \ MM_FILTER_RULE_NET | \ - MM_FILTER_RULE_CDC_WDM | \ + MM_FILTER_RULE_USBMISC | \ + MM_FILTER_RULE_RPMSG | \ MM_FILTER_RULE_TTY | \ MM_FILTER_RULE_TTY_BLACKLIST | \ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \ @@ -78,21 +82,24 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_TTY_DRIVER | \ MM_FILTER_RULE_TTY_ACM_INTERFACE | \ MM_FILTER_RULE_TTY_WITH_NET | \ - MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN) + MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN | \ + MM_FILTER_RULE_WWAN) -/* This is the default ModemManager policy that tries to automatically probe +/* This is the legacy ModemManager policy that tries to automatically probe * device ports unless they're blacklisted in some way or another. */ -#define MM_FILTER_POLICY_DEFAULT \ +#define MM_FILTER_POLICY_LEGACY \ (MM_FILTER_RULE_EXPLICIT_WHITELIST | \ MM_FILTER_RULE_EXPLICIT_BLACKLIST | \ MM_FILTER_RULE_VIRTUAL | \ MM_FILTER_RULE_NET | \ - MM_FILTER_RULE_CDC_WDM | \ + MM_FILTER_RULE_USBMISC | \ + MM_FILTER_RULE_RPMSG | \ MM_FILTER_RULE_TTY | \ MM_FILTER_RULE_TTY_BLACKLIST | \ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \ - MM_FILTER_RULE_TTY_DEFAULT_ALLOWED) + MM_FILTER_RULE_TTY_DEFAULT_ALLOWED | \ + MM_FILTER_RULE_WWAN) /* This is a stricter policy which will only automatically probe device ports * if they are allowed by any of the automatic whitelist rules. */ @@ -102,13 +109,15 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_PLUGIN_WHITELIST | \ MM_FILTER_RULE_VIRTUAL | \ MM_FILTER_RULE_NET | \ - MM_FILTER_RULE_CDC_WDM | \ + MM_FILTER_RULE_USBMISC | \ + MM_FILTER_RULE_RPMSG | \ MM_FILTER_RULE_TTY | \ MM_FILTER_RULE_TTY_PLATFORM_DRIVER | \ MM_FILTER_RULE_TTY_DRIVER | \ MM_FILTER_RULE_TTY_ACM_INTERFACE | \ MM_FILTER_RULE_TTY_WITH_NET | \ - MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN) + MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN | \ + MM_FILTER_RULE_WWAN) /* This is equivalent to the strict policy, but also applying the device * blacklists explicitly */ @@ -118,7 +127,8 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_PLUGIN_WHITELIST | \ MM_FILTER_RULE_VIRTUAL | \ MM_FILTER_RULE_NET | \ - MM_FILTER_RULE_CDC_WDM | \ + MM_FILTER_RULE_USBMISC | \ + MM_FILTER_RULE_RPMSG | \ MM_FILTER_RULE_TTY | \ MM_FILTER_RULE_TTY_BLACKLIST | \ MM_FILTER_RULE_TTY_MANUAL_SCAN_ONLY | \ @@ -126,7 +136,8 @@ typedef enum { /*< underscore_name=mm_filter_rule >*/ MM_FILTER_RULE_TTY_DRIVER | \ MM_FILTER_RULE_TTY_ACM_INTERFACE | \ MM_FILTER_RULE_TTY_WITH_NET | \ - MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN) + MM_FILTER_RULE_TTY_DEFAULT_FORBIDDEN | \ + MM_FILTER_RULE_WWAN) /* This policy only allows using device ports explicitly whitelisted via * udev rules. i.e. ModemManager won't do any kind of automatic probing. */ @@ -145,6 +156,8 @@ gboolean mm_filter_device_and_port (MMFilter *self, void mm_filter_register_plugin_whitelist_tag (MMFilter *self, const gchar *tag); +void mm_filter_register_plugin_whitelist_vendor_id (MMFilter *self, + guint16 vid); void mm_filter_register_plugin_whitelist_product_id (MMFilter *self, guint16 vid, guint16 pid); diff --git a/src/mm-iface-modem-3gpp-ussd.c b/src/mm-iface-modem-3gpp-ussd.c index fd029230..e649a40f 100644 --- a/src/mm-iface-modem-3gpp-ussd.c +++ b/src/mm-iface-modem-3gpp-ussd.c @@ -26,7 +26,7 @@ #include "mm-iface-modem-3gpp-ussd.h" #include "mm-base-modem.h" #include "mm-modem-helpers.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "3gpp-ussd-support-checked-tag" #define SUPPORTED_TAG "3gpp-ussd-supported-tag" @@ -526,7 +526,7 @@ disable_unsolicited_events_ready (MMIfaceModem3gppUssd *self, MM_IFACE_MODEM_3GPP_USSD_GET_INTERFACE (self)->disable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Couldn't disable unsolicited USSD events: '%s'", error->message); + mm_obj_dbg (self, "couldn't disable unsolicited USSD events: %s", error->message); g_error_free (error); } @@ -547,7 +547,7 @@ cleanup_unsolicited_events_ready (MMIfaceModem3gppUssd *self, MM_IFACE_MODEM_3GPP_USSD_GET_INTERFACE (self)->cleanup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Couldn't cleanup unsolicited USSD events: '%s'", error->message); + mm_obj_dbg (self, "couldn't cleanup unsolicited USSD events: %s", error->message); g_error_free (error); } @@ -673,7 +673,7 @@ setup_unsolicited_events_ready (MMIfaceModem3gppUssd *self, MM_IFACE_MODEM_3GPP_USSD_GET_INTERFACE (self)->setup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Couldn't setup unsolicited USSD events: '%s'", error->message); + mm_obj_dbg (self, "couldn't setup unsolicited USSD events: %s", error->message); g_error_free (error); } @@ -694,7 +694,7 @@ enable_unsolicited_events_ready (MMIfaceModem3gppUssd *self, MM_IFACE_MODEM_3GPP_USSD_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Couldn't enable unsolicited USSD events: '%s'", error->message); + mm_obj_dbg (self, "couldn't enable unsolicited USSD events: %s", error->message); g_error_free (error); } @@ -813,7 +813,7 @@ check_support_ready (MMIfaceModem3gppUssd *self, &error)) { if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("USSD support check failed: '%s'", error->message); + mm_obj_dbg (self, "USSD support check failed: %s", error->message); g_error_free (error); } } else { diff --git a/src/mm-iface-modem-3gpp-ussd.h b/src/mm-iface-modem-3gpp-ussd.h index 37c60133..8a6d2f42 100644 --- a/src/mm-iface-modem-3gpp-ussd.h +++ b/src/mm-iface-modem-3gpp-ussd.h @@ -107,6 +107,7 @@ struct _MMIfaceModem3gppUssd { }; GType mm_iface_modem_3gpp_ussd_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModem3gppUssd, g_object_unref) /* Initialize USSD interface (async) */ void mm_iface_modem_3gpp_ussd_initialize (MMIfaceModem3gppUssd *self, diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c index 3e04f957..93899355 100644 --- a/src/mm-iface-modem-3gpp.c +++ b/src/mm-iface-modem-3gpp.c @@ -30,6 +30,16 @@ #define SUBSYSTEM_3GPP "3gpp" +/* When comparing EPS bearer settings take into account that PASSWORD may not always + * be readable, and apply very loose matching for all fields. Also, some implementations + * may allow configuring roaming allowance in the initial EPS bearer, but that is also + * not common. */ +#define MM_BEARER_PROPERTIES_CMP_FLAGS_EPS \ + (MM_BEARER_PROPERTIES_CMP_FLAGS_LOOSE | \ + MM_BEARER_PROPERTIES_CMP_FLAGS_NO_PASSWORD | \ + MM_BEARER_PROPERTIES_CMP_FLAGS_NO_ALLOW_ROAMING | \ + MM_BEARER_PROPERTIES_CMP_FLAGS_NO_RM_PROTOCOL) + /*****************************************************************************/ /* Private data context */ @@ -38,9 +48,10 @@ static GQuark private_quark; typedef struct { /* Registration state */ - MMModem3gppRegistrationState cs; - MMModem3gppRegistrationState ps; - MMModem3gppRegistrationState eps; + MMModem3gppRegistrationState state_cs; + MMModem3gppRegistrationState state_ps; + MMModem3gppRegistrationState state_eps; + MMModem3gppRegistrationState state_5gs; gboolean manual_registration; gchar *manual_registration_operator_id; GCancellable *pending_registration_cancellable; @@ -74,9 +85,10 @@ get_private (MMIfaceModem3gpp *self) priv = g_object_get_qdata (G_OBJECT (self), private_quark); if (!priv) { priv = g_slice_new0 (Private); - priv->cs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; - priv->ps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; - priv->eps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + priv->state_cs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + priv->state_ps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + priv->state_eps = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + priv->state_5gs = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free); } @@ -130,8 +142,7 @@ mm_iface_modem_3gpp_bind_simple_status (MMIfaceModem3gpp *self, static MMModem3gppRegistrationState get_consolidated_reg_state (MMIfaceModem3gpp *self) { - Private *priv; - MMModem3gppRegistrationState consolidated = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + Private *priv; priv = get_private (self); @@ -140,50 +151,41 @@ get_consolidated_reg_state (MMIfaceModem3gpp *self) * So here we prefer the +CREG response, but if we never got a successful * +CREG response, we'll take +CGREG instead. */ - if (priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || - priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) { - consolidated = priv->cs; - goto out; - } - if (priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || - priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) { - consolidated = priv->ps; - goto out; - } - if (priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || - priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) { - consolidated = priv->eps; - goto out; - } + if (priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) + return priv->state_cs; + if (priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) + return priv->state_ps; + if (priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) + return priv->state_eps; + if (priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) + return priv->state_5gs; /* Searching? */ - if (priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || - priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || - priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING) { - consolidated = MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING; - goto out; - } + if (priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || + priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || + priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING || + priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING) + return MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING; /* If at least one state is DENIED and the others are UNKNOWN or IDLE, use DENIED */ - if ((priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || - priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || - priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED) && - REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->cs) && - REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->ps) && - REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->eps)) { - consolidated = MM_MODEM_3GPP_REGISTRATION_STATE_DENIED; - goto out; - } + if ((priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || + priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || + priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED || + priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED) && + REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->state_cs) && + REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->state_ps) && + REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->state_eps) && + REG_STATE_IS_UNKNOWN_IDLE_DENIED (priv->state_5gs)) + return MM_MODEM_3GPP_REGISTRATION_STATE_DENIED; /* Emergency services? */ - if (priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY || - priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY || - priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY) { - consolidated = MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY; - goto out; - } + if (priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY || + priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY || + priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY || + priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY) + return MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY; - /* Support for additional registration states reported when on LTE. + /* Support for additional registration states reported when on LTE/5GNR. * * For example, we may see the modem registered in LTE (EPS==HOME), and we * may get "SMS only" reported for CS. @@ -195,32 +197,23 @@ get_consolidated_reg_state (MMIfaceModem3gpp *self) * We also warn in that case, because ideally we should always report the * LTE registration state first, not this one. */ - if (priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY || - priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY || - priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED || - priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) { - mm_warn ("3GPP CSFB registration state is consolidated: %s", - mm_modem_3gpp_registration_state_get_string (priv->cs)); - consolidated = priv->cs; - goto out; + if (priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY || + priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY || + priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED || + priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) { + mm_obj_warn (self, "3GPP CSFB registration state is consolidated: %s", + mm_modem_3gpp_registration_state_get_string (priv->state_cs)); + return priv->state_cs; } /* Idle? */ - if (priv->cs == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE || - priv->ps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE || - priv->eps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) { - consolidated = MM_MODEM_3GPP_REGISTRATION_STATE_IDLE; - goto out; - } + if (priv->state_cs == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE || + priv->state_ps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE || + priv->state_eps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE || + priv->state_5gs == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) + return MM_MODEM_3GPP_REGISTRATION_STATE_IDLE; - out: - mm_dbg ("building consolidated registration state: cs '%s', ps '%s', eps '%s' --> '%s'", - mm_modem_3gpp_registration_state_get_string (priv->cs), - mm_modem_3gpp_registration_state_get_string (priv->ps), - mm_modem_3gpp_registration_state_get_string (priv->eps), - mm_modem_3gpp_registration_state_get_string (consolidated)); - - return consolidated; + return MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; } /*****************************************************************************/ @@ -298,7 +291,7 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, mm_iface_modem_3gpp_run_registration_checks_finish (MM_IFACE_MODEM_3GPP (self), res, &error); if (error) { - mm_dbg ("3GPP registration check failed: '%s'", error->message); + mm_obj_dbg (self, "3GPP registration check failed: %s", error->message); register_in_network_context_complete_failed (task, error); return; } @@ -308,10 +301,10 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, /* If we got a final state and it's denied, we can assume the registration is * finished */ if (current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED) { - mm_dbg ("Registration denied"); + mm_obj_dbg (self, "registration denied"); register_in_network_context_complete_failed ( task, - mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED)); + mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED, self)); return; } @@ -322,7 +315,7 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, * wouldn't be an explicit refresh triggered from the modem interface as * the modem never got un-registered during the sequence. */ mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self)); - mm_dbg ("Modem is currently registered in a 3GPP network"); + mm_obj_dbg (self, "currently registered in a 3GPP network"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; @@ -330,10 +323,10 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, /* Don't spend too much time waiting to get registered */ if (g_timer_elapsed (ctx->timer, NULL) > ctx->max_registration_time) { - mm_dbg ("3GPP registration check timed out"); + mm_obj_dbg (self, "3GPP registration check timed out"); register_in_network_context_complete_failed ( task, - mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)); + mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, self)); return; } @@ -343,7 +336,7 @@ run_registration_checks_ready (MMIfaceModem3gpp *self, * This 3s timeout will catch results from automatic registrations as * well. */ - mm_dbg ("Modem not yet registered in a 3GPP network... will recheck soon"); + mm_obj_dbg (self, "not yet registered in a 3GPP network... will recheck soon"); g_timeout_add_seconds (3, (GSourceFunc)run_registration_checks, task); } @@ -441,16 +434,15 @@ mm_iface_modem_3gpp_register_in_network (MMIfaceModem3gpp *self, (g_strcmp0 (current_operator_code, ctx->operator_id) == 0) && REG_STATE_IS_REGISTERED (reg_state) && priv->manual_registration) { - mm_dbg ("Already registered manually in selected network '%s'," - " manual registration not launched...", - current_operator_code); + mm_obj_dbg (self, "already registered manually in selected network '%s', manual registration not launched...", + current_operator_code); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } /* Manual registration to a new operator required */ - mm_dbg ("Launching manual network registration (%s)...", ctx->operator_id); + mm_obj_dbg (self, "launching manual network registration (%s)...", ctx->operator_id); g_free (priv->manual_registration_operator_id); priv->manual_registration_operator_id = g_strdup (ctx->operator_id); priv->manual_registration = TRUE; @@ -462,16 +454,16 @@ mm_iface_modem_3gpp_register_in_network (MMIfaceModem3gpp *self, if (!force_registration && (current_operator_code || REG_STATE_IS_REGISTERED (reg_state)) && !priv->manual_registration) { - mm_dbg ("Already registered automatically in network '%s'," - " automatic registration not launched...", - current_operator_code); + mm_obj_dbg (self, "already registered automatically in network '%s'," + " automatic registration not launched...", + current_operator_code); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } /* Automatic registration to a new operator requested */ - mm_dbg ("Launching automatic network registration..."); + mm_obj_dbg (self, "launching automatic network registration..."); g_clear_pointer (&priv->manual_registration_operator_id, g_free); priv->manual_registration = FALSE; } @@ -990,6 +982,45 @@ handle_set_initial_eps_bearer_settings_context_free (HandleSetInitialEpsBearerSe g_slice_free (HandleSetInitialEpsBearerSettingsContext, ctx); } +static void +log_initial_eps_bearer_settings (MMIfaceModem3gpp *self, + MMBearerProperties *properties) +{ + const gchar *apn; + MMBearerAllowedAuth allowed_auth; + const gchar *user; + const gchar *password; + MMBearerIpFamily ip_family; + + apn = mm_bearer_properties_get_apn (properties); + if (apn) + mm_obj_dbg (self, " APN: '%s'", apn); + + allowed_auth = mm_bearer_properties_get_allowed_auth (properties); + if (allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) { + g_autofree gchar *allowed_auth_str = NULL; + + allowed_auth_str = mm_bearer_allowed_auth_build_string_from_mask (allowed_auth); + mm_obj_dbg (self, " allowed auth: '%s'", allowed_auth_str); + } + + user = mm_bearer_properties_get_user (properties); + if (user) + mm_obj_dbg (self, " user: '%s'", user); + + password = mm_bearer_properties_get_password (properties); + if (password) + mm_obj_dbg (self, " password: '%s'", password); + + ip_family = mm_bearer_properties_get_ip_type (properties); + if (ip_family != MM_BEARER_IP_FAMILY_NONE) { + g_autofree gchar *ip_family_str = NULL; + + ip_family_str = mm_bearer_ip_family_build_string_from_mask (ip_family); + mm_obj_dbg (self, " ip family: '%s'", ip_family_str); + } +} + static void after_set_load_initial_eps_bearer_settings_ready (MMIfaceModem3gpp *self, GAsyncResult *res, @@ -1005,7 +1036,12 @@ after_set_load_initial_eps_bearer_settings_ready (MMIfaceModem3gpp return; } - if (!mm_bearer_properties_cmp (new_config, ctx->config)) { + mm_obj_dbg (self, "Updated initial EPS bearer settings:"); + log_initial_eps_bearer_settings (self, new_config); + + if (!mm_bearer_properties_cmp (new_config, ctx->config, MM_BEARER_PROPERTIES_CMP_FLAGS_EPS)) { + mm_obj_dbg (self, "Requested initial EPS bearer settings:"); + log_initial_eps_bearer_settings (self, ctx->config); g_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Initial EPS bearer settings were not updated"); } else { @@ -1082,15 +1118,11 @@ set_initial_eps_bearer_settings_auth_ready (MMBaseModem return; } - /* If the user doesn't specify explicit auth settings, assume NONE as default */ - if (mm_bearer_properties_get_allowed_auth (ctx->config) == MM_BEARER_ALLOWED_AUTH_UNKNOWN) - mm_bearer_properties_set_allowed_auth (ctx->config, MM_BEARER_ALLOWED_AUTH_NONE); - old_dictionary = mm_gdbus_modem3gpp_get_initial_eps_bearer_settings (ctx->skeleton); if (old_dictionary) old_config = mm_bearer_properties_new_from_dictionary (old_dictionary, NULL); - if (old_config && mm_bearer_properties_cmp (ctx->config, old_config)) { + if (old_config && mm_bearer_properties_cmp (ctx->config, old_config, MM_BEARER_PROPERTIES_CMP_FLAGS_EPS)) { mm_gdbus_modem3gpp_complete_set_initial_eps_bearer_settings (ctx->skeleton, ctx->invocation); handle_set_initial_eps_bearer_settings_context_free (ctx); } else { @@ -1142,27 +1174,31 @@ mm_iface_modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, GAsyncReadyCallback callback, gpointer user_data) { - gboolean cs_supported = FALSE; - gboolean ps_supported = FALSE; - gboolean eps_supported = FALSE; + gboolean is_cs_supported = FALSE; + gboolean is_ps_supported = FALSE; + gboolean is_eps_supported = FALSE; + gboolean is_5gs_supported = FALSE; g_assert (MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->run_registration_checks != NULL); g_object_get (self, - MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, &cs_supported, - MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, &ps_supported, - MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, &eps_supported, + MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, &is_cs_supported, + MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, &is_ps_supported, + MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, &is_eps_supported, + MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED, &is_5gs_supported, NULL); - mm_dbg ("Running registration checks (CS: '%s', PS: '%s', EPS: '%s')", - cs_supported ? "yes" : "no", - ps_supported ? "yes" : "no", - eps_supported ? "yes" : "no"); + mm_obj_dbg (self, "running registration checks (CS: '%s', PS: '%s', EPS: '%s', 5GS: '%s')", + is_cs_supported ? "yes" : "no", + is_ps_supported ? "yes" : "no", + is_eps_supported ? "yes" : "no", + is_5gs_supported ? "yes" : "no"); MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->run_registration_checks (self, - cs_supported, - ps_supported, - eps_supported, + is_cs_supported, + is_ps_supported, + is_eps_supported, + is_5gs_supported, callback, user_data); } @@ -1206,7 +1242,7 @@ load_operator_name_ready (MMIfaceModem3gpp *self, str = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_operator_name_finish (self, res, &error); if (error) { - mm_warn ("Couldn't load Operator Name: '%s'", error->message); + mm_obj_warn (self, "couldn't load operator name: %s", error->message); g_error_free (error); } @@ -1233,9 +1269,9 @@ load_operator_code_ready (MMIfaceModem3gpp *self, str = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_operator_code_finish (self, res, &error); if (error) { - mm_warn ("Couldn't load Operator Code: '%s'", error->message); + mm_obj_warn (self, "couldn't load operator code: %s", error->message); } else if (!mm_3gpp_parse_operator_id (str, &mcc, &mnc, &error)) { - mm_dbg ("Unexpected MCC/MNC string '%s': '%s'", str, error->message); + mm_obj_dbg (self, "unexpected operator code string '%s': %s", str, error->message); g_clear_pointer (&str, g_free); } g_clear_error (&error); @@ -1373,9 +1409,9 @@ mm_iface_modem_3gpp_update_access_technologies (MMIfaceModem3gpp *self, void mm_iface_modem_3gpp_update_location (MMIfaceModem3gpp *self, - gulong location_area_code, - gulong tracking_area_code, - gulong cell_id) + gulong location_area_code, + gulong tracking_area_code, + gulong cell_id) { Private *priv; MMModem3gppRegistrationState state; @@ -1394,7 +1430,7 @@ mm_iface_modem_3gpp_update_location (MMIfaceModem3gpp *self, * where we're registering (loading current registration info after a state * change to registered), we also allow LAC/CID updates. */ if (REG_STATE_IS_REGISTERED (state) || priv->reloading_registration_info) { - if ((location_area_code > 0 || tracking_area_code > 0) && cell_id > 0) + if (location_area_code || tracking_area_code || cell_id) mm_iface_modem_location_3gpp_update_lac_tac_ci (MM_IFACE_MODEM_LOCATION (self), location_area_code, tracking_area_code, @@ -1417,9 +1453,14 @@ update_registration_reload_current_registration_info_ready (MMIfaceModem3gpp *se new_state = GPOINTER_TO_UINT (user_data); - mm_info ("Modem %s: 3GPP Registration state changed (registering -> %s)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self)), - mm_modem_3gpp_registration_state_get_string (new_state)); + mm_obj_info (self, "3GPP registration state changed (registering -> %s)", + mm_modem_3gpp_registration_state_get_string (new_state)); + mm_obj_dbg (self, "consolidated registration state: cs '%s', ps '%s', eps '%s', 5gs '%s' --> '%s'", + mm_modem_3gpp_registration_state_get_string (priv->state_cs), + mm_modem_3gpp_registration_state_get_string (priv->state_ps), + mm_modem_3gpp_registration_state_get_string (priv->state_eps), + mm_modem_3gpp_registration_state_get_string (priv->state_5gs), + mm_modem_3gpp_registration_state_get_string (new_state)); /* The property in the interface is bound to the property * in the skeleton, so just updating here is enough */ @@ -1494,14 +1535,12 @@ update_registration_state (MMIfaceModem3gpp *self, MM_IFACE_MODEM_STATE, &modem_state, NULL); if (modem_state < MM_MODEM_STATE_ENABLED) { - mm_dbg ("Modem %s: 3GPP Registration state change ignored as modem isn't enabled", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self))); + mm_obj_dbg (self, "3GPP registration state change ignored as modem isn't enabled"); return; } - mm_info ("Modem %s: 3GPP Registration state changed (%s -> registering)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self)), - mm_modem_3gpp_registration_state_get_string (old_state)); + mm_obj_info (self, "3GPP registration state changed (%s -> registering)", + mm_modem_3gpp_registration_state_get_string (old_state)); /* Reload current registration info. ONLY update the state to REGISTERED * after having loaded operator code/name/subscription state */ @@ -1513,10 +1552,15 @@ update_registration_state (MMIfaceModem3gpp *self, return; } - mm_info ("Modem %s: 3GPP Registration state changed (%s -> %s)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self)), - mm_modem_3gpp_registration_state_get_string (old_state), - mm_modem_3gpp_registration_state_get_string (new_state)); + mm_obj_info (self, "3GPP registration state changed (%s -> %s)", + mm_modem_3gpp_registration_state_get_string (old_state), + mm_modem_3gpp_registration_state_get_string (new_state)); + mm_obj_dbg (self, "consolidated registration state: cs '%s', ps '%s', eps '%s', 5gs '%s' --> '%s'", + mm_modem_3gpp_registration_state_get_string (priv->state_cs), + mm_modem_3gpp_registration_state_get_string (priv->state_ps), + mm_modem_3gpp_registration_state_get_string (priv->state_eps), + mm_modem_3gpp_registration_state_get_string (priv->state_5gs), + mm_modem_3gpp_registration_state_get_string (new_state)); update_non_registered_state (self, old_state, new_state); } @@ -1536,7 +1580,7 @@ mm_iface_modem_3gpp_update_cs_registration_state (MMIfaceModem3gpp * return; priv = get_private (self); - priv->cs = state; + priv->state_cs = state; update_registration_state (self, get_consolidated_reg_state (self), TRUE); } @@ -1555,7 +1599,7 @@ mm_iface_modem_3gpp_update_ps_registration_state (MMIfaceModem3gpp * return; priv = get_private (self); - priv->ps = state; + priv->state_ps = state; update_registration_state (self, get_consolidated_reg_state (self), TRUE); } @@ -1574,7 +1618,26 @@ mm_iface_modem_3gpp_update_eps_registration_state (MMIfaceModem3gpp return; priv = get_private (self); - priv->eps = state; + priv->state_eps = state; + update_registration_state (self, get_consolidated_reg_state (self), TRUE); +} + +void +mm_iface_modem_3gpp_update_5gs_registration_state (MMIfaceModem3gpp *self, + MMModem3gppRegistrationState state) +{ + Private *priv; + gboolean supported = FALSE; + + g_object_get (self, + MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED, &supported, + NULL); + + if (!supported) + return; + + priv = get_private (self); + priv->state_5gs = state; update_registration_state (self, get_consolidated_reg_state (self), TRUE); } @@ -1594,7 +1657,7 @@ periodic_registration_checks_ready (MMIfaceModem3gpp *self, mm_iface_modem_3gpp_run_registration_checks_finish (self, res, &error); if (error) { - mm_dbg ("Couldn't refresh 3GPP registration status: '%s'", error->message); + mm_obj_dbg (self, "couldn't refresh 3GPP registration status: %s", error->message); g_error_free (error); } @@ -1633,7 +1696,7 @@ periodic_registration_check_disable (MMIfaceModem3gpp *self) g_source_remove (priv->check_timeout_source); priv->check_timeout_source = 0; - mm_dbg ("Periodic 3GPP registration checks disabled"); + mm_obj_dbg (self, "periodic 3GPP registration checks disabled"); } static void @@ -1648,7 +1711,7 @@ periodic_registration_check_enable (MMIfaceModem3gpp *self) return; /* Create context and keep it as object data */ - mm_dbg ("Periodic 3GPP registration checks enabled"); + mm_obj_dbg (self, "periodic 3GPP registration checks enabled"); priv->check_timeout_source = g_timeout_add_seconds (REGISTRATION_CHECK_TIMEOUT_SEC, (GSourceFunc)periodic_registration_check, self); @@ -1699,13 +1762,16 @@ mm_iface_modem_3gpp_update_initial_eps_bearer (MMIfaceModem3gpp *self, /* skip update? */ if ((!old_bearer && !properties) || - (old_bearer && properties && mm_bearer_properties_cmp (properties, mm_base_bearer_peek_config (MM_BASE_BEARER (old_bearer))))) + (old_bearer && properties && + mm_bearer_properties_cmp (properties, + mm_base_bearer_peek_config (MM_BASE_BEARER (old_bearer)), + MM_BEARER_PROPERTIES_CMP_FLAGS_EPS))) goto out; if (properties) { MMBaseBearer *new_bearer; - mm_dbg ("updating initial EPS bearer..."); + mm_obj_dbg (self, "updating initial EPS bearer..."); g_assert (MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->create_initial_eps_bearer); new_bearer = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->create_initial_eps_bearer (self, properties); g_object_set (self, @@ -1714,7 +1780,7 @@ mm_iface_modem_3gpp_update_initial_eps_bearer (MMIfaceModem3gpp *self, mm_gdbus_modem3gpp_set_initial_eps_bearer (skeleton, mm_base_bearer_get_path (new_bearer)); g_object_unref (new_bearer); } else { - mm_dbg ("clearing initial EPS bearer..."); + mm_obj_dbg (self, "clearing initial EPS bearer..."); g_object_set (self, MM_IFACE_MODEM_3GPP_INITIAL_EPS_BEARER, NULL, NULL); @@ -1726,6 +1792,41 @@ mm_iface_modem_3gpp_update_initial_eps_bearer (MMIfaceModem3gpp *self, g_object_unref (skeleton); } +static void +reload_initial_eps_bearer_ready (MMIfaceModem3gpp *self, + GAsyncResult *res) +{ + g_autoptr(MMBearerProperties) properties = NULL; + g_autoptr(GError) error = NULL; + + properties = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish (self, res, &error); + if (!properties) { + mm_obj_dbg (self, "couldn't load initial default bearer properties: %s", error->message); + return; + } + + mm_iface_modem_3gpp_update_initial_eps_bearer (self, properties); +} + +void +mm_iface_modem_3gpp_reload_initial_eps_bearer (MMIfaceModem3gpp *self) +{ + gboolean eps_supported = FALSE; + + g_object_get (self, + MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, &eps_supported, + NULL); + + if (eps_supported && + MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer && + MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish) { + MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer ( + self, + (GAsyncReadyCallback)reload_initial_eps_bearer_ready, + NULL); + } +} + /*****************************************************************************/ typedef struct _DisablingContext DisablingContext; @@ -1776,7 +1877,7 @@ mm_iface_modem_3gpp_disable_finish (MMIfaceModem3gpp *self, \ MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->NAME##_finish (self, res, &error); \ if (error) { \ - mm_dbg ("Couldn't %s: '%s'", DISPLAY, error->message); \ + mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \ g_error_free (error); \ } \ \ @@ -1979,7 +2080,7 @@ setup_unsolicited_events_ready (MMIfaceModem3gpp *self, MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->setup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Setting up unsolicited events failed: '%s'", error->message); + mm_obj_dbg (self, "setting up unsolicited events failed: %s", error->message); g_error_free (error); /* If we get an error setting up unsolicited events, don't even bother trying to @@ -2005,7 +2106,7 @@ enable_unsolicited_events_ready (MMIfaceModem3gpp *self, MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Enabling unsolicited events failed: '%s'", error->message); + mm_obj_dbg (self, "enabling unsolicited events failed: %s", error->message); g_error_free (error); } @@ -2028,7 +2129,7 @@ setup_unsolicited_registration_events_ready (MMIfaceModem3gpp *self, MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->setup_unsolicited_registration_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Setting up unsolicited registration events failed: '%s'", error->message); + mm_obj_dbg (self, "setting up unsolicited registration events failed: %s", error->message); g_error_free (error); /* If we get an error setting up unsolicited events, don't even bother trying to @@ -2056,7 +2157,7 @@ enable_unsolicited_registration_events_ready (MMIfaceModem3gpp *self, MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->enable_unsolicited_registration_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Enabling unsolicited registration events failed: '%s'", error->message); + mm_obj_dbg (self, "enabling unsolicited registration events failed: %s", error->message); g_error_free (error); /* If error, setup periodic registration checks */ periodic_registration_check_enable (self); @@ -2081,7 +2182,7 @@ load_initial_eps_bearer_ready (MMIfaceModem3gpp *self, properties = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_finish (self, res, &error); if (!properties) { - mm_dbg ("couldn't load initial default bearer properties: '%s'", error->message); + mm_obj_dbg (self, "couldn't load initial default bearer properties: %s", error->message); g_error_free (error); goto out; } @@ -2293,7 +2394,7 @@ load_initial_eps_bearer_settings_ready (MMIfaceModem3gpp *self, config = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_initial_eps_bearer_settings_finish (self, res, &error); if (!config) { - mm_warn ("couldn't load initial EPS bearer settings: '%s'", error->message); + mm_obj_warn (self, "couldn't load initial EPS bearer settings: %s", error->message); g_error_free (error); } else { GVariant *dictionary; @@ -2325,7 +2426,7 @@ load_eps_ue_mode_operation_ready (MMIfaceModem3gpp *self, mm_gdbus_modem3gpp_set_eps_ue_mode_operation (ctx->skeleton, uemode); if (error) { - mm_warn ("couldn't load UE mode of operation for EPS: '%s'", error->message); + mm_obj_warn (self, "couldn't load UE mode of operation for EPS: %s", error->message); g_error_free (error); } @@ -2349,7 +2450,7 @@ load_enabled_facility_locks_ready (MMIfaceModem3gpp *self, mm_gdbus_modem3gpp_set_enabled_facility_locks (ctx->skeleton, facilities); if (error) { - mm_warn ("couldn't load facility locks: '%s'", error->message); + mm_obj_warn (self, "couldn't load facility locks: %s", error->message); g_error_free (error); } else { MMBaseSim *sim = NULL; @@ -2389,7 +2490,7 @@ load_imei_ready (MMIfaceModem3gpp *self, g_free (imei); if (error) { - mm_warn ("couldn't load IMEI: '%s'", error->message); + mm_obj_warn (self, "couldn't load IMEI: %s", error->message); g_error_free (error); } @@ -2548,15 +2649,6 @@ mm_iface_modem_3gpp_initialize (MMIfaceModem3gpp *self, g_object_set (self, MM_IFACE_MODEM_3GPP_DBUS_SKELETON, skeleton, NULL); - - /* If the modem is *only* LTE, we assume that CS network is not - * supported */ - if (mm_iface_modem_is_3gpp_lte_only (MM_IFACE_MODEM (self))) { - mm_dbg ("Modem is LTE-only, assuming CS network is not supported"); - g_object_set (self, - MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, FALSE, - NULL); - } } ctx = g_new0 (InitializationContext, 1); @@ -2632,6 +2724,14 @@ iface_modem_3gpp_init (gpointer g_iface) FALSE, G_PARAM_READWRITE)); + g_object_interface_install_property + (g_iface, + g_param_spec_boolean (MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED, + "5GS network supported", + "Whether the modem works in the 5GS network", + FALSE, + G_PARAM_READWRITE)); + g_object_interface_install_property (g_iface, g_param_spec_flags (MM_IFACE_MODEM_3GPP_IGNORED_FACILITY_LOCKS, diff --git a/src/mm-iface-modem-3gpp.h b/src/mm-iface-modem-3gpp.h index 91976fdc..258e5c10 100644 --- a/src/mm-iface-modem-3gpp.h +++ b/src/mm-iface-modem-3gpp.h @@ -34,6 +34,7 @@ #define MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED "iface-modem-3gpp-cs-network-supported" #define MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED "iface-modem-3gpp-ps-network-supported" #define MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED "iface-modem-3gpp-eps-network-supported" +#define MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED "iface-modem-3gpp-5gs-network-supported" #define MM_IFACE_MODEM_3GPP_IGNORED_FACILITY_LOCKS "iface-modem-3gpp-ignored-facility-locks" #define MM_IFACE_MODEM_3GPP_INITIAL_EPS_BEARER "iface-modem-3gpp-initial-eps-bearer" @@ -47,7 +48,8 @@ MM_MODEM_ACCESS_TECHNOLOGY_HSUPA | \ MM_MODEM_ACCESS_TECHNOLOGY_HSPA | \ MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS | \ - MM_MODEM_ACCESS_TECHNOLOGY_LTE) + MM_MODEM_ACCESS_TECHNOLOGY_LTE | \ + MM_MODEM_ACCESS_TECHNOLOGY_5GNR) typedef struct _MMIfaceModem3gpp MMIfaceModem3gpp; @@ -167,13 +169,14 @@ struct _MMIfaceModem3gpp { MMBaseBearer * (*create_initial_eps_bearer) (MMIfaceModem3gpp *self, MMBearerProperties *properties); - /* Run CS/PS/EPS registration state checks.. + /* Run CS/PS/EPS/5GS registration state checks.. * Note that no registration state is returned, implementations should call * mm_iface_modem_3gpp_update_registration_state(). */ void (* run_registration_checks) (MMIfaceModem3gpp *self, - gboolean cs_supported, - gboolean ps_supported, - gboolean eps_supported, + gboolean is_cs_supported, + gboolean is_ps_supported, + gboolean is_eps_supported, + gboolean is_5gs_supported, GAsyncReadyCallback callback, gpointer user_data); gboolean (*run_registration_checks_finish) (MMIfaceModem3gpp *self, @@ -234,6 +237,7 @@ struct _MMIfaceModem3gpp { }; GType mm_iface_modem_3gpp_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModem3gpp, g_object_unref) /* Initialize Modem 3GPP interface (async) */ void mm_iface_modem_3gpp_initialize (MMIfaceModem3gpp *self, @@ -274,6 +278,8 @@ void mm_iface_modem_3gpp_update_ps_registration_state (MMIfaceModem3gpp *self, MMModem3gppRegistrationState state); void mm_iface_modem_3gpp_update_eps_registration_state (MMIfaceModem3gpp *self, MMModem3gppRegistrationState state); +void mm_iface_modem_3gpp_update_5gs_registration_state (MMIfaceModem3gpp *self, + MMModem3gppRegistrationState state); void mm_iface_modem_3gpp_update_subscription_state (MMIfaceModem3gpp *self, MMModem3gppSubscriptionState state); void mm_iface_modem_3gpp_update_access_technologies (MMIfaceModem3gpp *self, @@ -286,6 +292,7 @@ void mm_iface_modem_3gpp_update_pco_list (MMIfaceModem3gpp *self, const GList *pco_list); void mm_iface_modem_3gpp_update_initial_eps_bearer (MMIfaceModem3gpp *self, MMBearerProperties *properties); +void mm_iface_modem_3gpp_reload_initial_eps_bearer (MMIfaceModem3gpp *self); /* Run all registration checks */ void mm_iface_modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self, diff --git a/src/mm-iface-modem-cdma.c b/src/mm-iface-modem-cdma.c index c012fe0c..877afe4e 100644 --- a/src/mm-iface-modem-cdma.c +++ b/src/mm-iface-modem-cdma.c @@ -23,7 +23,7 @@ #include "mm-iface-modem-cdma.h" #include "mm-base-modem.h" #include "mm-modem-helpers.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUBSYSTEM_CDMA1X "cdma1x" #define SUBSYSTEM_EVDO "evdo" @@ -161,7 +161,7 @@ handle_activate_auth_ready (MMBaseModem *self, /* If we're already activated, nothing to do */ if (mm_gdbus_modem_cdma_get_activation_state (ctx->skeleton) == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED) { - mm_dbg ("Modem is already activated"); + mm_obj_dbg (self, "already activated"); mm_gdbus_modem_cdma_complete_activate (ctx->skeleton, ctx->invocation); handle_activate_context_free (ctx); return; @@ -348,7 +348,7 @@ handle_activate_manual_auth_ready (MMBaseModem *self, /* If we're already activated, nothing to do */ if (mm_gdbus_modem_cdma_get_activation_state (ctx->skeleton) == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED) { - mm_dbg ("Modem is already activated"); + mm_obj_dbg (self, "already activated"); mm_gdbus_modem_cdma_complete_activate_manual (ctx->skeleton, ctx->invocation); handle_activate_manual_context_free (ctx); return; @@ -617,7 +617,7 @@ get_call_manager_state_ready (MMIfaceModemCdma *self, &ctx->call_manager_system_mode, &ctx->call_manager_operating_mode, &error)) { - mm_dbg ("Could not get call manager state: %s", error->message); + mm_obj_dbg (self, "could not get call manager state: %s", error->message); g_error_free (error); /* Fallback to AT-based check */ ctx->step = REGISTRATION_CHECK_STEP_AT_CDMA_SERVICE_STATUS; @@ -654,7 +654,7 @@ get_hdr_state_ready (MMIfaceModemCdma *self, &ctx->hdr_session_state, &ctx->hdr_almp_state, &error)) { - mm_dbg ("Could not get HDR state: %s", error->message); + mm_obj_dbg (self, "could not get HDR state: %s", error->message); g_error_free (error); /* Fallback to AT-based check */ ctx->step = REGISTRATION_CHECK_STEP_AT_CDMA_SERVICE_STATUS; @@ -670,14 +670,16 @@ get_hdr_state_ready (MMIfaceModemCdma *self, static void parse_qcdm_results (GTask *task) { + MMIfaceModemCdma *self; RunRegistrationChecksContext *ctx; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - mm_dbg ("QCDM CM System Mode: %d", ctx->call_manager_system_mode); - mm_dbg ("QCDM HDR Hybrid Mode: %d", ctx->hdr_hybrid_mode); - mm_dbg ("QCDM HDR Session State: %d", ctx->hdr_session_state); - mm_dbg ("QCDM HDR ALMP State: %d", ctx->hdr_almp_state); + mm_obj_dbg (self, "QCDM CM System Mode: %d", ctx->call_manager_system_mode); + mm_obj_dbg (self, "QCDM HDR Hybrid Mode: %d", ctx->hdr_hybrid_mode); + mm_obj_dbg (self, "QCDM HDR Session State: %d", ctx->hdr_session_state); + mm_obj_dbg (self, "QCDM HDR ALMP State: %d", ctx->hdr_almp_state); /* Set QCDM-obtained registration info */ switch (ctx->call_manager_system_mode) { @@ -725,7 +727,7 @@ get_service_status_ready (MMIfaceModemCdma *self, res, &has_service, &error)) { - mm_warn ("Could not get service status: %s", error->message); + mm_obj_warn (self, "could not get service status: %s", error->message); g_task_return_error (task, error); g_object_unref (task); return; @@ -733,7 +735,7 @@ get_service_status_ready (MMIfaceModemCdma *self, if (!has_service) { /* There is no CDMA service at all, end registration checks */ - mm_dbg ("No CDMA service found"); + mm_obj_dbg (self, "no CDMA service found"); ctx->step = REGISTRATION_CHECK_STEP_LAST; } else /* If we do have service, go on to next step */ @@ -766,7 +768,7 @@ get_cdma1x_serving_system_ready (MMIfaceModemCdma *self, if (!g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK)) { - mm_warn ("Could not get serving system: %s", error->message); + mm_obj_warn (self, "could not get serving system: %s", error->message); g_task_return_error (task, error); g_object_unref (task); return; @@ -786,15 +788,17 @@ get_cdma1x_serving_system_ready (MMIfaceModemCdma *self, static void parse_at_results (GTask *task) { + MMIfaceModemCdma *self; RunRegistrationChecksContext *ctx; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); /* 99999 means unknown/no service */ if (ctx->cdma1x_sid == MM_MODEM_CDMA_SID_UNKNOWN && ctx->cdma1x_nid == MM_MODEM_CDMA_NID_UNKNOWN) { /* Not registered in CDMA network, end registration checks */ - mm_dbg ("Not registered in any CDMA network"); + mm_obj_dbg (self, "no registered in any CDMA network"); ctx->step = REGISTRATION_CHECK_STEP_LAST; } else { /* We're registered on the CDMA 1x network (at least) */ @@ -826,7 +830,7 @@ get_detailed_registration_state_ready (MMIfaceModemCdma *self, &error)) { /* This error is NOT fatal. If we get an error here, we'll just fallback * to the non-detailed values we already got. */ - mm_dbg ("Could not get more detailed registration state: %s", error->message); + mm_obj_dbg (self, "could not get more detailed registration state: %s", error->message); } else { ctx->cdma1x_state = detailed_cdma1x_state; ctx->evdo_state = detailed_evdo_state; @@ -868,7 +872,7 @@ registration_check_step (GTask *task) /* fall through */ case REGISTRATION_CHECK_STEP_QCDM_CALL_MANAGER_STATE: - mm_dbg ("Starting QCDM-based registration checks"); + mm_obj_dbg (self, "starting QCDM-based registration checks..."); if (!ctx->skip_qcdm_call_manager_step && MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->get_call_manager_state && MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->get_call_manager_state_finish) { @@ -880,7 +884,7 @@ registration_check_step (GTask *task) return; } /* Fallback to AT-based check */ - mm_dbg (" Skipping all QCDM-based checks and falling back to AT-based checks"); + mm_obj_dbg (self, " skipping all QCDM-based checks and falling back to AT-based checks"); ctx->step = REGISTRATION_CHECK_STEP_AT_CDMA_SERVICE_STATUS; registration_check_step (task); return; @@ -897,7 +901,7 @@ registration_check_step (GTask *task) task); return; } - mm_dbg (" Skipping HDR check"); + mm_obj_dbg (self, " skipping HDR check"); ctx->step++; /* fall through */ @@ -913,7 +917,7 @@ registration_check_step (GTask *task) task); return; } - mm_dbg (" Skipping CDMA1x Serving System check"); + mm_obj_dbg (self, " skipping CDMA1x serving system check"); ctx->step++; /* fall through */ @@ -923,8 +927,7 @@ registration_check_step (GTask *task) return; case REGISTRATION_CHECK_STEP_AT_CDMA_SERVICE_STATUS: - mm_dbg ("Starting AT-based registration checks"); - + mm_obj_dbg (self, "starting AT-based registration checks"); /* If we don't have means to get service status, just assume we do have * CDMA service and keep on */ if (!ctx->skip_at_cdma_service_status_step && @@ -936,7 +939,7 @@ registration_check_step (GTask *task) task); return; } - mm_dbg (" Skipping CDMA service status check, assuming with service"); + mm_obj_dbg (self, " skipping CDMA service status check, assuming with service"); ctx->step++; /* fall through */ @@ -960,7 +963,7 @@ registration_check_step (GTask *task) task); return; } - mm_dbg (" Skipping CDMA1x Serving System check"); + mm_obj_dbg (self, " skipping CDMA1x Serving System check"); ctx->step++; /* fall through */ @@ -970,7 +973,7 @@ registration_check_step (GTask *task) return; case REGISTRATION_CHECK_STEP_DETAILED_REGISTRATION_STATE: - mm_dbg ("Starting detailed registration state check"); + mm_obj_dbg (self, "starting detailed registration state check"); /* We let classes implementing this interface to look for more detailed * registration info. */ if (!ctx->skip_detailed_registration_state && @@ -988,13 +991,13 @@ registration_check_step (GTask *task) task); return; } - mm_dbg (" Skipping detailed registration state check"); + mm_obj_dbg (self, " skipping detailed registration state check"); ctx->step++; /* fall through */ case REGISTRATION_CHECK_STEP_LAST: /* We are done without errors! */ - mm_dbg ("All CDMA registration state checks done"); + mm_obj_dbg (self, "all CDMA registration state checks done"); mm_iface_modem_cdma_update_cdma1x_registration_state (self, ctx->cdma1x_state, ctx->cdma1x_sid, @@ -1043,9 +1046,9 @@ mm_iface_modem_cdma_run_registration_checks (MMIfaceModemCdma *self, MM_IFACE_MODEM_CDMA_CDMA1X_NETWORK_SUPPORTED, &cdma1x_supported, NULL); - mm_dbg ("Running registration checks (CDMA1x: '%s', EV-DO: '%s')", - cdma1x_supported ? "yes" : "no", - evdo_supported ? "yes" : "no"); + mm_obj_dbg (self, "running registration checks (CDMA1x: '%s', EV-DO: '%s')", + cdma1x_supported ? "yes" : "no", + evdo_supported ? "yes" : "no"); if (MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->run_registration_checks && MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->run_registration_checks_finish) { @@ -1244,7 +1247,7 @@ periodic_registration_checks_ready (MMIfaceModemCdma *self, mm_iface_modem_cdma_run_registration_checks_finish (self, res, &error); if (error) { - mm_dbg ("Couldn't refresh CDMA registration status: '%s'", error->message); + mm_obj_dbg (self, "couldn't refresh CDMA registration status: %s", error->message); g_error_free (error); } @@ -1283,7 +1286,7 @@ periodic_registration_check_disable (MMIfaceModemCdma *self) registration_check_context_quark, NULL); - mm_dbg ("Periodic CDMA registration checks disabled"); + mm_obj_dbg (self, "periodic CDMA registration checks disabled"); } static void @@ -1302,7 +1305,7 @@ periodic_registration_check_enable (MMIfaceModemCdma *self) return; /* Create context and keep it as object data */ - mm_dbg ("Periodic CDMA registration checks enabled"); + mm_obj_dbg (self, "periodic CDMA registration checks enabled"); ctx = g_new0 (RegistrationCheckContext, 1); ctx->timeout_source = g_timeout_add_seconds (REGISTRATION_CHECK_TIMEOUT_SEC, (GSourceFunc)periodic_registration_check, @@ -1339,11 +1342,11 @@ mm_iface_modem_cdma_update_activation_state (MMIfaceModemCdma *self, return; if (activation_error) { - mm_dbg ("Activation failed: %s", activation_error->message); + mm_obj_dbg (self, "activation failed: %s", activation_error->message); if (activation_error->domain == MM_CDMA_ACTIVATION_ERROR) error = activation_error->code; else { - mm_warn ("Error given is not an activation error"); + mm_obj_warn (self, "error given is not an activation error"); error = MM_CDMA_ACTIVATION_ERROR_UNKNOWN; } } @@ -1406,7 +1409,7 @@ disable_unsolicited_events_ready (MMIfaceModemCdma *self, MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->disable_unsolicited_events_finish (self, res, &error); if (error) { - mm_dbg ("Couldn't disable unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't disable unsolicited events: %s", error->message); g_error_free (error); } @@ -1426,7 +1429,7 @@ cleanup_unsolicited_events_ready (MMIfaceModemCdma *self, MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->cleanup_unsolicited_events_finish (self, res, &error); if (error) { - mm_dbg ("Couldn't cleanup unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't cleanup unsolicited events: %s", error->message); g_error_free (error); } @@ -1567,7 +1570,7 @@ setup_unsolicited_events_ready (MMIfaceModemCdma *self, MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->setup_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Setting up unsolicited events failed: '%s'", error->message); + mm_obj_dbg (self, "setting up unsolicited events failed: %s", error->message); g_error_free (error); } @@ -1588,7 +1591,7 @@ enable_unsolicited_events_ready (MMIfaceModemCdma *self, MM_IFACE_MODEM_CDMA_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error); if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Enabling unsolicited events failed: '%s'", error->message); + mm_obj_dbg (self, "enabling unsolicited events failed: %s", error->message); g_error_free (error); } @@ -1733,7 +1736,7 @@ initialization_context_free (InitializationContext *ctx) g_free (val); \ \ if (error) { \ - mm_warn ("couldn't load %s: '%s'", DISPLAY, error->message); \ + mm_obj_warn (self, "couldn't load %s: %s", DISPLAY, error->message); \ g_error_free (error); \ } \ \ @@ -1760,7 +1763,7 @@ load_activation_state_ready (MMIfaceModemCdma *self, mm_gdbus_modem_cdma_set_activation_state (ctx->skeleton, state); if (error) { - mm_warn ("couldn't load activation state: '%s'", error->message); + mm_obj_warn (self, "couldn't load activation state: %s", error->message); g_error_free (error); } diff --git a/src/mm-iface-modem-cdma.h b/src/mm-iface-modem-cdma.h index 9e817dde..7501d897 100644 --- a/src/mm-iface-modem-cdma.h +++ b/src/mm-iface-modem-cdma.h @@ -229,6 +229,7 @@ struct _MMIfaceModemCdma { }; GType mm_iface_modem_cdma_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemCdma, g_object_unref) /* Initialize CDMA interface (async) */ void mm_iface_modem_cdma_initialize (MMIfaceModemCdma *self, diff --git a/src/mm-iface-modem-firmware.c b/src/mm-iface-modem-firmware.c index 8344778a..d363f929 100644 --- a/src/mm-iface-modem-firmware.c +++ b/src/mm-iface-modem-firmware.c @@ -19,7 +19,14 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-firmware.h" -#include "mm-log.h" +#include "mm-log-object.h" + +#if defined WITH_QMI +# include "mm-broadband-modem-qmi.h" +#endif +#if defined WITH_MBIM +# include "mm-broadband-modem-mbim.h" +#endif /*****************************************************************************/ @@ -70,16 +77,19 @@ load_current_ready (MMIfaceModemFirmware *self, handle_list_context_free (ctx); return; } - mm_dbg ("Couldn't load current firmware image: %s", error->message); + mm_obj_dbg (self, "couldn't load current firmware image: %s", error->message); g_clear_error (&error); } /* Build array of dicts */ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); - for (l = ctx->list; l; l = g_list_next (l)) - g_variant_builder_add_value ( - &builder, - mm_firmware_properties_get_dictionary (MM_FIRMWARE_PROPERTIES (l->data))); + for (l = ctx->list; l; l = g_list_next (l)) { + GVariant *dict; + + dict = mm_firmware_properties_get_dictionary (MM_FIRMWARE_PROPERTIES (l->data)); + g_variant_builder_add_value (&builder, dict); + g_variant_unref (dict); + } mm_gdbus_modem_firmware_complete_list ( ctx->skeleton, @@ -104,7 +114,7 @@ load_list_ready (MMIfaceModemFirmware *self, handle_list_context_free (ctx); return; } - mm_dbg ("Couldn't load firmware image list: %s", error->message); + mm_obj_dbg (self, "couldn't load firmware image list: %s", error->message); g_clear_error (&error); } @@ -287,18 +297,23 @@ add_generic_version (MMBaseModem *self, MMFirmwareUpdateSettings *update_settings, GError **error) { - const gchar *firmware_revision; - const gchar *carrier_revision; - gchar *combined; + const gchar *firmware_revision; + const gchar *carrier_revision = NULL; + g_autofree gchar *combined = NULL; + gboolean ignore_carrier = FALSE; firmware_revision = mm_iface_modem_get_revision (MM_IFACE_MODEM (self)); if (!firmware_revision) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown revision"); + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unknown revision"); return FALSE; } - mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), NULL, &carrier_revision); + g_object_get (self, + MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, &ignore_carrier, + NULL); + + if (!ignore_carrier) + mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), NULL, &carrier_revision); if (!carrier_revision) { mm_firmware_update_settings_set_version (update_settings, firmware_revision); @@ -307,7 +322,6 @@ add_generic_version (MMBaseModem *self, combined = g_strdup_printf ("%s - %s", firmware_revision, carrier_revision); mm_firmware_update_settings_set_version (update_settings, combined); - g_free (combined); return TRUE; } @@ -316,53 +330,75 @@ add_generic_device_ids (MMBaseModem *self, MMFirmwareUpdateSettings *update_settings, GError **error) { - guint16 vid; - guint16 pid; - guint16 rid; - GPtrArray *ids; - MMPort *primary = NULL; - const gchar *subsystem; - const gchar *aux; + static const gchar *supported_subsystems[] = { "USB", "PCI" }; + guint16 vid; + guint16 pid; + guint16 rid; + MMPort *primary = NULL; + const gchar *subsystem; + const gchar *carrier_config = NULL; + g_autoptr(GPtrArray) ids = NULL; + guint i; + gboolean ignore_carrier = FALSE; vid = mm_base_modem_get_vendor_id (self); pid = mm_base_modem_get_product_id (self); #if defined WITH_QMI - primary = MM_PORT (mm_base_modem_peek_port_qmi (self)); + if (MM_IS_BROADBAND_MODEM_QMI (self)) + primary = MM_PORT (mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self))); #endif #if defined WITH_MBIM - if (!primary) - primary = MM_PORT (mm_base_modem_peek_port_mbim (self)); + if (!primary && MM_IS_BROADBAND_MODEM_MBIM (self)) + primary = MM_PORT (mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self))); #endif if (!primary) primary = MM_PORT (mm_base_modem_peek_port_primary (self)); g_assert (primary != NULL); rid = mm_kernel_device_get_physdev_revision (mm_port_peek_kernel_device (primary)); + subsystem = mm_kernel_device_get_physdev_subsystem (mm_port_peek_kernel_device (primary)); - if (g_strcmp0 (subsystem, "usb")) { + if (!subsystem) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Unknown device subsystem"); + return FALSE; + } + + for (i = 0; i < G_N_ELEMENTS (supported_subsystems); i++) { + if (g_ascii_strcasecmp (supported_subsystems[i], subsystem) == 0) + break; + } + if (i == G_N_ELEMENTS (supported_subsystems)) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unsupported subsystem: %s", subsystem); return FALSE; } - mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), &aux, NULL); + g_object_get (self, + MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, &ignore_carrier, + NULL); + + if (!ignore_carrier) + mm_iface_modem_get_carrier_config (MM_IFACE_MODEM (self), &carrier_config, NULL); ids = g_ptr_array_new_with_free_func (g_free); - if (aux) { - gchar *carrier; + if (carrier_config) { + g_autofree gchar *carrier = NULL; - carrier = g_ascii_strup (aux, -1); - g_ptr_array_add (ids, g_strdup_printf ("USB\\VID_%04X&PID_%04X&REV_%04X&CARRIER_%s", vid, pid, rid, carrier)); - g_free (carrier); + carrier = g_ascii_strup (carrier_config, -1); + g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X&REV_%04X&CARRIER_%s", + supported_subsystems[i], vid, pid, rid, carrier)); } - g_ptr_array_add (ids, g_strdup_printf ("USB\\VID_%04X&PID_%04X&REV_%04X", vid, pid, rid)); - g_ptr_array_add (ids, g_strdup_printf ("USB\\VID_%04X&PID_%04X", vid, pid)); - g_ptr_array_add (ids, g_strdup_printf ("USB\\VID_%04X", vid)); + g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X&REV_%04X", + supported_subsystems[i], vid, pid, rid)); + g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X&PID_%04X", + supported_subsystems[i], vid, pid)); + g_ptr_array_add (ids, g_strdup_printf ("%s\\VID_%04X", + supported_subsystems[i], vid)); g_ptr_array_add (ids, NULL); mm_firmware_update_settings_set_device_ids (update_settings, (const gchar **)ids->pdata); - g_ptr_array_unref (ids); return TRUE; } @@ -380,7 +416,7 @@ load_update_settings_ready (MMIfaceModemFirmware *self, update_settings = MM_IFACE_MODEM_FIRMWARE_GET_INTERFACE (self)->load_update_settings_finish (self, res, &error); if (!update_settings) { - mm_dbg ("Couldn't load update settings: '%s'", error->message); + mm_obj_dbg (self, "couldn't load update settings: %s", error->message); g_error_free (error); goto out; } @@ -388,7 +424,7 @@ load_update_settings_ready (MMIfaceModemFirmware *self, /* If the plugin didn't specify custom device ids, add the default ones ourselves */ if (!mm_firmware_update_settings_get_device_ids (update_settings) && !add_generic_device_ids (MM_BASE_MODEM (self), update_settings, &error)) { - mm_warn ("Couldn't build device ids: '%s'", error->message); + mm_obj_warn (self, "couldn't build device ids: %s", error->message); g_error_free (error); g_clear_object (&update_settings); goto out; @@ -397,7 +433,7 @@ load_update_settings_ready (MMIfaceModemFirmware *self, /* If the plugin didn't specify custom version, add the default one ourselves */ if (!mm_firmware_update_settings_get_version (update_settings) && !add_generic_version (MM_BASE_MODEM (self), update_settings, &error)) { - mm_warn ("Couldn't set version: '%s'", error->message); + mm_obj_warn (self, "couldn't set version: %s", error->message); g_error_free (error); g_clear_object (&update_settings); goto out; @@ -536,6 +572,14 @@ iface_modem_firmware_init (gpointer g_iface) MM_GDBUS_TYPE_MODEM_FIRMWARE_SKELETON, G_PARAM_READWRITE)); + g_object_interface_install_property + (g_iface, + g_param_spec_boolean (MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER, + "Ignore carrier info in firmware details", + "Whether carrier info (version, name) should be ignored when showing the firmware details", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + initialized = TRUE; } diff --git a/src/mm-iface-modem-firmware.h b/src/mm-iface-modem-firmware.h index 15052bce..365bfb15 100644 --- a/src/mm-iface-modem-firmware.h +++ b/src/mm-iface-modem-firmware.h @@ -27,7 +27,8 @@ #define MM_IS_IFACE_MODEM_FIRMWARE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_IFACE_MODEM_FIRMWARE)) #define MM_IFACE_MODEM_FIRMWARE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_IFACE_MODEM_FIRMWARE, MMIfaceModemFirmware)) -#define MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON "iface-modem-firmware-dbus-skeleton" +#define MM_IFACE_MODEM_FIRMWARE_DBUS_SKELETON "iface-modem-firmware-dbus-skeleton" +#define MM_IFACE_MODEM_FIRMWARE_IGNORE_CARRIER "iface-modem-firmware-ignore-carrier" typedef struct _MMIfaceModemFirmware MMIfaceModemFirmware; @@ -69,6 +70,7 @@ struct _MMIfaceModemFirmware { }; GType mm_iface_modem_firmware_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemFirmware, g_object_unref) /* Initialize Firmware interface (async) */ void mm_iface_modem_firmware_initialize (MMIfaceModemFirmware *self, diff --git a/src/mm-iface-modem-location.c b/src/mm-iface-modem-location.c index 9a85c9e8..b45a3405 100644 --- a/src/mm-iface-modem-location.c +++ b/src/mm-iface-modem-location.c @@ -21,7 +21,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-location.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-modem-helpers.h" #define MM_LOCATION_GPS_REFRESH_TIME_SECS 30 @@ -235,11 +235,7 @@ notify_gps_location_update (MMIfaceModemLocation *self, MMLocationGpsNmea *location_gps_nmea, MMLocationGpsRaw *location_gps_raw) { - const gchar *dbus_path; - - dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self)); - mm_dbg ("Modem %s: GPS location updated", - dbus_path); + mm_obj_dbg (self, "GPS location updated"); /* We only update the property if we are supposed to signal * location */ @@ -273,7 +269,7 @@ location_gps_update_nmea (MMIfaceModemLocation *self, g_assert (ctx->location_gps_nmea != NULL); if (mm_location_gps_nmea_add_trace (ctx->location_gps_nmea, nmea_trace) && (ctx->location_gps_nmea_last_time == 0 || - time (NULL) - ctx->location_gps_nmea_last_time >= mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { + time (NULL) - ctx->location_gps_nmea_last_time >= (glong)mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { ctx->location_gps_nmea_last_time = time (NULL); update_nmea = TRUE; } @@ -283,7 +279,7 @@ location_gps_update_nmea (MMIfaceModemLocation *self, g_assert (ctx->location_gps_raw != NULL); if (mm_location_gps_raw_add_trace (ctx->location_gps_raw, nmea_trace) && (ctx->location_gps_raw_last_time == 0 || - time (NULL) - ctx->location_gps_raw_last_time >= mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { + time (NULL) - ctx->location_gps_raw_last_time >= (glong)mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { ctx->location_gps_raw_last_time = time (NULL); update_raw = TRUE; } @@ -322,7 +318,7 @@ mm_iface_modem_location_gps_update (MMIfaceModemLocation *self, g_autoptr(GString) str = NULL; g_autoptr(GDateTime) now = NULL; - mm_dbg ("GGA trace detected: '%s'", nmea_trace); + mm_obj_dbg (self, "GGA trace detected: %s", nmea_trace); now = g_date_time_new_now_utc (); str = g_string_new (""); @@ -349,17 +345,13 @@ notify_3gpp_location_update (MMIfaceModemLocation *self, MmGdbusModemLocation *skeleton, MMLocation3gpp *location_3gpp) { - const gchar *dbus_path; - - dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self)); - mm_dbg ("Modem %s: 3GPP location updated " - "(MCC: '%u', MNC: '%u', Location area code: '%lX', Tracking area code: '%lX', Cell ID: '%lX')", - dbus_path, - mm_location_3gpp_get_mobile_country_code (location_3gpp), - mm_location_3gpp_get_mobile_network_code (location_3gpp), - mm_location_3gpp_get_location_area_code (location_3gpp), - mm_location_3gpp_get_tracking_area_code (location_3gpp), - mm_location_3gpp_get_cell_id (location_3gpp)); + mm_obj_dbg (self, "3GPP location updated " + "(MCC: '%u', MNC: '%u', location area code: '%lX', tracking area code: '%lX', cell ID: '%lX')", + mm_location_3gpp_get_mobile_country_code (location_3gpp), + mm_location_3gpp_get_mobile_network_code (location_3gpp), + mm_location_3gpp_get_location_area_code (location_3gpp), + mm_location_3gpp_get_tracking_area_code (location_3gpp), + mm_location_3gpp_get_cell_id (location_3gpp)); /* We only update the property if we are supposed to signal * location */ @@ -404,32 +396,70 @@ mm_iface_modem_location_3gpp_update_mcc_mnc (MMIfaceModemLocation *self, void mm_iface_modem_location_3gpp_update_lac_tac_ci (MMIfaceModemLocation *self, - gulong location_area_code, - gulong tracking_area_code, - gulong cell_id) + gulong location_area_code, + gulong tracking_area_code, + gulong cell_id) { - MmGdbusModemLocation *skeleton; - LocationContext *ctx; + g_autoptr(MmGdbusModemLocationSkeleton) skeleton = NULL; + LocationContext *ctx; + guint changed = 0; + gulong old_location_area_code; + gulong old_tracking_area_code; + gulong old_cell_id; - ctx = get_location_context (self); g_object_get (self, MM_IFACE_MODEM_LOCATION_DBUS_SKELETON, &skeleton, NULL); - if (!skeleton) + if (!skeleton || !(mm_gdbus_modem_location_get_enabled (MM_GDBUS_MODEM_LOCATION (skeleton)) & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI)) return; - if (mm_gdbus_modem_location_get_enabled (skeleton) & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI) { - guint changed = 0; + ctx = get_location_context (self); + g_assert (ctx->location_3gpp != NULL); + + old_location_area_code = mm_location_3gpp_get_location_area_code (ctx->location_3gpp); + old_tracking_area_code = mm_location_3gpp_get_tracking_area_code (ctx->location_3gpp); + old_cell_id = mm_location_3gpp_get_cell_id (ctx->location_3gpp); + + /* Update LAC if given, and clear TAC unless a TAC is also given */ + if (location_area_code) { + if (old_location_area_code != location_area_code) { + mm_obj_dbg (self, "3GPP location area code updated: '%lX->%lX'", old_location_area_code, location_area_code); + mm_location_3gpp_set_location_area_code (ctx->location_3gpp, location_area_code); + changed++; + } + if (!tracking_area_code) { + if (old_tracking_area_code != 0) { + mm_obj_dbg (self, "3GPP tracking area code cleared: '%lX->%lX'", old_tracking_area_code, tracking_area_code); + mm_location_3gpp_set_tracking_area_code (ctx->location_3gpp, 0); + changed++; + } + } + } + /* Update TAC if given, and clear LAC unless a LAC is also given */ + if (tracking_area_code) { + if (old_tracking_area_code != tracking_area_code) { + mm_obj_dbg (self, "3GPP tracking area code updated: '%lX->%lX'", old_tracking_area_code, tracking_area_code); + mm_location_3gpp_set_tracking_area_code (ctx->location_3gpp, tracking_area_code); + changed++; + } + if (!location_area_code) { + if (old_location_area_code != 0) { + mm_obj_dbg (self, "3GPP location area code cleared: '%lX->%lX'", old_location_area_code, location_area_code); + mm_location_3gpp_set_location_area_code (ctx->location_3gpp, 0); + changed++; + } + } + } - g_assert (ctx->location_3gpp != NULL); - changed += mm_location_3gpp_set_location_area_code (ctx->location_3gpp, location_area_code); - changed += mm_location_3gpp_set_tracking_area_code (ctx->location_3gpp, tracking_area_code); - changed += mm_location_3gpp_set_cell_id (ctx->location_3gpp, cell_id); - if (changed) - notify_3gpp_location_update (self, skeleton, ctx->location_3gpp); + /* Cell ID only updated if given. It is assumed that if LAC or TAC are given, CID is also given */ + if (cell_id && (old_cell_id != cell_id)) { + mm_obj_dbg (self, "3GPP cell id updated: '%lX->%lX'", old_cell_id, cell_id); + mm_location_3gpp_set_cell_id (ctx->location_3gpp, cell_id); + changed++; } - g_object_unref (skeleton); + if (changed) + notify_3gpp_location_update (self, MM_GDBUS_MODEM_LOCATION (skeleton), ctx->location_3gpp); } void @@ -461,14 +491,9 @@ notify_cdma_bs_location_update (MMIfaceModemLocation *self, MmGdbusModemLocation *skeleton, MMLocationCdmaBs *location_cdma_bs) { - const gchar *dbus_path; - - dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self)); - mm_dbg ("Modem %s: CDMA BS location updated " - "(Longitude: '%lf', Latitude: '%lf')", - dbus_path, - mm_location_cdma_bs_get_longitude (location_cdma_bs), - mm_location_cdma_bs_get_latitude (location_cdma_bs)); + mm_obj_dbg (self, "CDMA base station location updated (longitude: '%lf', latitude: '%lf')", + mm_location_cdma_bs_get_longitude (location_cdma_bs), + mm_location_cdma_bs_get_latitude (location_cdma_bs)); /* We only update the property if we are supposed to signal * location */ @@ -712,7 +737,7 @@ setup_gathering_step (GTask *task) } source_str = mm_modem_location_source_build_string_from_mask (ctx->current); - mm_dbg ("Enabled location '%s' gathering...", source_str); + mm_obj_dbg (self, "enabled location '%s' gathering...", source_str); g_free (source_str); } else if (ctx->to_disable & ctx->current) { /* Remove from mask */ @@ -732,7 +757,7 @@ setup_gathering_step (GTask *task) } source_str = mm_modem_location_source_build_string_from_mask (ctx->current); - mm_dbg ("Disabled location '%s' gathering...", source_str); + mm_obj_dbg (self, "disabled location '%s' gathering...", source_str); g_free (source_str); } @@ -797,7 +822,7 @@ setup_gathering (MMIfaceModemLocation *self, if (mask & source) { /* Source set in mask, need to enable if disabled */ if (currently_enabled & source) - mm_dbg ("Location '%s' gathering is already enabled...", str); + mm_obj_dbg (self, "location '%s' gathering is already enabled...", str); else ctx->to_enable |= source; } else { @@ -805,7 +830,7 @@ setup_gathering (MMIfaceModemLocation *self, if (currently_enabled & source) ctx->to_disable |= source; else - mm_dbg ("Location '%s' gathering is already disabled...", str); + mm_obj_dbg (self, "location '%s' gathering is already disabled...", str); } g_free (str); @@ -847,13 +872,13 @@ setup_gathering (MMIfaceModemLocation *self, if (ctx->to_enable != MM_MODEM_LOCATION_SOURCE_NONE) { str = mm_modem_location_source_build_string_from_mask (ctx->to_enable); - mm_dbg ("Need to enable the following location sources: '%s'", str); + mm_obj_dbg (self, "need to enable the following location sources: '%s'", str); g_free (str); } if (ctx->to_disable != MM_MODEM_LOCATION_SOURCE_NONE) { str = mm_modem_location_source_build_string_from_mask (ctx->to_disable); - mm_dbg ("Need to disable the following location sources: '%s'", str); + mm_obj_dbg (self, "need to disable the following location sources: '%s'", str); g_free (str); } @@ -944,8 +969,8 @@ handle_setup_auth_ready (MMBaseModem *self, /* Enable/disable location signaling */ location_ctx = get_location_context (ctx->self); if (mm_gdbus_modem_location_get_signals_location (ctx->skeleton) != ctx->signal_location) { - mm_dbg ("%s location signaling", - ctx->signal_location ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s location signaling", + ctx->signal_location ? "enabling" : "disabling"); mm_gdbus_modem_location_set_signals_location (ctx->skeleton, ctx->signal_location); if (ctx->signal_location) @@ -963,7 +988,7 @@ handle_setup_auth_ready (MMBaseModem *self, } str = mm_modem_location_source_build_string_from_mask (ctx->sources); - mm_dbg ("Setting up location sources: '%s'", str); + mm_obj_dbg (self, "setting up location sources: '%s'", str); g_free (str); /* Go on to enable or disable the requested sources */ @@ -1674,7 +1699,7 @@ load_assistance_data_servers_ready (MMIfaceModemLocation *self, servers = MM_IFACE_MODEM_LOCATION_GET_INTERFACE (self)->load_assistance_data_servers_finish (self, res, &error); if (error) { - mm_warn ("couldn't load assistance data servers: '%s'", error->message); + mm_obj_warn (self, "couldn't load assistance data servers: %s", error->message); g_error_free (error); } @@ -1699,7 +1724,7 @@ load_supported_assistance_data_ready (MMIfaceModemLocation *self, mask = MM_IFACE_MODEM_LOCATION_GET_INTERFACE (self)->load_supported_assistance_data_finish (self, res, &error); if (error) { - mm_warn ("couldn't load supported assistance data types: '%s'", error->message); + mm_obj_warn (self, "couldn't load supported assistance data types: %s", error->message); g_error_free (error); } @@ -1723,7 +1748,7 @@ load_supl_server_ready (MMIfaceModemLocation *self, supl = MM_IFACE_MODEM_LOCATION_GET_INTERFACE (self)->load_supl_server_finish (self, res, &error); if (error) { - mm_warn ("couldn't load SUPL server: '%s'", error->message); + mm_obj_warn (self, "couldn't load SUPL server: %s", error->message); g_error_free (error); } @@ -1747,7 +1772,7 @@ load_capabilities_ready (MMIfaceModemLocation *self, ctx->capabilities = MM_IFACE_MODEM_LOCATION_GET_INTERFACE (self)->load_capabilities_finish (self, res, &error); if (error) { - mm_warn ("couldn't load location capabilities: '%s'", error->message); + mm_obj_warn (self, "couldn't load location capabilities: %s", error->message); g_error_free (error); } diff --git a/src/mm-iface-modem-location.h b/src/mm-iface-modem-location.h index c8b045af..d00ecc71 100644 --- a/src/mm-iface-modem-location.h +++ b/src/mm-iface-modem-location.h @@ -106,6 +106,7 @@ struct _MMIfaceModemLocation { }; GType mm_iface_modem_location_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemLocation, g_object_unref) /* Initialize Location interface (async) */ void mm_iface_modem_location_initialize (MMIfaceModemLocation *self, diff --git a/src/mm-iface-modem-messaging.c b/src/mm-iface-modem-messaging.c index 02e6a769..f9c2c98b 100644 --- a/src/mm-iface-modem-messaging.c +++ b/src/mm-iface-modem-messaging.c @@ -20,7 +20,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-messaging.h" #include "mm-sms-list.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "messaging-support-checked-tag" #define SUPPORTED_TAG "messaging-supported-tag" @@ -410,29 +410,27 @@ handle_list (MmGdbusModemMessaging *skeleton, gboolean mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self, - MMSmsPart *sms_part, - MMSmsState state, - MMSmsStorage storage) + MMSmsPart *sms_part, + MMSmsState state, + MMSmsStorage storage) { - MMSmsList *list = NULL; - GError *error = NULL; - gboolean added; + g_autoptr(MMSmsList) list = NULL; + g_autoptr(GError) error = NULL; + gboolean added = FALSE; g_object_get (self, MM_IFACE_MODEM_MESSAGING_SMS_LIST, &list, NULL); - if (!list) - return FALSE; - added = mm_sms_list_take_part (list, sms_part, state, storage, &error); - if (!added) { - mm_dbg ("Couldn't take part in SMS list: '%s'", error->message); - g_error_free (error); + if (list) { + added = mm_sms_list_take_part (list, sms_part, state, storage, &error); + if (!added) + mm_obj_dbg (self, "couldn't take part in SMS list: %s", error->message); + } - /* If part wasn't taken, we need to free the part ourselves */ + /* If part wasn't taken, we need to free the part ourselves */ + if (!added) mm_sms_part_free (sms_part); - } - g_object_unref (list); return added; } @@ -503,24 +501,20 @@ update_message_list (MmGdbusModemMessaging *skeleton, } static void -sms_added (MMSmsList *list, - const gchar *sms_path, - gboolean received, +sms_added (MMSmsList *list, + const gchar *sms_path, + gboolean received, MmGdbusModemMessaging *skeleton) { - mm_dbg ("Added %s SMS at '%s'", - received ? "received" : "local", - sms_path); update_message_list (skeleton, list); mm_gdbus_modem_messaging_emit_added (skeleton, sms_path, received); } static void -sms_deleted (MMSmsList *list, - const gchar *sms_path, +sms_deleted (MMSmsList *list, + const gchar *sms_path, MmGdbusModemMessaging *skeleton) { - mm_dbg ("Deleted SMS at '%s'", sms_path); update_message_list (skeleton, list); mm_gdbus_modem_messaging_emit_deleted (skeleton, sms_path); } @@ -762,11 +756,11 @@ load_initial_sms_parts_ready (MMIfaceModemMessaging *self, StorageContext *storage_ctx; storage_ctx = get_storage_context (self); - mm_dbg ("Couldn't load SMS parts from storage '%s': '%s'", - mm_sms_storage_get_string (g_array_index (storage_ctx->supported_mem1, - MMSmsStorage, - ctx->mem1_storage_index)), - error->message); + mm_obj_dbg (self, "couldn't load SMS parts from storage '%s': %s", + mm_sms_storage_get_string (g_array_index (storage_ctx->supported_mem1, + MMSmsStorage, + ctx->mem1_storage_index)), + error->message); g_error_free (error); } @@ -784,7 +778,7 @@ set_default_storage_ready (MMIfaceModemMessaging *self, GError *error = NULL; if (!MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->set_default_storage_finish (self, res, &error)) { - mm_warn ("Could not set default storage: '%s'", error->message); + mm_obj_warn (self, "could not set default storage: %s", error->message); g_error_free (error); } @@ -866,7 +860,7 @@ enable_unsolicited_events_ready (MMIfaceModemMessaging *self, /* Not critical! */ if (!MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Couldn't enable unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't enable unsolicited events: %s", error->message); g_error_free (error); } @@ -989,7 +983,7 @@ interface_enabling_step (GTask *task) NULL); if (default_storage == MM_SMS_STORAGE_UNKNOWN) - mm_info ("Cannot set default storage, none of the suggested ones supported"); + mm_obj_warn (self, "cannot set default storage, none of the suggested ones supported"); else if (MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->set_default_storage && MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->set_default_storage_finish) { MM_IFACE_MODEM_MESSAGING_GET_INTERFACE (self)->set_default_storage ( @@ -1141,7 +1135,7 @@ load_supported_storages_ready (MMIfaceModemMessaging *self, &storage_ctx->supported_mem2, &storage_ctx->supported_mem3, &error)) { - mm_dbg ("Couldn't load supported storages: '%s'", error->message); + mm_obj_dbg (self, "couldn't load supported storages: %s", error->message); g_error_free (error); } else { gchar *mem1; @@ -1155,17 +1149,17 @@ load_supported_storages_ready (MMIfaceModemMessaging *self, skip_unknown_storages (storage_ctx->supported_mem2); skip_unknown_storages (storage_ctx->supported_mem3); - mem1 = mm_common_build_sms_storages_string ((MMSmsStorage *)storage_ctx->supported_mem1->data, + mem1 = mm_common_build_sms_storages_string ((MMSmsStorage *)(gpointer)storage_ctx->supported_mem1->data, storage_ctx->supported_mem1->len); - mem2 = mm_common_build_sms_storages_string ((MMSmsStorage *)storage_ctx->supported_mem2->data, + mem2 = mm_common_build_sms_storages_string ((MMSmsStorage *)(gpointer)storage_ctx->supported_mem2->data, storage_ctx->supported_mem2->len); - mem3 = mm_common_build_sms_storages_string ((MMSmsStorage *)storage_ctx->supported_mem3->data, + mem3 = mm_common_build_sms_storages_string ((MMSmsStorage *)(gpointer)storage_ctx->supported_mem3->data, storage_ctx->supported_mem3->len); - mm_dbg ("Supported storages loaded:"); - mm_dbg (" mem1 (list/read/delete) storages: '%s'", mem1); - mm_dbg (" mem2 (write/send) storages: '%s'", mem2); - mm_dbg (" mem3 (reception) storages: '%s'", mem3); + mm_obj_dbg (self, "supported storages loaded:"); + mm_obj_dbg (self, " mem1 (list/read/delete) storages: '%s'", mem1); + mm_obj_dbg (self, " mem2 (write/send) storages: '%s'", mem2); + mm_obj_dbg (self, " mem3 (reception) storages: '%s'", mem3); g_free (mem1); g_free (mem2); g_free (mem3); @@ -1215,7 +1209,7 @@ check_support_ready (MMIfaceModemMessaging *self, &error)) { if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Messaging support check failed: '%s'", error->message); + mm_obj_dbg (self, "messaging support check failed: %s", error->message); g_error_free (error); } } else { @@ -1243,11 +1237,10 @@ init_current_storages_ready (MMIfaceModemMessaging *self, self, res, &error)) { - mm_dbg ("Couldn't initialize current storages: '%s'", error->message); + mm_obj_dbg (self, "couldn't initialize current storages: %s", error->message); g_error_free (error); - } else { - mm_dbg ("Current storages initialized"); - } + } else + mm_obj_dbg (self, "current storages initialized"); /* Go on to next step */ ctx = g_task_get_task_data (task); diff --git a/src/mm-iface-modem-messaging.h b/src/mm-iface-modem-messaging.h index 57fa4521..64dfb2b1 100644 --- a/src/mm-iface-modem-messaging.h +++ b/src/mm-iface-modem-messaging.h @@ -134,6 +134,7 @@ struct _MMIfaceModemMessaging { }; GType mm_iface_modem_messaging_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemMessaging, g_object_unref) /* Initialize Messaging interface (async) */ void mm_iface_modem_messaging_initialize (MMIfaceModemMessaging *self, diff --git a/src/mm-iface-modem-oma.c b/src/mm-iface-modem-oma.c index cf3a7a30..cc796b88 100644 --- a/src/mm-iface-modem-oma.c +++ b/src/mm-iface-modem-oma.c @@ -19,7 +19,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-oma.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "oma-support-checked-tag" #define SUPPORTED_TAG "oma-supported-tag" @@ -124,10 +124,9 @@ mm_iface_modem_oma_update_session_state (MMIfaceModemOma *self, old_session_state = mm_gdbus_modem_oma_get_session_state (skeleton); if (old_session_state != new_session_state) { - mm_info ("Modem %s: OMA session state changed (%s -> %s)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self)), - mm_oma_session_state_get_string (old_session_state), - mm_oma_session_state_get_string (new_session_state)); + mm_obj_info (self, "OMA session state changed (%s -> %s)", + mm_oma_session_state_get_string (old_session_state), + mm_oma_session_state_get_string (new_session_state)); /* Flush current change before signaling the state change, * so that clients get the proper state already in the @@ -220,7 +219,7 @@ handle_setup_auth_ready (MMBaseModem *self, } str = mm_oma_feature_build_string_from_mask (ctx->features); - mm_dbg ("Setting up OMA features: '%s'", str); + mm_obj_dbg (self, "setting up OMA features: '%s'", str); g_free (str); MM_IFACE_MODEM_OMA_GET_INTERFACE (ctx->self)->setup ( @@ -342,8 +341,8 @@ handle_start_client_initiated_session_auth_ready (MMBaseModem *self, return; } - mm_dbg ("Starting client-initiated OMA session (%s)", - mm_oma_session_type_get_string (ctx->session_type)); + mm_obj_dbg (self, "starting client-initiated OMA session (%s)", + mm_oma_session_type_get_string (ctx->session_type)); MM_IFACE_MODEM_OMA_GET_INTERFACE (ctx->self)->start_client_initiated_session ( ctx->self, ctx->session_type, @@ -501,10 +500,10 @@ handle_accept_network_initiated_session_auth_ready (MMBaseModem *self, return; } - mm_dbg ("%s network-initiated OMA session (%s, %u)", - ctx->accept ? "Accepting" : "Rejecting", - mm_oma_session_type_get_string (ctx->session_type), - ctx->session_id); + mm_obj_dbg (self, "%s network-initiated OMA session (%s, %u)", + ctx->accept ? "accepting" : "rejecting", + mm_oma_session_type_get_string (ctx->session_type), + ctx->session_id); MM_IFACE_MODEM_OMA_GET_INTERFACE (ctx->self)->accept_network_initiated_session ( ctx->self, ctx->session_id, @@ -615,7 +614,7 @@ handle_cancel_session_auth_ready (MMBaseModem *self, return; } - mm_dbg ("Cancelling OMA session"); + mm_obj_dbg (self, "cancelling OMA session"); MM_IFACE_MODEM_OMA_GET_INTERFACE (ctx->self)->cancel_session ( ctx->self, (GAsyncReadyCallback)cancel_session_ready, @@ -890,7 +889,7 @@ enable_unsolicited_events_ready (MMIfaceModemOma *self, /* Not critical! */ if (!MM_IFACE_MODEM_OMA_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Couldn't enable unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't enable unsolicited events: %s", error->message); g_error_free (error); } @@ -1036,7 +1035,7 @@ check_support_ready (MMIfaceModemOma *self, if (!MM_IFACE_MODEM_OMA_GET_INTERFACE (self)->check_support_finish (self, res, &error)) { if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("OMA support check failed: '%s'", error->message); + mm_obj_dbg (self, "OMA support check failed: %s", error->message); g_error_free (error); } } else { diff --git a/src/mm-iface-modem-oma.h b/src/mm-iface-modem-oma.h index 94b16e1d..8117ebe6 100644 --- a/src/mm-iface-modem-oma.h +++ b/src/mm-iface-modem-oma.h @@ -120,6 +120,7 @@ struct _MMIfaceModemOma { }; GType mm_iface_modem_oma_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemOma, g_object_unref) /* Initialize Oma interface (async) */ void mm_iface_modem_oma_initialize (MMIfaceModemOma *self, diff --git a/src/mm-iface-modem-signal.c b/src/mm-iface-modem-signal.c index 396ce688..25d0840c 100644 --- a/src/mm-iface-modem-signal.c +++ b/src/mm-iface-modem-signal.c @@ -19,7 +19,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-signal.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "signal-support-checked-tag" #define SUPPORTED_TAG "signal-supported-tag" @@ -55,7 +55,7 @@ refresh_context_free (RefreshContext *ctx) static void clear_values (MMIfaceModemSignal *self) { - MmGdbusModemSignal *skeleton; + g_autoptr(MmGdbusModemSignalSkeleton) skeleton = NULL; g_object_get (self, MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton, @@ -63,26 +63,32 @@ clear_values (MMIfaceModemSignal *self) if (!skeleton) return; - mm_gdbus_modem_signal_set_cdma (skeleton, NULL); - mm_gdbus_modem_signal_set_evdo (skeleton, NULL); - mm_gdbus_modem_signal_set_gsm (skeleton, NULL); - mm_gdbus_modem_signal_set_umts (skeleton, NULL); - mm_gdbus_modem_signal_set_lte (skeleton, NULL); - g_object_unref (skeleton); + mm_gdbus_modem_signal_set_cdma (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); + mm_gdbus_modem_signal_set_evdo (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); + mm_gdbus_modem_signal_set_gsm (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); + mm_gdbus_modem_signal_set_umts (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); + mm_gdbus_modem_signal_set_lte (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); + mm_gdbus_modem_signal_set_nr5g (MM_GDBUS_MODEM_SIGNAL (skeleton), NULL); } static void load_values_ready (MMIfaceModemSignal *self, - GAsyncResult *res) + GAsyncResult *res) { - GVariant *dictionary; - GError *error = NULL; - MMSignal *cdma = NULL; - MMSignal *evdo = NULL; - MMSignal *gsm = NULL; - MMSignal *umts = NULL; - MMSignal *lte = NULL; - MmGdbusModemSignal *skeleton; + g_autoptr(GError) error = NULL; + g_autoptr(MMSignal) cdma = NULL; + g_autoptr(GVariant) dict_cdma = NULL; + g_autoptr(MMSignal) evdo = NULL; + g_autoptr(GVariant) dict_evdo = NULL; + g_autoptr(MMSignal) gsm = NULL; + g_autoptr(GVariant) dict_gsm = NULL; + g_autoptr(MMSignal) umts = NULL; + g_autoptr(GVariant) dict_umts = NULL; + g_autoptr(MMSignal) lte = NULL; + g_autoptr(GVariant) dict_lte = NULL; + g_autoptr(MMSignal) nr5g = NULL; + g_autoptr(GVariant) dict_nr5g = NULL; + g_autoptr(MmGdbusModemSignalSkeleton) skeleton = NULL; if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->load_values_finish ( self, @@ -92,9 +98,9 @@ load_values_ready (MMIfaceModemSignal *self, &gsm, &umts, <e, + &nr5g, &error)) { - mm_warn ("Couldn't load extended signal information: %s", error->message); - g_error_free (error); + mm_obj_warn (self, "couldn't load extended signal information: %s", error->message); clear_values (self); return; } @@ -103,55 +109,36 @@ load_values_ready (MMIfaceModemSignal *self, MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, &skeleton, NULL); if (!skeleton) { - mm_warn ("Cannot update extended signal information: " - "Couldn't get interface skeleton"); + mm_obj_warn (self, "cannot update extended signal information: couldn't get interface skeleton"); return; } - if (cdma) { - dictionary = mm_signal_get_dictionary (cdma); - mm_gdbus_modem_signal_set_cdma (skeleton, dictionary); - g_variant_unref (dictionary); - g_object_unref (cdma); - } else - mm_gdbus_modem_signal_set_cdma (skeleton, NULL); - - if (evdo) { - dictionary = mm_signal_get_dictionary (evdo); - mm_gdbus_modem_signal_set_evdo (skeleton, dictionary); - g_variant_unref (dictionary); - g_object_unref (evdo); - } else - mm_gdbus_modem_signal_set_evdo (skeleton, NULL); - - if (gsm) { - dictionary = mm_signal_get_dictionary (gsm); - mm_gdbus_modem_signal_set_gsm (skeleton, dictionary); - g_variant_unref (dictionary); - g_object_unref (gsm); - } else - mm_gdbus_modem_signal_set_gsm (skeleton, NULL); - - if (umts) { - dictionary = mm_signal_get_dictionary (umts); - mm_gdbus_modem_signal_set_umts (skeleton, dictionary); - g_variant_unref (dictionary); - g_object_unref (umts); - } else - mm_gdbus_modem_signal_set_umts (skeleton, NULL); - - if (lte) { - dictionary = mm_signal_get_dictionary (lte); - mm_gdbus_modem_signal_set_lte (skeleton, dictionary); - g_variant_unref (dictionary); - g_object_unref (lte); - } else - mm_gdbus_modem_signal_set_lte (skeleton, NULL); + if (cdma) + dict_cdma = mm_signal_get_dictionary (cdma); + mm_gdbus_modem_signal_set_cdma (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_cdma); + + if (evdo) + dict_evdo = mm_signal_get_dictionary (evdo); + mm_gdbus_modem_signal_set_evdo (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_evdo); + + if (gsm) + dict_gsm = mm_signal_get_dictionary (gsm); + mm_gdbus_modem_signal_set_gsm (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_gsm); + + if (umts) + dict_umts = mm_signal_get_dictionary (umts); + mm_gdbus_modem_signal_set_umts (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_umts); + + if (lte) + dict_lte = mm_signal_get_dictionary (lte); + mm_gdbus_modem_signal_set_lte (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_lte); + + if (nr5g) + dict_nr5g = mm_signal_get_dictionary (nr5g); + mm_gdbus_modem_signal_set_nr5g (MM_GDBUS_MODEM_SIGNAL (skeleton), dict_nr5g); /* Flush right away */ g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton)); - - g_object_unref (skeleton); } static gboolean @@ -172,7 +159,7 @@ teardown_refresh_context (MMIfaceModemSignal *self) if (G_UNLIKELY (!refresh_context_quark)) refresh_context_quark = g_quark_from_static_string (REFRESH_CONTEXT_TAG); if (g_object_get_qdata (G_OBJECT (self), refresh_context_quark)) { - mm_dbg ("Extended signal information reporting disabled"); + mm_obj_dbg (self, "extended signal information reporting disabled"); g_object_set_qdata (G_OBJECT (self), refresh_context_quark, NULL); } } @@ -210,14 +197,14 @@ setup_refresh_context (MMIfaceModemSignal *self, /* User disabling? */ if (new_rate == 0) { - mm_dbg ("Extended signal information reporting disabled (rate: 0 seconds)"); + mm_obj_dbg (self, "extended signal information reporting disabled (rate: 0 seconds)"); clear_values (self); g_object_set_qdata (G_OBJECT (self), refresh_context_quark, NULL); return TRUE; } if (modem_state < MM_MODEM_STATE_ENABLING) { - mm_dbg ("Extended signal information reporting disabled (modem not yet enabled)"); + mm_obj_dbg (self, "extended signal information reporting disabled (modem not yet enabled)"); return TRUE; } @@ -238,7 +225,7 @@ setup_refresh_context (MMIfaceModemSignal *self, } /* Update refresh context */ - mm_dbg ("Extended signal information reporting enabled (rate: %u seconds)", new_rate); + mm_obj_dbg (self, "extended signal information reporting enabled (rate: %u seconds)", new_rate); ctx->rate = new_rate; if (ctx->timeout_source) g_source_remove (ctx->timeout_source); @@ -402,7 +389,7 @@ check_support_ready (MMIfaceModemSignal *self, if (!MM_IFACE_MODEM_SIGNAL_GET_INTERFACE (self)->check_support_finish (self, res, &error)) { if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Extended signal support check failed: '%s'", error->message); + mm_obj_dbg (self, "extended signal support check failed: %s", error->message); g_error_free (error); } } else { @@ -525,7 +512,6 @@ mm_iface_modem_signal_initialize (MMIfaceModemSignal *self, NULL); if (!skeleton) { skeleton = mm_gdbus_modem_signal_skeleton_new (); - clear_values (self); g_object_set (self, MM_IFACE_MODEM_SIGNAL_DBUS_SKELETON, skeleton, NULL); diff --git a/src/mm-iface-modem-signal.h b/src/mm-iface-modem-signal.h index 1d49e5f3..dd7a6685 100644 --- a/src/mm-iface-modem-signal.h +++ b/src/mm-iface-modem-signal.h @@ -54,10 +54,12 @@ struct _MMIfaceModemSignal { MMSignal **gsm, MMSignal **umts, MMSignal **lte, + MMSignal **nr5g, GError **error); }; GType mm_iface_modem_signal_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemSignal, g_object_unref) /* Initialize Signal interface (async) */ void mm_iface_modem_signal_initialize (MMIfaceModemSignal *self, diff --git a/src/mm-iface-modem-simple.c b/src/mm-iface-modem-simple.c index ac845d76..b0cf5e22 100644 --- a/src/mm-iface-modem-simple.c +++ b/src/mm-iface-modem-simple.c @@ -26,7 +26,7 @@ #include "mm-iface-modem-3gpp.h" #include "mm-iface-modem-cdma.h" #include "mm-iface-modem-simple.h" -#include "mm-log.h" +#include "mm-log-object.h" /*****************************************************************************/ /* Private data context */ @@ -164,7 +164,7 @@ check_next_registration (GTask *task) /* No more tries of anything */ g_task_return_error ( task, - mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)); + mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, self)); g_object_unref (task); } @@ -280,7 +280,7 @@ connect_bearer_ready (MMBaseBearer *bearer, GError *error = NULL; if (!mm_base_bearer_connect_finish (bearer, res, &error)) { - mm_dbg ("Couldn't connect bearer: '%s'", error->message); + mm_obj_dbg (ctx->self, "couldn't connect bearer: %s", error->message); g_dbus_method_invocation_take_error (ctx->invocation, error); connection_context_free (ctx); return; @@ -432,10 +432,11 @@ update_lock_info_ready (MMIfaceModem *self, } /* If we are already unlocked, go on to next step. Note that we do also - * allow SIM-PIN2, as we don't need to unlock that in order to get + * allow SIM-PIN2/SIM-PUK2, as we don't need to unlock that in order to get * connected. */ if (lock == MM_MODEM_LOCK_NONE || - lock == MM_MODEM_LOCK_SIM_PIN2) { + lock == MM_MODEM_LOCK_SIM_PIN2 || + lock == MM_MODEM_LOCK_SIM_PUK2) { ctx->step++; connection_step (ctx); return; @@ -540,8 +541,8 @@ connection_step (ConnectionContext *ctx) /* fall through */ case CONNECTION_STEP_UNLOCK_CHECK: - mm_info ("Simple connect state (%d/%d): Unlock check", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): unlock check", + ctx->step, CONNECTION_STEP_LAST); mm_iface_modem_update_lock_info (MM_IFACE_MODEM (ctx->self), MM_MODEM_LOCK_UNKNOWN, /* ask */ (GAsyncReadyCallback)update_lock_info_ready, @@ -549,8 +550,8 @@ connection_step (ConnectionContext *ctx) return; case CONNECTION_STEP_WAIT_FOR_INITIALIZED: - mm_info ("Simple connect state (%d/%d): Wait to get fully initialized", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): wait to get fully initialized", + ctx->step, CONNECTION_STEP_LAST); mm_iface_modem_wait_for_final_state (MM_IFACE_MODEM (ctx->self), MM_MODEM_STATE_DISABLED, /* disabled == initialized */ (GAsyncReadyCallback)wait_for_initialized_ready, @@ -558,16 +559,16 @@ connection_step (ConnectionContext *ctx) return; case CONNECTION_STEP_ENABLE: - mm_info ("Simple connect state (%d/%d): Enable", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): enable", + ctx->step, CONNECTION_STEP_LAST); mm_base_modem_enable (MM_BASE_MODEM (ctx->self), (GAsyncReadyCallback)enable_ready, ctx); return; case CONNECTION_STEP_WAIT_FOR_ENABLED: - mm_info ("Simple connect state (%d/%d): Wait to get fully enabled", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): wait to get fully enabled", + ctx->step, CONNECTION_STEP_LAST); mm_iface_modem_wait_for_final_state (MM_IFACE_MODEM (ctx->self), MM_MODEM_STATE_UNKNOWN, /* just a final state */ (GAsyncReadyCallback)wait_for_enabled_ready, @@ -575,9 +576,8 @@ connection_step (ConnectionContext *ctx) return; case CONNECTION_STEP_REGISTER: - mm_info ("Simple connect state (%d/%d): Register", - ctx->step, CONNECTION_STEP_LAST); - + mm_obj_info (ctx->self, "simple connect state (%d/%d): register", + ctx->step, CONNECTION_STEP_LAST); if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (ctx->self)) || mm_iface_modem_is_cdma (MM_IFACE_MODEM (ctx->self))) { /* 3GPP or CDMA registration */ @@ -598,9 +598,8 @@ connection_step (ConnectionContext *ctx) MMBearerList *list = NULL; MMBearerProperties *bearer_properties; - mm_info ("Simple connect state (%d/%d): Bearer", - ctx->step, CONNECTION_STEP_LAST); - + mm_obj_info (ctx->self, "simple connect state (%d/%d): bearer", + ctx->step, CONNECTION_STEP_LAST); g_object_get (ctx->self, MM_IFACE_MODEM_BEARER_LIST, &list, NULL); @@ -619,7 +618,7 @@ connection_step (ConnectionContext *ctx) /* Check if the bearer we want to create is already in the list */ ctx->bearer = mm_bearer_list_find_by_properties (list, bearer_properties); if (!ctx->bearer) { - mm_dbg ("Creating new bearer..."); + mm_obj_dbg (ctx->self, "creating new bearer..."); /* If we don't have enough space to create the bearer, try to remove * a disconnected bearer first. */ if (mm_bearer_list_get_max (list) == mm_bearer_list_get_count (list)) { @@ -637,13 +636,13 @@ connection_step (ConnectionContext *ctx) if (!mm_bearer_list_delete_bearer (list, mm_base_bearer_get_path (foreach_ctx.found), &error)) { - mm_dbg ("Couldn't delete disconnected bearer at '%s': '%s'", - mm_base_bearer_get_path (foreach_ctx.found), - error->message); + mm_obj_dbg (ctx->self, "couldn't delete disconnected bearer at '%s': %s", + mm_base_bearer_get_path (foreach_ctx.found), + error->message); g_error_free (error); } else - mm_dbg ("Deleted disconnected bearer at '%s'", - mm_base_bearer_get_path (foreach_ctx.found)); + mm_obj_dbg (ctx->self, "deleted disconnected bearer at '%s'", + mm_base_bearer_get_path (foreach_ctx.found)); g_object_unref (foreach_ctx.found); } @@ -671,16 +670,16 @@ connection_step (ConnectionContext *ctx) return; } - mm_dbg ("Using already existing bearer at '%s'...", - mm_base_bearer_get_path (ctx->bearer)); + mm_obj_dbg (ctx->self, "Using already existing bearer at '%s'...", + mm_base_bearer_get_path (ctx->bearer)); g_object_unref (list); g_object_unref (bearer_properties); ctx->step++; } /* fall through */ case CONNECTION_STEP_CONNECT: - mm_info ("Simple connect state (%d/%d): Connect", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): connect", + ctx->step, CONNECTION_STEP_LAST); /* At this point, we can cleanup the cancellation point in the Simple interface, * because the bearer connection has its own cancellation setup. */ @@ -695,15 +694,15 @@ connection_step (ConnectionContext *ctx) return; } - mm_dbg ("Bearer at '%s' is already connected...", - mm_base_bearer_get_path (ctx->bearer)); + mm_obj_dbg (ctx->self, "bearer at '%s' is already connected...", + mm_base_bearer_get_path (ctx->bearer)); ctx->step++; /* fall through */ case CONNECTION_STEP_LAST: - mm_info ("Simple connect state (%d/%d): All done", - ctx->step, CONNECTION_STEP_LAST); + mm_obj_info (ctx->self, "simple connect state (%d/%d): all done", + ctx->step, CONNECTION_STEP_LAST); /* All done, yey! */ mm_gdbus_modem_simple_complete_connect ( ctx->skeleton, @@ -751,7 +750,7 @@ connect_auth_ready (MMBaseModem *self, MM_IFACE_MODEM_STATE, ¤t, NULL); - mm_info ("Simple connect started..."); + mm_obj_info (self, "simple connect started..."); /* Log about all the parameters being used for the simple connect */ { @@ -761,33 +760,29 @@ connect_auth_ready (MMBaseModem *self, #define VALIDATE_UNSPECIFIED(str) (str ? str : "unspecified") - mm_dbg (" PIN: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_pin (ctx->properties))); - - mm_dbg (" Operator ID: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_operator_id (ctx->properties))); - - mm_dbg (" Allowed roaming: %s", mm_simple_connect_properties_get_allow_roaming (ctx->properties) ? "yes" : "no"); - - mm_dbg (" APN: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_apn (ctx->properties))); + mm_obj_dbg (self, " PIN: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_pin (ctx->properties))); + mm_obj_dbg (self, " operator ID: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_operator_id (ctx->properties))); + mm_obj_dbg (self, " allowed roaming: %s", mm_simple_connect_properties_get_allow_roaming (ctx->properties) ? "yes" : "no"); + mm_obj_dbg (self, " APN: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_apn (ctx->properties))); ip_family = mm_simple_connect_properties_get_ip_type (ctx->properties); if (ip_family != MM_BEARER_IP_FAMILY_NONE) { str = mm_bearer_ip_family_build_string_from_mask (ip_family); - mm_dbg (" IP family: %s", str); + mm_obj_dbg (self, " IP family: %s", str); g_free (str); } else - mm_dbg (" IP family: %s", VALIDATE_UNSPECIFIED (NULL)); + mm_obj_dbg (self, " IP family: %s", VALIDATE_UNSPECIFIED (NULL)); allowed_auth = mm_simple_connect_properties_get_allowed_auth (ctx->properties); if (allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) { str = mm_bearer_allowed_auth_build_string_from_mask (allowed_auth); - mm_dbg (" Allowed authentication: %s", str); + mm_obj_dbg (self, " allowed authentication: %s", str); g_free (str); } else - mm_dbg (" Allowed authentication: %s", VALIDATE_UNSPECIFIED (NULL)); - - mm_dbg (" User: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_user (ctx->properties))); + mm_obj_dbg (self, " allowed authentication: %s", VALIDATE_UNSPECIFIED (NULL)); - mm_dbg (" Password: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_password (ctx->properties))); + mm_obj_dbg (self, " User: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_user (ctx->properties))); + mm_obj_dbg (self, " Password: %s", VALIDATE_UNSPECIFIED (mm_simple_connect_properties_get_password (ctx->properties))); #undef VALIDATE_UNSPECIFIED } @@ -847,7 +842,7 @@ handle_connect (MmGdbusModemSimple *skeleton, ctx->self = g_object_ref (self); ctx->dictionary = g_variant_ref (dictionary); - mm_dbg ("User request to connect modem"); + mm_obj_dbg (self, "user request to connect modem"); mm_base_modem_authorize (MM_BASE_MODEM (self), invocation, @@ -1008,10 +1003,10 @@ handle_disconnect (MmGdbusModemSimple *skeleton, * We will detect the '/' string and set the bearer path as NULL in the * context if so, and otherwise use the given input string as path */ if (g_strcmp0 (bearer_path, "/") != 0) { - mm_dbg ("User request to disconnect modem (bearer '%s')", bearer_path); + mm_obj_dbg (self, "user request to disconnect modem (bearer '%s')", bearer_path); ctx->bearer_path = g_strdup (bearer_path); } else - mm_dbg ("User request to disconnect modem (all bearers)"); + mm_obj_dbg (self, "user request to disconnect modem (all bearers)"); mm_base_modem_authorize (MM_BASE_MODEM (self), invocation, diff --git a/src/mm-iface-modem-simple.h b/src/mm-iface-modem-simple.h index 5b9b8af6..1aca5de1 100644 --- a/src/mm-iface-modem-simple.h +++ b/src/mm-iface-modem-simple.h @@ -34,6 +34,7 @@ struct _MMIfaceModemSimple { }; GType mm_iface_modem_simple_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemSimple, g_object_unref) /* Initialize Modem Simple interface */ void mm_iface_modem_simple_initialize (MMIfaceModemSimple *self); diff --git a/src/mm-iface-modem-time.c b/src/mm-iface-modem-time.c index 3aa20820..5770e7b7 100644 --- a/src/mm-iface-modem-time.c +++ b/src/mm-iface-modem-time.c @@ -19,7 +19,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-time.h" -#include "mm-log.h" +#include "mm-log-object.h" #define SUPPORT_CHECKED_TAG "time-support-checked-tag" #define SUPPORTED_TAG "time-supported-tag" @@ -194,7 +194,7 @@ static void load_network_timezone_ready (MMIfaceModemTime *self, GAsyncResult *res) { - GError *error = NULL; + g_autoptr(GError) error = NULL; MMNetworkTimezone *tz; /* Finish the async operation */ @@ -202,8 +202,7 @@ load_network_timezone_ready (MMIfaceModemTime *self, if (!tz) { NetworkTimezoneContext *ctx; - mm_dbg ("Couldn't load network timezone: %s", error->message); - g_error_free (error); + mm_obj_dbg (self, "couldn't load network timezone: %s", error->message); /* Note: may be NULL if the polling has been removed while processing the async operation */ ctx = (NetworkTimezoneContext *) g_object_get_qdata (G_OBJECT (self), network_timezone_context_quark); @@ -216,7 +215,7 @@ load_network_timezone_ready (MMIfaceModemTime *self, /* If no more retries, we don't do anything else */ if (ctx->network_timezone_poll_retries == 0 || !g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { - mm_warn ("Couldn't load network timezone from the current network"); + mm_obj_warn (self, "couldn't load network timezone from the current network"); return; } @@ -255,7 +254,7 @@ start_network_timezone_poll (MMIfaceModemTime *self) ctx = (NetworkTimezoneContext *) g_object_get_qdata (G_OBJECT (self), network_timezone_context_quark); - mm_dbg ("Network timezone polling started"); + mm_obj_dbg (self, "network timezone polling started"); ctx->network_timezone_poll_retries = NETWORK_TIMEZONE_POLL_RETRIES; ctx->network_timezone_poll_id = g_timeout_add_seconds (NETWORK_TIMEZONE_POLL_INTERVAL_SEC, (GSourceFunc)network_timezone_poll_cb, self); } @@ -268,7 +267,7 @@ stop_network_timezone_poll (MMIfaceModemTime *self) ctx = (NetworkTimezoneContext *) g_object_get_qdata (G_OBJECT (self), network_timezone_context_quark); if (ctx->network_timezone_poll_id) { - mm_dbg ("Network timezone polling stopped"); + mm_obj_dbg (self, "network timezone polling stopped"); g_source_remove (ctx->network_timezone_poll_id); ctx->network_timezone_poll_id = 0; } @@ -322,7 +321,7 @@ start_network_timezone (MMIfaceModemTime *self) /* If loading network timezone not supported, just finish here */ if (!MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_timezone || !MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_timezone_finish) { - mm_dbg ("Loading network timezone is not supported"); + mm_obj_dbg (self, "loading network timezone is not supported"); return; } @@ -622,7 +621,7 @@ enable_unsolicited_events_ready (MMIfaceModemTime *self, /* Not critical! */ if (!MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Couldn't enable unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't enable unsolicited events: %s", error->message); g_error_free (error); } @@ -764,7 +763,7 @@ check_support_ready (MMIfaceModemTime *self, &error)) { if (error) { /* This error shouldn't be treated as critical */ - mm_dbg ("Time support check failed: '%s'", error->message); + mm_obj_dbg (self, "time support check failed: %s", error->message); g_error_free (error); } } else { diff --git a/src/mm-iface-modem-time.h b/src/mm-iface-modem-time.h index 462d8b96..ca0640d6 100644 --- a/src/mm-iface-modem-time.h +++ b/src/mm-iface-modem-time.h @@ -94,6 +94,7 @@ struct _MMIfaceModemTime { }; GType mm_iface_modem_time_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemTime, g_object_unref) /* Initialize Time interface (async) */ void mm_iface_modem_time_initialize (MMIfaceModemTime *self, diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c index 9a57aa00..03aaeb0a 100644 --- a/src/mm-iface-modem-voice.c +++ b/src/mm-iface-modem-voice.c @@ -21,7 +21,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-voice.h" #include "mm-call-list.h" -#include "mm-log.h" +#include "mm-log-object.h" #define CALL_LIST_POLLING_CONTEXT_TAG "voice-call-list-polling-context-tag" #define IN_CALL_EVENT_CONTEXT_TAG "voice-in-call-event-context-tag" @@ -89,14 +89,14 @@ mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self, /* If we're not in emergency mode, the call (emergency or normal) is always allowed */ if (!emergency_only) { - mm_dbg ("voice call to %s allowed", number); + mm_obj_dbg (self, "voice call to %s allowed", number); call_allowed = TRUE; goto out; } for (i = 0; i < G_N_ELEMENTS (always_valid_emergency_numbers); i++) { if (g_strcmp0 (number, always_valid_emergency_numbers[i]) == 0) { - mm_dbg ("voice call to %s allowed: emergency call number always valid", number); + mm_obj_dbg (self, "voice call to %s allowed: emergency call number always valid", number); call_allowed = TRUE; goto out; } @@ -110,22 +110,22 @@ mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self, /* If no SIM available, some additional numbers may be valid emergency numbers */ for (i = 0; i < G_N_ELEMENTS (no_sim_valid_emergency_numbers); i++) { if (g_strcmp0 (number, no_sim_valid_emergency_numbers[i]) == 0) { - mm_dbg ("voice call to %s allowed: emergency call number valid when no SIM", number); + mm_obj_dbg (self, "voice call to %s allowed: emergency call number valid when no SIM", number); call_allowed = TRUE; goto out; } } - mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number when no SIM", number); + mm_obj_dbg (self, "voice call to %s NOT allowed: not a valid emergency call number when no SIM", number); goto out; } /* Check if the number is programmed in EF_ECC */ if (mm_base_sim_is_emergency_number (sim, number)) { - mm_dbg ("voice call to %s allowed: emergency call number programmed in the SIM", number); + mm_obj_dbg (self, "voice call to %s allowed: emergency call number programmed in the SIM", number); call_allowed = TRUE; } else - mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number programmed in the SIM", number); + mm_obj_dbg (self, "voice call to %s NOT allowed: not a valid emergency call number programmed in the SIM", number); out: @@ -188,8 +188,9 @@ create_outgoing_call_from_properties (MMIfaceModemVoice *self, /* Common helper to match call info against a known call object */ static gboolean -match_single_call_info (const MMCallInfo *call_info, - MMBaseCall *call) +match_single_call_info (MMIfaceModemVoice *self, + const MMCallInfo *call_info, + MMBaseCall *call) { MMCallState state; MMCallDirection direction; @@ -242,20 +243,20 @@ match_single_call_info (const MMCallInfo *call_info, !match_terminated) return FALSE; - mm_dbg ("call info matched (matched direction/state %s, matched number %s" - ", matched index %s, matched terminated %s) with call at '%s'", - match_direction_and_state ? "yes" : "no", - match_number ? "yes" : "no", - match_index ? "yes" : "no", - match_terminated ? "yes" : "no", - mm_base_call_get_path (call)); + mm_obj_dbg (self, "call info matched (matched direction/state %s, matched number %s" + ", matched index %s, matched terminated %s) with call at '%s'", + match_direction_and_state ? "yes" : "no", + match_number ? "yes" : "no", + match_index ? "yes" : "no", + match_terminated ? "yes" : "no", + mm_base_call_get_path (call)); /* Early detect if a known incoming call that was created * from a plain CRING URC (i.e. without caller number) * needs to have the number provided. */ if (call_info->number && !number) { - mm_dbg (" number set: %s", call_info->number); + mm_obj_dbg (self, " number set: %s", call_info->number); mm_base_call_set_number (call, call_info->number); } @@ -263,20 +264,20 @@ match_single_call_info (const MMCallInfo *call_info, * not have a known call index yet. */ if (call_info->index && !idx) { - mm_dbg (" index set: %u", call_info->index); + mm_obj_dbg (self, " index set: %u", call_info->index); mm_base_call_set_index (call, call_info->index); } /* Update state if it changed */ if (call_info->state != state) { - mm_dbg (" state updated: %s", mm_call_state_get_string (call_info->state)); + mm_obj_dbg (self, " state updated: %s", mm_call_state_get_string (call_info->state)); mm_base_call_change_state (call, call_info->state, MM_CALL_STATE_REASON_UNKNOWN); } /* refresh if incoming and new state is not terminated */ if ((call_info->state != MM_CALL_STATE_TERMINATED) && (direction == MM_CALL_DIRECTION_INCOMING)) { - mm_dbg (" incoming refreshed"); + mm_obj_dbg (self, " incoming refreshed"); mm_base_call_incoming_refresh (call); } @@ -286,7 +287,8 @@ match_single_call_info (const MMCallInfo *call_info, /*****************************************************************************/ typedef struct { - const MMCallInfo *call_info; + MMIfaceModemVoice *self; + const MMCallInfo *call_info; } ReportCallForeachContext; static void @@ -302,7 +304,7 @@ report_call_foreach (MMBaseCall *call, return; /* Reset call info in context if the call info matches an existing call */ - if (match_single_call_info (ctx->call_info, call)) + if (match_single_call_info (ctx->self, ctx->call_info, call)) ctx->call_info = NULL; } @@ -322,22 +324,23 @@ mm_iface_modem_voice_report_call (MMIfaceModemVoice *self, g_assert (call_info->state != MM_CALL_STATE_UNKNOWN); /* Early debugging of the call state update */ - mm_dbg ("call at index %u: direction %s, state %s, number %s", - call_info->index, - mm_call_direction_get_string (call_info->direction), - mm_call_state_get_string (call_info->state), - call_info->number ? call_info->number : "n/a"); + mm_obj_dbg (self, "call at index %u: direction %s, state %s, number %s", + call_info->index, + mm_call_direction_get_string (call_info->direction), + mm_call_state_get_string (call_info->state), + call_info->number ? call_info->number : "n/a"); g_object_get (MM_BASE_MODEM (self), MM_IFACE_MODEM_VOICE_CALL_LIST, &list, NULL); if (!list) { - mm_warn ("Cannot process call state update: missing call list"); + mm_obj_warn (self, "cannot process call state update: missing call list"); return; } /* Iterate over all known calls and try to match a known one */ + ctx.self = self; ctx.call_info = call_info; mm_call_list_foreach (list, (MMCallListForeachFunc)report_call_foreach, &ctx); @@ -349,13 +352,13 @@ mm_iface_modem_voice_report_call (MMIfaceModemVoice *self, * reported a NEW incoming call. If that's not the case, we'll ignore the report. */ if ((call_info->direction != MM_CALL_DIRECTION_INCOMING) || ((call_info->state != MM_CALL_STATE_WAITING) && (call_info->state != MM_CALL_STATE_RINGING_IN))) { - mm_dbg ("unhandled call state update reported: direction: %s, state %s", - mm_call_direction_get_string (call_info->direction), - mm_call_state_get_string (call_info->state)); + mm_obj_dbg (self, "unhandled call state update reported: direction: %s, state %s", + mm_call_direction_get_string (call_info->direction), + mm_call_state_get_string (call_info->state)); goto out; } - mm_dbg ("Creating new incoming call..."); + mm_obj_dbg (self, "creating new incoming call..."); call = create_incoming_call (self, call_info->number); /* Set the state */ @@ -393,7 +396,8 @@ mm_iface_modem_voice_report_call (MMIfaceModemVoice *self, */ typedef struct { - GList *call_info_list; + MMIfaceModemVoice *self; + GList *call_info_list; } ReportAllCallsForeachContext; static void @@ -413,20 +417,20 @@ report_all_calls_foreach (MMBaseCall *call, MMCallInfo *call_info = (MMCallInfo *)(l->data); /* if match found, delete item from list and halt iteration right away */ - if (match_single_call_info (call_info, call)) { + if (match_single_call_info (ctx->self, call_info, call)) { ctx->call_info_list = g_list_delete_link (ctx->call_info_list, l); return; } } /* not found in list! this call is now terminated */ - mm_dbg ("Call '%s' with direction %s, state %s, number '%s', index %u" - " not found in list, terminating", - mm_base_call_get_path (call), - mm_call_direction_get_string (mm_base_call_get_direction (call)), - mm_call_state_get_string (state), - mm_base_call_get_number (call), - mm_base_call_get_index (call)); + mm_obj_dbg (ctx->self, "call '%s' with direction %s, state %s, number '%s', index %u" + " not found in list, terminating", + mm_base_call_get_path (call), + mm_call_direction_get_string (mm_base_call_get_direction (call)), + mm_call_state_get_string (state), + mm_base_call_get_number (call), + mm_base_call_get_index (call)); mm_base_call_change_state (call, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN); } @@ -439,7 +443,7 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, GList *l; /* Early debugging of the full list of calls */ - mm_dbg ("Reported %u ongoing calls", g_list_length (call_info_list)); + mm_obj_dbg (self, "reported %u ongoing calls", g_list_length (call_info_list)); for (l = call_info_list; l; l = g_list_next (l)) { MMCallInfo *call_info = (MMCallInfo *)(l->data); @@ -447,11 +451,11 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, g_assert (call_info->index != 0); g_assert (call_info->state != MM_CALL_STATE_UNKNOWN); - mm_dbg ("call at index %u: direction %s, state %s, number %s", - call_info->index, - mm_call_direction_get_string (call_info->direction), - mm_call_state_get_string (call_info->state), - call_info->number ? call_info->number : "n/a"); + mm_obj_dbg (self, "call at index %u: direction %s, state %s, number %s", + call_info->index, + mm_call_direction_get_string (call_info->direction), + mm_call_state_get_string (call_info->state), + call_info->number ? call_info->number : "n/a"); } /* Retrieve list of known calls */ @@ -459,12 +463,13 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, MM_IFACE_MODEM_VOICE_CALL_LIST, &list, NULL); if (!list) { - mm_warn ("Cannot report all calls: missing call list"); + mm_obj_warn (self, "cannot report all calls: missing call list"); return; } /* Iterate over all the calls already known to us. * Whenever a known call is updated, it will be removed from the call info list */ + ctx.self = self; ctx.call_info_list = g_list_copy (call_info_list); mm_call_list_foreach (list, (MMCallListForeachFunc)report_all_calls_foreach, &ctx); @@ -480,9 +485,9 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, continue; if (call_info->direction == MM_CALL_DIRECTION_OUTGOING) { - mm_warn ("unexpected outgoing call to number '%s' reported in call list: state %s", - call_info->number ? call_info->number : "n/a", - mm_call_state_get_string (call_info->state)); + mm_obj_warn (self, "unexpected outgoing call to number '%s' reported in call list: state %s", + call_info->number ? call_info->number : "n/a", + mm_call_state_get_string (call_info->state)); continue; } @@ -492,13 +497,13 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, /* We only expect either RINGING-IN or WAITING states */ if ((call_info->state != MM_CALL_STATE_RINGING_IN) && (call_info->state != MM_CALL_STATE_WAITING)) { - mm_warn ("unexpected incoming call to number '%s' reported in call list: state %s", - call_info->number ? call_info->number : "n/a", - mm_call_state_get_string (call_info->state)); + mm_obj_warn (self, "unexpected incoming call to number '%s' reported in call list: state %s", + call_info->number ? call_info->number : "n/a", + mm_call_state_get_string (call_info->state)); continue; } - mm_dbg ("Creating new incoming call..."); + mm_obj_dbg (self, "creating new incoming call..."); call = create_incoming_call (self, call_info->number); /* Set the state and the index */ @@ -515,9 +520,9 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self, continue; } - mm_warn ("unexpected call to number '%s' reported in call list: state %s, direction unknown", - call_info->number ? call_info->number : "n/a", - mm_call_state_get_string (call_info->state)); + mm_obj_warn (self, "unexpected call to number '%s' reported in call list: state %s, direction unknown", + call_info->number ? call_info->number : "n/a", + mm_call_state_get_string (call_info->state)); } g_list_free (ctx.call_info_list); g_object_unref (list); @@ -556,7 +561,7 @@ mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self, MM_IFACE_MODEM_VOICE_CALL_LIST, &list, NULL); if (!list) { - mm_warn ("Cannot report received DTMF: missing call list"); + mm_obj_warn (self, "cannot report received DTMF: missing call list"); return; } @@ -1839,7 +1844,7 @@ setup_in_call_audio_channel_ready (MMIfaceModemVoice *self, &ctx->audio_port, &ctx->audio_format, &error)) { - mm_warn ("Couldn't setup in-call audio channel: %s", error->message); + mm_obj_warn (self, "couldn't setup in-call audio channel: %s", error->message); g_clear_error (&error); } @@ -1858,7 +1863,7 @@ setup_in_call_unsolicited_events_ready (MMIfaceModemVoice *self, ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->setup_in_call_unsolicited_events_finish (self, res, &error)) { - mm_warn ("Couldn't setup in-call unsolicited events: %s", error->message); + mm_obj_warn (self, "couldn't setup in-call unsolicited events: %s", error->message); g_clear_error (&error); } @@ -1891,7 +1896,7 @@ in_call_setup_context_step (GTask *task) self, (GAsyncReadyCallback) setup_in_call_unsolicited_events_ready, task); - break; + return; } ctx->step++; /* fall-through */ @@ -1902,7 +1907,7 @@ in_call_setup_context_step (GTask *task) self, (GAsyncReadyCallback) setup_in_call_audio_channel_ready, task); - break; + return; } ctx->step++; /* fall-through */ @@ -1974,7 +1979,7 @@ cleanup_in_call_unsolicited_events_ready (MMIfaceModemVoice *self, ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->cleanup_in_call_unsolicited_events_finish (self, res, &error)) { - mm_warn ("Couldn't cleanup in-call unsolicited events: %s", error->message); + mm_obj_warn (self, "couldn't cleanup in-call unsolicited events: %s", error->message); g_clear_error (&error); } @@ -1993,7 +1998,7 @@ cleanup_in_call_audio_channel_ready (MMIfaceModemVoice *self, ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->cleanup_in_call_audio_channel_finish (self, res, &error)) { - mm_warn ("Couldn't cleanup in-call audio channel: %s", error->message); + mm_obj_warn (self, "couldn't cleanup in-call audio channel: %s", error->message); g_clear_error (&error); } @@ -2026,7 +2031,7 @@ in_call_cleanup_context_step (GTask *task) self, (GAsyncReadyCallback) cleanup_in_call_audio_channel_ready, task); - break; + return; } ctx->step++; /* fall-through */ @@ -2037,7 +2042,7 @@ in_call_cleanup_context_step (GTask *task) self, (GAsyncReadyCallback) cleanup_in_call_unsolicited_events_ready, task); - break; + return; } ctx->step++; /* fall-through */ @@ -2154,7 +2159,7 @@ update_audio_settings_in_ongoing_calls (MMIfaceModemVoice *self) MM_IFACE_MODEM_VOICE_CALL_LIST, &list, NULL); if (!list) { - mm_warn ("Cannot update audio settings in active calls: missing internal call list"); + mm_obj_warn (self, "cannot update audio settings in active calls: missing internal call list"); return; } @@ -2209,10 +2214,10 @@ in_call_cleanup_ready (MMIfaceModemVoice *self, if (!in_call_cleanup_finish (self, res, &error)) { /* ignore cancelled operations */ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - mm_warn ("Cannot cleanup in-call modem state: %s", error->message); + mm_obj_warn (self, "cannot cleanup in-call modem state: %s", error->message); g_clear_error (&error); } else { - mm_dbg ("modem is no longer in-call state"); + mm_obj_dbg (self, "modem is no longer in-call state"); ctx->in_call_state = FALSE; g_clear_object (&ctx->audio_port); g_clear_object (&ctx->audio_format); @@ -2233,10 +2238,10 @@ in_call_setup_ready (MMIfaceModemVoice *self, if (!in_call_setup_finish (self, res, &ctx->audio_port, &ctx->audio_format, &error)) { /* ignore cancelled operations */ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - mm_warn ("Cannot setup in-call modem state: %s", error->message); + mm_obj_warn (self, "cannot setup in-call modem state: %s", error->message); g_clear_error (&error); } else { - mm_dbg ("modem is now in-call state"); + mm_obj_dbg (self, "modem is now in-call state"); ctx->in_call_state = TRUE; update_audio_settings_in_ongoing_calls (self); } @@ -2258,7 +2263,7 @@ call_list_check_in_call_events (MMIfaceModemVoice *self) MM_IFACE_MODEM_VOICE_CALL_LIST, &list, NULL); if (!list) { - mm_warn ("Cannot update in-call state: missing internal call list"); + mm_obj_warn (self, "cannot update in-call state: missing internal call list"); goto out; } @@ -2277,7 +2282,7 @@ call_list_check_in_call_events (MMIfaceModemVoice *self) } /* run setup */ - mm_dbg ("Setting up in-call state..."); + mm_obj_dbg (self, "setting up in-call state..."); ctx->setup_cancellable = g_cancellable_new (); in_call_setup (self, ctx->setup_cancellable, (GAsyncReadyCallback) in_call_setup_ready, NULL); goto out; @@ -2296,7 +2301,7 @@ call_list_check_in_call_events (MMIfaceModemVoice *self) } /* run cleanup */ - mm_dbg ("Cleaning up in-call state..."); + mm_obj_dbg (self, "cleaning up in-call state..."); ctx->cleanup_cancellable = g_cancellable_new (); in_call_cleanup (self, ctx->cleanup_cancellable, (GAsyncReadyCallback) in_call_cleanup_ready, NULL); goto out; @@ -2406,7 +2411,7 @@ load_call_list_ready (MMIfaceModemVoice *self, g_assert (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish); if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish (self, res, &call_info_list, &error)) { - mm_warn ("couldn't load call list: %s", error->message); + mm_obj_warn (self, "couldn't load call list: %s", error->message); g_error_free (error); } else { /* Always report the list even if NULL (it would mean no ongoing calls) */ @@ -2414,11 +2419,13 @@ load_call_list_ready (MMIfaceModemVoice *self, mm_3gpp_call_info_list_free (call_info_list); } - /* setup the polling again */ - g_assert (!ctx->polling_id); - ctx->polling_id = g_timeout_add_seconds (CALL_LIST_POLLING_TIMEOUT_SECS, - (GSourceFunc) call_list_poll, - self); + /* setup the polling again, but only if it hasn't been done already while + * we reported calls (e.g. a new incoming call may have been detected that + * also triggers the poll setup) */ + if (!ctx->polling_id) + ctx->polling_id = g_timeout_add_seconds (CALL_LIST_POLLING_TIMEOUT_SECS, + (GSourceFunc) call_list_poll, + self); } static void @@ -2458,7 +2465,7 @@ call_list_poll (MMIfaceModemVoice *self) NULL); if (!list) { - mm_warn ("Cannot poll call list: missing internal call list"); + mm_obj_warn (self, "Cannot poll call list: missing internal call list"); goto out; } @@ -2466,14 +2473,14 @@ call_list_poll (MMIfaceModemVoice *self) /* If there is at least ONE call being established, we need the call list */ if (n_calls_establishing > 0) { - mm_dbg ("%u calls being established: call list polling required", n_calls_establishing); + mm_obj_dbg (self, "%u calls being established: call list polling required", n_calls_establishing); ctx->polling_ongoing = TRUE; g_assert (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list); MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list (self, (GAsyncReadyCallback)load_call_list_ready, NULL); } else - mm_dbg ("no calls being established: call list polling stopped"); + mm_obj_dbg (self, "no calls being established: call list polling stopped"); out: g_clear_object (&list); @@ -2515,7 +2522,6 @@ call_added (MMCallList *list, const gchar *call_path, MmGdbusModemVoice *skeleton) { - mm_dbg ("Added call at '%s'", call_path); update_call_list (skeleton, list); mm_gdbus_modem_voice_emit_call_added (skeleton, call_path); } @@ -2525,7 +2531,6 @@ call_deleted (MMCallList *list, const gchar *call_path, MmGdbusModemVoice *skeleton) { - mm_dbg ("Deleted call at '%s'", call_path); update_call_list (skeleton, list); mm_gdbus_modem_voice_emit_call_deleted (skeleton, call_path); } @@ -2752,7 +2757,7 @@ enable_unsolicited_events_ready (MMIfaceModemVoice *self, /* Not critical! */ if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->enable_unsolicited_events_finish (self, res, &error)) { - mm_dbg ("Couldn't enable unsolicited events: '%s'", error->message); + mm_obj_dbg (self, "couldn't enable unsolicited events: %s", error->message); g_error_free (error); } @@ -2885,7 +2890,7 @@ check_support_ready (MMIfaceModemVoice *self, if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support_finish (self, res, &error)) { if (error) { - mm_dbg ("Voice support check failed: '%s'", error->message); + mm_obj_dbg (self, "voice support check failed: %s", error->message); g_error_free (error); } g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Voice not supported"); @@ -2981,7 +2986,7 @@ interface_initialization_step (GTask *task) MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, &periodic_call_list_check_disabled, NULL); if (!periodic_call_list_check_disabled) { - mm_dbg ("periodic call list polling will be used if supported"); + mm_obj_dbg (self, "periodic call list polling will be used if supported"); g_signal_connect (list, MM_CALL_ADDED, G_CALLBACK (setup_call_list_polling), diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h index 2a9e52e0..fe2ae243 100644 --- a/src/mm-iface-modem-voice.h +++ b/src/mm-iface-modem-voice.h @@ -196,6 +196,7 @@ struct _MMIfaceModemVoice { }; GType mm_iface_modem_voice_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModemVoice, g_object_unref) /* Initialize Voice interface (async) */ void mm_iface_modem_voice_initialize (MMIfaceModemVoice *self, diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index 624a4ee4..ad28fcf7 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -13,7 +13,6 @@ * Copyright (C) 2011 Google, Inc. */ - #include #define _LIBMM_INSIDE_MM #include @@ -26,8 +25,15 @@ #include "mm-base-modem-at.h" #include "mm-base-sim.h" #include "mm-bearer-list.h" -#include "mm-log.h" +#include "mm-private-boxed-types.h" +#include "mm-log-object.h" #include "mm-context.h" +#if defined WITH_QMI +# include "mm-broadband-modem-qmi.h" +#endif +#if defined WITH_MBIM +# include "mm-broadband-modem-mbim.h" +#endif #define SIGNAL_QUALITY_RECENT_TIMEOUT_SEC 60 @@ -47,6 +53,89 @@ static GQuark restart_initialize_idle_quark; /*****************************************************************************/ +gboolean +mm_iface_modem_check_for_sim_swap_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +explicit_check_for_sim_swap_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish (self, res, &error)) { + mm_obj_warn (self, "SIM swap check failed: %s", error->message); + g_task_return_error (task, error); + } else { + mm_obj_dbg (self, "SIM swap check completed"); + g_task_return_boolean (task, TRUE); + } + g_object_unref (task); +} + +void +mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, + guint slot_index, + const gchar *iccid, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + /* Slot index 0 is used when slot is not known, assumingly on a modem with just one SIM slot */ + if (slot_index != 0) { + MmGdbusModem *skeleton; + guint primary_slot; + + g_object_get (self, + MM_IFACE_MODEM_DBUS_SKELETON, &skeleton, + NULL); + + if (!skeleton) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't get interface skeleton"); + g_object_unref (task); + return; + } + + primary_slot = mm_gdbus_modem_get_primary_sim_slot (MM_GDBUS_MODEM (skeleton)); + g_object_unref (skeleton); + + /* Check that it's really the primary slot whose iccid has changed */ + if (primary_slot && primary_slot != slot_index) { + mm_obj_dbg (self, "checking for SIM swap ignored: status changed in slot %u, but primary is %u", slot_index, primary_slot); + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + } + + if (MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap && + MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish) { + mm_obj_dbg (self, "start checking for SIM swap in slot %u", slot_index); + MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap ( + self, + iccid, + (GAsyncReadyCallback)explicit_check_for_sim_swap_ready, + task); + return; + } + + g_task_return_boolean (task, FALSE); + g_object_unref (task); +} + +/*****************************************************************************/ + void mm_iface_modem_bind_simple_status (MMIfaceModem *self, MMSimpleStatus *status) @@ -310,7 +399,7 @@ load_unlock_required_ready (MMIfaceModem *self, lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error); if (error) { - mm_dbg ("Couldn't check if unlock required: '%s'", error->message); + mm_obj_dbg (self, "couldn't check if unlock required: %s", error->message); /* For several kinds of errors, just return them directly */ if (error->domain == MM_SERIAL_ERROR || @@ -334,7 +423,7 @@ load_unlock_required_ready (MMIfaceModem *self, /* For the remaining ones, retry if possible */ if (ctx->retries < MAX_RETRIES) { ctx->retries++; - mm_dbg ("Retrying (%u) unlock required check", ctx->retries); + mm_obj_dbg (self, "retrying (%u) unlock required check", ctx->retries); g_assert (ctx->pin_check_timeout_id == 0); ctx->pin_check_timeout_id = g_timeout_add_seconds (2, @@ -422,6 +511,7 @@ bearer_list_updated (MMBearerList *bearer_list, g_strfreev (paths); g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (skeleton)); + g_object_unref (skeleton); } /*****************************************************************************/ @@ -957,6 +1047,117 @@ handle_list_bearers (MmGdbusModem *skeleton, /*****************************************************************************/ +typedef struct { + MmGdbusModem *skeleton; + GDBusMethodInvocation *invocation; + MMIfaceModem *self; + guint requested_sim_slot; +} HandleSetPrimarySimSlotContext; + +static void +handle_set_primary_sim_slot_context_free (HandleSetPrimarySimSlotContext *ctx) +{ + g_clear_object (&ctx->skeleton); + g_clear_object (&ctx->invocation); + g_clear_object (&ctx->self); + g_free (ctx); +} + +static void +set_primary_sim_slot_ready (MMIfaceModem *self, + GAsyncResult *res, + HandleSetPrimarySimSlotContext *ctx) +{ + g_autoptr(GError) error = NULL; + + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot_finish (self, res, &error)) { + /* If the implementation returns EXISTS, we're already in the requested SIM slot, + * so we can safely return a success on the operation and skip the reprobing */ + if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_EXISTS)) { + mm_obj_warn (self, "couldn't process primary SIM update request: %s", error->message); + g_dbus_method_invocation_take_error (ctx->invocation, g_steal_pointer (&error)); + handle_set_primary_sim_slot_context_free (ctx); + return; + } + mm_obj_dbg (self, "ignoring SIM update request: %s", error->message); + } else { + /* Notify about the SIM swap, which will disable and reprobe the device. + * There is no need to update the PrimarySimSlot property, as this value will be + * reloaded automatically during the reprobe. */ + mm_base_modem_process_sim_event (MM_BASE_MODEM (self)); + } + + mm_gdbus_modem_complete_set_primary_sim_slot (ctx->skeleton, ctx->invocation); + handle_set_primary_sim_slot_context_free (ctx); +} + +static void +handle_set_primary_sim_slot_auth_ready (MMBaseModem *self, + GAsyncResult *res, + HandleSetPrimarySimSlotContext *ctx) +{ + GError *error = NULL; + const gchar *const *sim_slot_paths; + + if (!mm_base_modem_authorize_finish (self, res, &error)) { + g_dbus_method_invocation_take_error (ctx->invocation, error); + handle_set_primary_sim_slot_context_free (ctx); + return; + } + + /* If SIM switching is not implemented, report an error */ + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot || + !MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot_finish) { + g_dbus_method_invocation_return_error (ctx->invocation, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "Cannot switch sim: " + "operation not supported"); + handle_set_primary_sim_slot_context_free (ctx); + return; + } + + /* Validate SIM slot number */ + sim_slot_paths = mm_gdbus_modem_get_sim_slots (ctx->skeleton); + if (ctx->requested_sim_slot > g_strv_length ((gchar **)sim_slot_paths)) { + g_dbus_method_invocation_return_error (ctx->invocation, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Cannot switch sim: requested SIM slot number is out of bounds"); + handle_set_primary_sim_slot_context_free (ctx); + return; + } + + MM_IFACE_MODEM_GET_INTERFACE (self)->set_primary_sim_slot (MM_IFACE_MODEM (self), + ctx->requested_sim_slot, + (GAsyncReadyCallback)set_primary_sim_slot_ready, + ctx); +} + +static gboolean +handle_set_primary_sim_slot (MmGdbusModem *skeleton, + GDBusMethodInvocation *invocation, + guint sim_slot, + MMIfaceModem *self) +{ + HandleSetPrimarySimSlotContext *ctx; + + ctx = g_new0 (HandleSetPrimarySimSlotContext, 1); + ctx->skeleton = g_object_ref (skeleton); + ctx->invocation = g_object_ref (invocation); + ctx->self = g_object_ref (self); + ctx->requested_sim_slot = sim_slot; + + mm_base_modem_authorize (MM_BASE_MODEM (self), + invocation, + MM_AUTHORIZATION_DEVICE_CONTROL, + (GAsyncReadyCallback)handle_set_primary_sim_slot_auth_ready, + ctx); + return TRUE; +} + +/*****************************************************************************/ + void mm_iface_modem_update_access_technologies (MMIfaceModem *self, MMModemAccessTechnology new_access_tech, @@ -990,10 +1191,9 @@ mm_iface_modem_update_access_technologies (MMIfaceModem *self, /* Log */ old_access_tech_string = mm_modem_access_technology_build_string_from_mask (old_access_tech); new_access_tech_string = mm_modem_access_technology_build_string_from_mask (built_access_tech); - mm_dbg ("Modem %s: access technology changed (%s -> %s)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (self)), - old_access_tech_string, - new_access_tech_string); + mm_obj_dbg (self, "access technology changed (%s -> %s)", + old_access_tech_string, + new_access_tech_string); g_free (old_access_tech_string); g_free (new_access_tech_string); } @@ -1038,9 +1238,8 @@ expire_signal_quality (MMIfaceModem *self) /* If value is already not recent, we're done */ if (recent) { - mm_dbg ("Signal quality value not updated in %us, " - "marking as not being recent", - SIGNAL_QUALITY_RECENT_TIMEOUT_SEC); + mm_obj_dbg (self, "signal quality value not updated in %us, marking as not being recent", + SIGNAL_QUALITY_RECENT_TIMEOUT_SEC); mm_gdbus_modem_set_signal_quality (skeleton, g_variant_new ("(ub)", signal_quality, @@ -1063,7 +1262,6 @@ update_signal_quality (MMIfaceModem *self, { SignalQualityUpdateContext *ctx; MmGdbusModem *skeleton = NULL; - const gchar *dbus_path; g_object_get (self, MM_IFACE_MODEM_DBUS_SKELETON, &skeleton, @@ -1098,10 +1296,7 @@ update_signal_quality (MMIfaceModem *self, signal_quality, expire)); - dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self)); - mm_dbg ("Modem %s: signal quality updated (%u)", - dbus_path, - signal_quality); + mm_obj_dbg (self, "signal quality updated (%u)", signal_quality); /* Remove any previous expiration refresh timeout */ if (ctx->recent_timeout_source) { @@ -1233,12 +1428,12 @@ access_technologies_check_ready (MMIfaceModem *self, &error)) { /* Did the plugin report that polling access technology is unsupported? */ if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) { - mm_dbg ("Polling to refresh access technologies is unsupported"); + mm_obj_dbg (self, "polling to refresh access technologies is unsupported"); ctx->access_technology_polling_supported = FALSE; } /* Ignore logging any message if the error is in 'in-progress' */ else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS)) - mm_dbg ("Couldn't refresh access technologies: '%s'", error->message); + mm_obj_dbg (self, "couldn't refresh access technologies: %s", error->message); g_error_free (error); } /* We may have been disabled while this command was running. */ @@ -1263,12 +1458,12 @@ signal_quality_check_ready (MMIfaceModem *self, if (error) { /* Did the plugin report that polling signal quality is unsupported? */ if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) { - mm_dbg ("Polling to refresh signal quality is unsupported"); + mm_obj_dbg (self, "polling to refresh signal quality is unsupported"); ctx->signal_quality_polling_supported = FALSE; } /* Ignore logging any message if the error is in 'in-progress' */ else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS)) - mm_dbg ("Couldn't refresh signal quality: '%s'", error->message); + mm_obj_dbg (self, "couldn't refresh signal quality: %s", error->message); g_error_free (error); } /* We may have been disabled while this command was running. */ @@ -1322,7 +1517,7 @@ peridic_signal_check_step (MMIfaceModem *self) /* If we have been disabled while we were running the steps, we don't * do anything else. */ if (!ctx->enabled) { - mm_dbg ("Periodic signal quality and access technology checks not rescheduled: disabled"); + mm_obj_dbg (self, "periodic signal quality and access technology checks not rescheduled: disabled"); return; } @@ -1353,12 +1548,12 @@ peridic_signal_check_step (MMIfaceModem *self) if (ctx->initial_check_done && (!ctx->signal_quality_polling_supported || ctx->signal_quality_polling_disabled) && (!ctx->access_technology_polling_supported || ctx->access_technology_polling_disabled)) { - mm_dbg ("Periodic signal quality and access technology checks not rescheduled: unneeded or unsupported"); + mm_obj_dbg (self, "periodic signal quality and access technology checks not rescheduled: unneeded or unsupported"); periodic_signal_check_disable (self, FALSE); return; } - mm_dbg ("Periodic signal quality and access technology checks scheduled"); + mm_obj_dbg (self, "periodic signal quality and access technology checks scheduled"); g_assert (!ctx->timeout_source); ctx->timeout_source = g_timeout_add_seconds (ctx->initial_check_done ? SIGNAL_CHECK_TIMEOUT_SEC : SIGNAL_CHECK_INITIAL_TIMEOUT_SEC, (GSourceFunc) periodic_signal_check_cb, @@ -1399,17 +1594,17 @@ mm_iface_modem_refresh_signal (MMIfaceModem *self) /* Don't refresh polling if we're not enabled */ ctx = get_signal_check_context (self); if (!ctx->enabled) { - mm_dbg ("Periodic signal check refresh ignored: checks not enabled"); + mm_obj_dbg (self, "periodic signal check refresh ignored: checks not enabled"); return; } /* Don't refresh if we're already doing it */ if (ctx->running_step != SIGNAL_CHECK_STEP_NONE) { - mm_dbg ("Periodic signal check refresh ignored: check already running"); + mm_obj_dbg (self, "periodic signal check refresh ignored: check already running"); return; } - mm_dbg ("Periodic signal check refresh requested"); + mm_obj_dbg (self, "periodic signal check refresh requested"); /* Remove the scheduled timeout as we're going to refresh * right away */ @@ -1452,7 +1647,7 @@ periodic_signal_check_disable (MMIfaceModem *self, } ctx->enabled = FALSE; - mm_dbg ("Periodic signal checks disabled"); + mm_obj_dbg (self, "periodic signal checks disabled"); } static void @@ -1465,13 +1660,13 @@ periodic_signal_check_enable (MMIfaceModem *self) /* If polling access technology and signal quality not supported, don't even * bother trying. */ if (!ctx->signal_quality_polling_supported && !ctx->access_technology_polling_supported) { - mm_dbg ("Not enabling periodic signal checks: unsupported"); + mm_obj_dbg (self, "not enabling periodic signal checks: unsupported"); return; } /* Log and flag as enabled */ if (!ctx->enabled) { - mm_dbg ("Periodic signal checks enabled"); + mm_obj_dbg (self, "periodic signal checks enabled"); ctx->enabled = TRUE; } @@ -1515,7 +1710,8 @@ __iface_modem_update_state_internal (MMIfaceModem *self, /* While connected we don't want registration status changes to change * the modem's state away from CONNECTED. */ - if ((new_state == MM_MODEM_STATE_SEARCHING || + if ((new_state == MM_MODEM_STATE_ENABLED || + new_state == MM_MODEM_STATE_SEARCHING || new_state == MM_MODEM_STATE_REGISTERED) && bearer_list && old_state > MM_MODEM_STATE_REGISTERED) { @@ -1535,14 +1731,9 @@ __iface_modem_update_state_internal (MMIfaceModem *self, /* Update state only if different */ if (new_state != old_state) { - const gchar *dbus_path; - - dbus_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (self)); - mm_info ("Modem%s%s: state changed (%s -> %s)", - dbus_path ? " " : "", - dbus_path ? dbus_path : "", - mm_modem_state_get_string (old_state), - mm_modem_state_get_string (new_state)); + mm_obj_info (self, "state changed (%s -> %s)", + mm_modem_state_get_string (old_state), + mm_modem_state_get_string (new_state)); /* The property in the interface is bound to the property * in the skeleton, so just updating here is enough */ @@ -1707,8 +1898,7 @@ get_updated_consolidated_state (MMIfaceModem *self, if (i == subsystem_states->len) { SubsystemState s; - mm_dbg ("Will start keeping track of state for subsystem '%s'", - subsystem); + mm_obj_dbg (self, "will start keeping track of state for subsystem '%s'", subsystem); s.subsystem = g_strdup (subsystem); s.state = subsystem_state; g_array_append_val (subsystem_states, s); @@ -2233,7 +2423,7 @@ handle_set_current_capabilities_auth_ready (MMBaseModem *self, } capabilities_string = mm_modem_capability_build_string_from_mask (ctx->capabilities); - mm_dbg ("Setting new list of capabilities: '%s'", capabilities_string); + mm_obj_dbg (self, "setting new list of capabilities: %s", capabilities_string); g_free (capabilities_string); MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_capabilities ( @@ -2337,14 +2527,14 @@ after_set_load_current_bands_ready (MMIfaceModem *self, if (!current_bands) { /* If we can retry, do it */ if (ctx->retries > 0) { - mm_dbg ("couldn't load current bands: '%s' (will retry)", error->message); + mm_obj_dbg (self, "couldn't load current bands: %s (will retry)", error->message); g_clear_error (&error); set_current_bands_reload_schedule (task); goto out; } /* Errors when reloading bands won't be critical */ - mm_warn ("couldn't load current bands: '%s'", error->message); + mm_obj_warn (self, "couldn't load current bands: %s", error->message); g_clear_error (&error); set_current_bands_complete_with_defaults (task); goto out; @@ -2362,13 +2552,13 @@ after_set_load_current_bands_ready (MMIfaceModem *self, /* If we can retry, do it */ if (ctx->retries > 0) { - mm_dbg ("reloaded current bands different to the requested ones (will retry)"); + mm_obj_dbg (self, "reloaded current bands different to the requested ones (will retry)"); set_current_bands_reload_schedule (task); goto out; } - requested_str = mm_common_build_bands_string ((MMModemBand *)requested_bands->data, requested_bands->len); - current_str = mm_common_build_bands_string ((MMModemBand *)current_bands->data, current_bands->len); + requested_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)requested_bands->data, requested_bands->len); + current_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)current_bands->data, current_bands->len); error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "reloaded current bands (%s) different to the requested ones (%s)", current_str, requested_str); @@ -2483,7 +2673,7 @@ validate_bands (const GArray *supported_bands_array, gchar *supported_bands_str; supported_bands_str = (mm_common_build_bands_string ( - (const MMModemBand *)supported_bands_array->data, + (const MMModemBand *)(gconstpointer)supported_bands_array->data, supported_bands_array->len)); g_set_error (error, MM_CORE_ERROR, @@ -2544,8 +2734,7 @@ mm_iface_modem_set_current_bands (MMIfaceModem *self, return; } - bands_string = mm_common_build_bands_string ((MMModemBand *)bands_array->data, - bands_array->len); + bands_string = mm_common_build_bands_string ((const MMModemBand *)(gpointer)bands_array->data, bands_array->len); /* Get list of supported bands */ ctx->supported_bands_array = (mm_common_bands_variant_to_garray ( @@ -2580,8 +2769,7 @@ mm_iface_modem_set_current_bands (MMIfaceModem *self, current_bands_array = (mm_common_bands_variant_to_garray ( mm_gdbus_modem_get_current_bands (ctx->skeleton))); if (mm_common_bands_garray_cmp (ctx->bands_array, current_bands_array)) { - mm_dbg ("Requested list of bands (%s) is equal to the current ones, skipping re-set", - bands_string); + mm_obj_dbg (self, "requested list of bands (%s) is equal to the current ones, skipping re-set", bands_string); g_free (bands_string); g_array_unref (current_bands_array); g_task_return_boolean (task, TRUE); @@ -2600,8 +2788,7 @@ mm_iface_modem_set_current_bands (MMIfaceModem *self, if (!validate_bands (ctx->supported_bands_array, ctx->bands_array, &error)) { - mm_dbg ("Requested list of bands (%s) cannot be handled", - bands_string); + mm_obj_dbg (self, "requested list of bands (%s) cannot be handled", bands_string); g_free (bands_string); g_array_unref (current_bands_array); g_task_return_error (task, error); @@ -2609,7 +2796,7 @@ mm_iface_modem_set_current_bands (MMIfaceModem *self, return; } - mm_dbg ("Setting new list of bands: '%s'", bands_string); + mm_obj_dbg (self, "setting new list of bands: %s", bands_string); MM_IFACE_MODEM_GET_INTERFACE (self)->set_current_bands ( self, ctx->bands_array, @@ -2754,14 +2941,14 @@ after_set_load_current_modes_ready (MMIfaceModem *self, &error)) { /* If we can retry, do it */ if (ctx->retries > 0) { - mm_dbg ("couldn't load current allowed/preferred modes: '%s'", error->message); + mm_obj_dbg (self, "couldn't load current allowed/preferred modes: %s", error->message); g_error_free (error); set_current_modes_reload_schedule (task); return; } /* Errors when getting allowed/preferred won't be critical */ - mm_warn ("couldn't load current allowed/preferred modes: '%s'", error->message); + mm_obj_warn (self, "couldn't load current allowed/preferred modes: %s", error->message); g_clear_error (&error); /* If errors getting allowed modes, default to the ones we asked for */ @@ -2782,7 +2969,7 @@ after_set_load_current_modes_ready (MMIfaceModem *self, /* If we can retry, do it */ if (ctx->retries > 0) { - mm_dbg ("reloaded current modes different to the requested ones (will retry)"); + mm_obj_dbg (self, "reloaded current modes different to the requested ones (will retry)"); set_current_modes_reload_schedule (task); return; } @@ -3103,7 +3290,7 @@ reinitialize_ready (MMBaseModem *self, mm_base_modem_initialize_finish (self, res, &error); if (error) { - mm_warn ("Modem reinitialization failed: '%s'", error->message); + mm_obj_warn (self, "reinitialization failed: %s", error->message); g_error_free (error); } } @@ -3135,6 +3322,8 @@ set_lock_status (MMIfaceModem *self, old_lock = mm_gdbus_modem_get_unlock_required (skeleton); mm_gdbus_modem_set_unlock_required (skeleton, lock); + if (lock == MM_MODEM_LOCK_UNKNOWN) + mm_gdbus_modem_set_unlock_retries (skeleton, 0); /* We don't care about SIM-PIN2/SIM-PUK2 since the device is * operational without it. */ @@ -3171,6 +3360,24 @@ set_lock_status (MMIfaceModem *self, } } +MMModemLock +mm_iface_modem_get_unlock_required (MMIfaceModem *self) +{ + MmGdbusModem *skeleton = NULL; + MMModemLock lock; + + g_object_get (self, + MM_IFACE_MODEM_DBUS_SKELETON, &skeleton, + NULL); + if (skeleton) { + lock = mm_gdbus_modem_get_unlock_required (skeleton); + g_object_unref (skeleton); + } else + lock = MM_MODEM_LOCK_UNKNOWN; + + return lock; +} + MMUnlockRetries * mm_iface_modem_get_unlock_retries (MMIfaceModem *self) { @@ -3276,7 +3483,7 @@ load_unlock_retries_ready (MMIfaceModem *self, unlock_retries = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_retries_finish (self, res, &error); if (!unlock_retries) { - mm_warn ("Couldn't load unlock retries: '%s'", error->message); + mm_obj_warn (self, "couldn't load unlock retries: %s", error->message); g_error_free (error); } else { /* Update the dictionary in the DBus interface */ @@ -3299,7 +3506,7 @@ modem_after_sim_unlock_ready (MMIfaceModem *self, GError *error = NULL; if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock_finish (self, res, &error)) { - mm_warn ("After SIM unlock failed setup: '%s'", error->message); + mm_obj_warn (self, "after SIM unlock failed: %s", error->message); g_error_free (error); } @@ -3352,11 +3559,11 @@ internal_load_unlock_required_ready (MMIfaceModem *self, } /* For mixed 3GPP+3GPP2 devices, skip SIM errors */ - mm_dbg ("Skipping SIM error in 3GPP2-capable device, assuming no lock is needed"); + mm_obj_dbg (self, "skipping SIM error in 3GPP2-capable device, assuming no lock is needed"); g_error_free (error); ctx->lock = MM_MODEM_LOCK_NONE; } else { - mm_dbg ("Couldn't check if unlock required: '%s'", error->message); + mm_obj_dbg (self, "couldn't check if unlock required: %s", error->message); g_error_free (error); ctx->lock = MM_MODEM_LOCK_UNKNOWN; } @@ -3413,7 +3620,7 @@ update_lock_info_context_step (GTask *task) ctx->lock == MM_MODEM_LOCK_SIM_PUK2)) { if (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock != NULL && MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock_finish != NULL) { - mm_dbg ("SIM is ready, running after SIM unlock step..."); + mm_obj_dbg (self, "SIM is ready, running after SIM unlock step..."); MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_sim_unlock ( self, (GAsyncReadyCallback)modem_after_sim_unlock_ready, @@ -3422,7 +3629,7 @@ update_lock_info_context_step (GTask *task) } /* If no way to run after SIM unlock step, we're done */ - mm_dbg ("SIM is ready, and no need for the after SIM unlock step..."); + mm_obj_dbg (self, "SIM is ready, and no need for the after SIM unlock step..."); } ctx->step++; /* fall-through */ @@ -3442,6 +3649,7 @@ update_lock_info_context_step (GTask *task) case UPDATE_LOCK_INFO_CONTEXT_STEP_LAST: if (ctx->saved_error) { + set_lock_status (self, ctx->skeleton, MM_MODEM_LOCK_UNKNOWN); /* Return saved error */ g_task_return_error (task, ctx->saved_error); ctx->saved_error = NULL; @@ -3469,9 +3677,6 @@ mm_iface_modem_update_lock_info (MMIfaceModem *self, GTask *task; ctx = g_slice_new0 (UpdateLockInfoContext); - g_object_get (self, - MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton, - NULL); /* If the given lock is known, we will avoid re-asking for it */ ctx->lock = known_lock; @@ -3479,255 +3684,259 @@ mm_iface_modem_update_lock_info (MMIfaceModem *self, task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)update_lock_info_context_free); + g_object_get (self, + MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton, + NULL); + + if (!ctx->skeleton) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't get interface skeleton"); + g_object_unref (task); + return; + } + update_lock_info_context_step (task); } /*****************************************************************************/ /* Set power state sequence */ +typedef enum { + SET_POWER_STATE_STEP_FIRST, + SET_POWER_STATE_STEP_LOAD, + SET_POWER_STATE_STEP_CHECK, + SET_POWER_STATE_STEP_UPDATE, + SET_POWER_STATE_STEP_FCC_UNLOCK, + SET_POWER_STATE_STEP_AFTER_UPDATE, + SET_POWER_STATE_STEP_LAST, +} SetPowerStateStep; + typedef struct { - MmGdbusModem *skeleton; - MMModemPowerState power_state; - MMModemPowerState previous_cached_power_state; - MMModemPowerState previous_real_power_state; + SetPowerStateStep step; + MmGdbusModem *skeleton; + GError *saved_error; + gboolean fcc_unlock_attempted; + MMModemPowerState requested_power_state; + MMModemPowerState previous_cached_power_state; + MMModemPowerState previous_real_power_state; + + void (*requested_power_setup) (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*requested_power_setup_finish) (MMIfaceModem *self, + GAsyncResult *res, + GError **error); } SetPowerStateContext; static void set_power_state_context_free (SetPowerStateContext *ctx) { + g_assert (!ctx->saved_error); if (ctx->skeleton) g_object_unref (ctx->skeleton); g_slice_free (SetPowerStateContext, ctx); } gboolean -mm_iface_modem_set_power_state_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) +mm_iface_modem_set_power_state_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } +static void set_power_state_step (GTask *task); + static void modem_after_power_up_ready (MMIfaceModem *self, GAsyncResult *res, - GTask *task) + GTask *task) { - GError *error = NULL; + SetPowerStateContext *ctx; - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish (self, res, &error); - if (error) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); + ctx = g_task_get_task_data (task); + g_assert (!ctx->saved_error); + MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish (self, res, &ctx->saved_error); + if (ctx->saved_error) + mm_obj_dbg (self, "failure running after power up step: %s", ctx->saved_error->message); + + ctx->step++; + set_power_state_step (task); } static void -modem_power_up_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) +fcc_unlock_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) { SetPowerStateContext *ctx; - GError *error = NULL; + g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock_finish (self, res, &error)) + mm_obj_dbg (self, "couldn't run FCC unlock: %s", error->message); - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish (self, res, &error); - if (error) { - /* If the real and cached ones are different, set the real one */ - if (ctx->previous_cached_power_state != ctx->previous_real_power_state) - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - mm_dbg ("Modem set in full-power mode..."); - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state); - - /* If we have something to do just after power-up, do it */ - if (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up && - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish) { - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up ( - self, - (GAsyncReadyCallback)modem_after_power_up_ready, - task); - return; - } - - /* Otherwise, we're done */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); + /* always retry, even on reported error */ + ctx->step = SET_POWER_STATE_STEP_UPDATE; + set_power_state_step (task); } static void -modem_power_down_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) +requested_power_setup_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) { SetPowerStateContext *ctx; - GError *error = NULL; ctx = g_task_get_task_data (task); + g_assert (!ctx->saved_error); + if (!ctx->requested_power_setup_finish (self, res, &ctx->saved_error)) + mm_obj_dbg (self, "couldn't update power state: %s", ctx->saved_error->message); - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (self, res, &error); - if (error) { - /* If the real and cached ones are different, set the real one */ - if (ctx->previous_cached_power_state != ctx->previous_real_power_state) - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state); - g_task_return_error (task, error); - } else { - mm_dbg ("Modem set in low-power mode..."); - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state); - g_task_return_boolean (task, TRUE); - } - - g_object_unref (task); + ctx->step++; + set_power_state_step (task); } static void -modem_power_off_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) +set_power_state_load_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) { SetPowerStateContext *ctx; - GError *error = NULL; + g_autoptr(GError) error = NULL; ctx = g_task_get_task_data (task); - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish (self, res, &error); + ctx->previous_real_power_state = MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish (self, res, &error); if (error) { - /* If the real and cached ones are different, set the real one */ - if (ctx->previous_cached_power_state != ctx->previous_real_power_state) - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state); - g_task_return_error (task, error); - } else { - mm_info ("Modem powered off... may no longer be accessible"); - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state); - g_task_return_boolean (task, TRUE); + mm_obj_dbg (self, "couldn't reload current power state: %s", error->message); + /* Default to the cached one */ + ctx->previous_real_power_state = ctx->previous_cached_power_state; } - g_object_unref (task); + ctx->step++; + set_power_state_step (task); } static void -set_power_state (GTask *task) +set_power_state_step (GTask *task) { - MMIfaceModem *self; + MMIfaceModem *self; SetPowerStateContext *ctx; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); + ctx = g_task_get_task_data (task); - /* Already done if we're in the desired power state */ - if (ctx->previous_real_power_state == ctx->power_state) { - mm_dbg ("No need to change power state: already in '%s' power state", - mm_modem_power_state_get_string (ctx->power_state)); - /* If the real and cached ones are different, set the real one */ - if (ctx->previous_cached_power_state != ctx->previous_real_power_state) - mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state); - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } + switch (ctx->step) { + case SET_POWER_STATE_STEP_FIRST: + ctx->step++; + /* fall-through */ - /* Fully powering off the modem? */ - if (ctx->power_state == MM_MODEM_POWER_STATE_OFF) { - /* Error if unsupported */ - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off || - !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "Powering off is not supported by this modem"); - g_object_unref (task); + case SET_POWER_STATE_STEP_LOAD: + /* We cannot really rely on the power state value that we had cached before, + * as the real power status of the modem may also be changed by rfkill. So, + * before updating the current power state, re-check which is the real power + * state. */ + if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish) { + MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state (self, (GAsyncReadyCallback)set_power_state_load_ready, task); return; } + /* If there is no way to load power state, just keep on assuming the cached + * one is also the real one */ + ctx->previous_real_power_state = ctx->previous_cached_power_state; + ctx->step++; + /* fall-through */ - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)modem_power_off_ready, - task); - return; - } + case SET_POWER_STATE_STEP_CHECK: + /* Already done if we're in the desired power state */ + if (ctx->previous_real_power_state == ctx->requested_power_state) { + mm_obj_dbg (self, "no need to change power state: already '%s'", + mm_modem_power_state_get_string (ctx->requested_power_state)); + ctx->step = SET_POWER_STATE_STEP_LAST; + set_power_state_step (task); + return; + } + ctx->step++; + /* fall-through */ + + case SET_POWER_STATE_STEP_UPDATE: + mm_obj_dbg (self, "updating power state: '%s'...", mm_modem_power_state_get_string (ctx->requested_power_state)); - /* Going into low power mode? */ - if (ctx->power_state == MM_MODEM_POWER_STATE_LOW) { /* Error if unsupported */ - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down || - !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "Going into low-power mode is not supported by this modem"); + if (!ctx->requested_power_setup || !ctx->requested_power_setup_finish) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Requested power transition is not supported by this modem"); g_object_unref (task); return; } - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)modem_power_down_ready, - task); + ctx->requested_power_setup (self, (GAsyncReadyCallback)requested_power_setup_ready, task); return; - } - /* Going out of low power mode? */ - if (ctx->power_state == MM_MODEM_POWER_STATE_ON) { - /* Error if unsupported */ - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up || - !MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "Going into full-power mode is not supported by this modem"); - g_object_unref (task); + case SET_POWER_STATE_STEP_FCC_UNLOCK: + /* The FCC unlock operation and update retry should only be done + * if requested by the implementation with MM_CORE_ERROR_RETRY. */ + if ((ctx->requested_power_state == MM_MODEM_POWER_STATE_ON) && + ctx->saved_error && + g_error_matches (ctx->saved_error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY) && + !ctx->fcc_unlock_attempted && + MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock && + MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock_finish) { + mm_obj_dbg (self, "attempting fcc unlock..."); + ctx->fcc_unlock_attempted = TRUE; + g_clear_error (&ctx->saved_error); + MM_IFACE_MODEM_GET_INTERFACE (self)->fcc_unlock (self, (GAsyncReadyCallback)fcc_unlock_ready, task); return; } + ctx->step++; + /* fall-through */ - MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)modem_power_up_ready, - task); + case SET_POWER_STATE_STEP_AFTER_UPDATE: + if ((ctx->requested_power_state == MM_MODEM_POWER_STATE_ON) && + !ctx->saved_error && + MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up && + MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish) { + mm_obj_dbg (self, "running after power up operation..."); + MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up (self, (GAsyncReadyCallback)modem_after_power_up_ready, task); + return; + } + ctx->step++; + /* fall-through */ + + case SET_POWER_STATE_STEP_LAST: + if (ctx->saved_error) { + /* If the real and cached ones are different, set the real one */ + if (ctx->previous_cached_power_state != ctx->previous_real_power_state) + mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state); + g_task_return_error (task, g_steal_pointer (&ctx->saved_error)); + } else { + mm_obj_info (self, "power state updated: %s", mm_modem_power_state_get_string (ctx->requested_power_state)); + mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->requested_power_state); + g_task_return_boolean (task, TRUE); + } + g_object_unref (task); return; - } - g_assert_not_reached (); -} - -static void -set_power_state_load_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - SetPowerStateContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - ctx->previous_real_power_state = MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish (self, res, &error); - if (error) { - mm_dbg ("Couldn't reload current power state: %s", error->message); - g_error_free (error); - /* Default to the cached one */ - ctx->previous_real_power_state = ctx->previous_cached_power_state; + default: + g_assert_not_reached (); } - - /* And keep on */ - set_power_state (task); } void -mm_iface_modem_set_power_state (MMIfaceModem *self, - MMModemPowerState power_state, - GAsyncReadyCallback callback, - gpointer user_data) +mm_iface_modem_set_power_state (MMIfaceModem *self, + MMModemPowerState power_state, + GAsyncReadyCallback callback, + gpointer user_data) { SetPowerStateContext *ctx; - GTask *task; + GTask *task; ctx = g_slice_new0 (SetPowerStateContext); - ctx->power_state = power_state; + ctx->step = SET_POWER_STATE_STEP_FIRST; + ctx->requested_power_state = power_state; task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)set_power_state_context_free); @@ -3743,26 +3952,28 @@ mm_iface_modem_set_power_state (MMIfaceModem *self, g_object_unref (task); return; } - ctx->previous_cached_power_state = mm_gdbus_modem_get_power_state (ctx->skeleton); - /* We cannot really rely on the power state value that we had cached before, - * as the real power status of the modem may also be changed by rfkill. So, - * before updating the current power state, re-check which is the real power - * state. */ - if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state && - MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish) { - MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state ( - self, - (GAsyncReadyCallback)set_power_state_load_ready, - task); - return; + /* Setup requested operation */ + switch (ctx->requested_power_state) { + case MM_MODEM_POWER_STATE_OFF: + ctx->requested_power_setup = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off; + ctx->requested_power_setup_finish = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish; + break; + case MM_MODEM_POWER_STATE_LOW: + ctx->requested_power_setup = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down; + ctx->requested_power_setup_finish = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish; + break; + case MM_MODEM_POWER_STATE_ON: + ctx->requested_power_setup = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up; + ctx->requested_power_setup_finish = MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish; + break; + case MM_MODEM_POWER_STATE_UNKNOWN: + default: + g_assert_not_reached (); } - /* If there is no way to load power state, just keep on assuming the cached - * one is also the real one */ - ctx->previous_real_power_state = ctx->previous_cached_power_state; - set_power_state (task); + set_power_state_step (task); } /*****************************************************************************/ @@ -3800,15 +4011,11 @@ typedef enum { ENABLING_STEP_SET_POWER_STATE, ENABLING_STEP_CHECK_FOR_SIM_SWAP, ENABLING_STEP_FLOW_CONTROL, - ENABLING_STEP_SUPPORTED_CHARSETS, - ENABLING_STEP_CHARSET, ENABLING_STEP_LAST } EnablingStep; struct _EnablingContext { EnablingStep step; - MMModemCharset supported_charsets; - const MMModemCharset *current_charset; MmGdbusModem *skeleton; }; @@ -3857,7 +4064,7 @@ check_for_sim_swap_ready (MMIfaceModem *self, GError *error = NULL; if (!MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish (self, res, &error)) { - mm_warn ("Error checking if SIM was swapped: '%s'", error->message); + mm_obj_warn (self, "failed to check if SIM was swapped: %s", error->message); g_error_free (error); } @@ -3888,52 +4095,6 @@ setup_flow_control_ready (MMIfaceModem *self, interface_enabling_step (task); } -static void -load_supported_charsets_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - EnablingContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - ctx->supported_charsets = - MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish (self, res, &error); - if (error) { - mm_warn ("couldn't load Supported Charsets: '%s'", error->message); - g_error_free (error); - } - - /* Go on to next step */ - ctx->step++; - interface_enabling_step (task); -} - -static void -setup_charset_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - EnablingContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - if (!MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish (self, res, &error)) { - mm_dbg ("couldn't set charset '%s': '%s'", - mm_modem_charset_to_string (*ctx->current_charset), - error->message); - g_error_free (error); - - /* Will retry step with some other charset type */ - } else - /* Done, Go on to next step */ - ctx->step++; - - interface_enabling_step (task); -} - static const MMModemCharset best_charsets[] = { MM_MODEM_CHARSET_UTF8, MM_MODEM_CHARSET_UCS2, @@ -3975,6 +4136,7 @@ interface_enabling_step (GTask *task) MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap_finish) { MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap ( self, + NULL, (GAsyncReadyCallback)check_for_sim_swap_ready, task); return; @@ -3994,59 +4156,6 @@ interface_enabling_step (GTask *task) ctx->step++; /* fall-through */ - case ENABLING_STEP_SUPPORTED_CHARSETS: - if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets && - MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish) { - MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets ( - self, - (GAsyncReadyCallback)load_supported_charsets_ready, - task); - return; - } - ctx->step++; - /* fall-through */ - - case ENABLING_STEP_CHARSET: - /* Only try to set charsets if we were able to load supported ones */ - if (ctx->supported_charsets > 0 && - MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset && - MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish) { - gboolean next_to_try = FALSE; - - while (!next_to_try) { - if (!ctx->current_charset) - /* Switch the device's charset; we prefer UTF-8, but UCS2 will do too */ - ctx->current_charset = &best_charsets[0]; - else - /* Try with the next one */ - ctx->current_charset++; - - if (*ctx->current_charset == MM_MODEM_CHARSET_UNKNOWN) - break; - - if (ctx->supported_charsets & (*ctx->current_charset)) - next_to_try = TRUE; - } - - if (next_to_try) { - MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset ( - self, - *ctx->current_charset, - (GAsyncReadyCallback)setup_charset_ready, - task); - return; - } - - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Failed to find a usable modem character set"); - g_object_unref (task); - return; - } - ctx->step++; - /* fall-through */ - case ENABLING_STEP_LAST: /* We are done without errors! */ g_task_return_boolean (task, TRUE); @@ -4100,6 +4209,8 @@ typedef enum { INITIALIZATION_STEP_FIRST, INITIALIZATION_STEP_CURRENT_CAPABILITIES, INITIALIZATION_STEP_SUPPORTED_CAPABILITIES, + INITIALIZATION_STEP_SUPPORTED_CHARSETS, + INITIALIZATION_STEP_CHARSET, INITIALIZATION_STEP_BEARERS, INITIALIZATION_STEP_MANUFACTURER, INITIALIZATION_STEP_MODEL, @@ -4113,6 +4224,7 @@ typedef enum { INITIALIZATION_STEP_SUPPORTED_IP_FAMILIES, INITIALIZATION_STEP_POWER_STATE, INITIALIZATION_STEP_SIM_HOT_SWAP, + INITIALIZATION_STEP_SIM_SLOTS, INITIALIZATION_STEP_UNLOCK_REQUIRED, INITIALIZATION_STEP_SIM, INITIALIZATION_STEP_SETUP_CARRIER_CONFIG, @@ -4125,6 +4237,8 @@ typedef enum { struct _InitializationContext { InitializationStep step; MmGdbusModem *skeleton; + MMModemCharset supported_charsets; + const MMModemCharset *current_charset; GError *fatal_error; }; @@ -4154,7 +4268,7 @@ initialization_context_free (InitializationContext *ctx) g_free (val); \ \ if (error) { \ - mm_warn ("couldn't load %s: '%s'", DISPLAY, error->message); \ + mm_obj_warn (self, "couldn't load %s: %s", DISPLAY, error->message); \ g_error_free (error); \ } \ \ @@ -4180,7 +4294,7 @@ initialization_context_free (InitializationContext *ctx) MM_IFACE_MODEM_GET_INTERFACE (self)->load_##NAME##_finish (self, res, &error)); \ \ if (error) { \ - mm_warn ("couldn't load %s: '%s'", DISPLAY, error->message); \ + mm_obj_warn (self, "couldn't load %s: %s", DISPLAY, error->message); \ g_error_free (error); \ } \ \ @@ -4214,10 +4328,9 @@ current_capabilities_internal_load_unlock_required_ready (MMIfaceModem *self, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) { MMModemCapability caps; - mm_dbg ("Multimode device without SIM, no 3GPP capabilities"); + mm_obj_dbg (self, "multimode device without SIM, no 3GPP capabilities"); caps = mm_gdbus_modem_get_current_capabilities (ctx->skeleton); - caps &= ~MM_MODEM_CAPABILITY_GSM_UMTS; - caps &= ~MM_MODEM_CAPABILITY_LTE; + caps &= ~MM_MODEM_CAPABILITY_3GPP; /* CDMA-EVDO must still be around */ g_assert (caps & MM_MODEM_CAPABILITY_CDMA_EVDO); @@ -4253,24 +4366,35 @@ load_current_capabilities_ready (MMIfaceModem *self, return; } - /* If LTE capability is reported, enable EPS network registration checks */ + /* By default CS/PS/CDMA1X/EVDO network registration checks are the only + * ones enabled, so fix them up based on capabilities, enabling EPS or 5GS + * checks if required, and disabling CS/PS/CDMA1X/EVDO if required. */ if (caps & MM_MODEM_CAPABILITY_LTE) { - mm_dbg ("Setting EPS network as supported"); + mm_obj_dbg (self, "setting EPS network as supported"); g_object_set (G_OBJECT (self), MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, TRUE, NULL); } - - /* If LTE capability is the only one reported, disable all other network registration checks */ - if (caps == MM_MODEM_CAPABILITY_LTE) { - mm_dbg ("Setting CS/PS/CDMA1x/EVDO networks as unsupported"); + if (caps & MM_MODEM_CAPABILITY_5GNR) { + mm_obj_dbg (self, "setting 5GS network as supported"); + g_object_set (G_OBJECT (self), + MM_IFACE_MODEM_3GPP_5GS_NETWORK_SUPPORTED, TRUE, + NULL); + } + if (!(caps & MM_MODEM_CAPABILITY_CDMA_EVDO)) { + mm_obj_dbg (self, "setting CDMA1x/EVDO networks as unsupported"); g_object_set (G_OBJECT (self), - MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, FALSE, - MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, FALSE, MM_IFACE_MODEM_CDMA_CDMA1X_NETWORK_SUPPORTED, FALSE, MM_IFACE_MODEM_CDMA_EVDO_NETWORK_SUPPORTED, FALSE, NULL); } + if (!(caps & MM_MODEM_CAPABILITY_GSM_UMTS)) { + mm_obj_dbg (self, "setting CS/PS networks as unsupported"); + g_object_set (G_OBJECT (self), + MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, FALSE, + MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, FALSE, + NULL); + } /* Update current caps right away, even if we may fix them during the * multimode device check. No big deal in updating them twice, as we're not @@ -4279,9 +4403,8 @@ load_current_capabilities_ready (MMIfaceModem *self, /* If the device is a multimode device (3GPP+3GPP2) check whether we have a * SIM or not. */ - if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO && - (caps & MM_MODEM_CAPABILITY_GSM_UMTS || caps & MM_MODEM_CAPABILITY_LTE)) { - mm_dbg ("Checking if multimode device has a SIM..."); + if ((caps & MM_MODEM_CAPABILITY_CDMA_EVDO) && (caps & MM_MODEM_CAPABILITY_3GPP)) { + mm_obj_dbg (self, "checking if multimode device has a SIM..."); internal_load_unlock_required ( self, (GAsyncReadyCallback)current_capabilities_internal_load_unlock_required_ready, @@ -4323,12 +4446,58 @@ load_supported_capabilities_ready (MMIfaceModem *self, interface_initialization_step (task); } -STR_REPLY_READY_FN (manufacturer, "Manufacturer") -STR_REPLY_READY_FN (model, "Model") -STR_REPLY_READY_FN (revision, "Revision") -STR_REPLY_READY_FN (hardware_revision, "HardwareRevision") -STR_REPLY_READY_FN (equipment_identifier, "Equipment Identifier") -STR_REPLY_READY_FN (device_identifier, "Device Identifier") +STR_REPLY_READY_FN (manufacturer, "manufacturer") +STR_REPLY_READY_FN (model, "model") +STR_REPLY_READY_FN (revision, "revision") +STR_REPLY_READY_FN (hardware_revision, "hardware revision") +STR_REPLY_READY_FN (equipment_identifier, "equipment identifier") +STR_REPLY_READY_FN (device_identifier, "device identifier") + +static void +load_supported_charsets_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + InitializationContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + ctx->supported_charsets = + MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish (self, res, &error); + if (error) { + mm_obj_warn (self, "couldn't load supported charsets: %s", error->message); + g_error_free (error); + } + + /* Go on to next step */ + ctx->step++; + interface_initialization_step (task); +} + +static void +setup_charset_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + InitializationContext *ctx; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish (self, res, &error)) { + mm_obj_dbg (self, "couldn't set charset '%s': %s", + mm_modem_charset_to_string (*ctx->current_charset), + error->message); + g_error_free (error); + + /* Will retry step with some other charset type */ + } else + /* Done, Go on to next step */ + ctx->step++; + + interface_initialization_step (task); +} static void load_supported_modes_ready (MMIfaceModem *self, @@ -4349,7 +4518,7 @@ load_supported_modes_ready (MMIfaceModem *self, } if (error) { - mm_warn ("couldn't load Supported Modes: '%s'", error->message); + mm_obj_warn (self, "couldn't load supported modes: %s", error->message); g_error_free (error); } @@ -4378,7 +4547,7 @@ load_supported_bands_ready (MMIfaceModem *self, } if (error) { - mm_warn ("couldn't load Supported Bands: '%s'", error->message); + mm_obj_warn (self, "couldn't load supported bands: %s", error->message); g_error_free (error); } @@ -4404,7 +4573,7 @@ load_supported_ip_families_ready (MMIfaceModem *self, mm_gdbus_modem_set_supported_ip_families (ctx->skeleton, ip_families); if (error) { - mm_warn ("couldn't load Supported IP families: '%s'", error->message); + mm_obj_warn (self, "couldn't load supported IP families: %s", error->message); g_error_free (error); } @@ -4413,7 +4582,99 @@ load_supported_ip_families_ready (MMIfaceModem *self, interface_initialization_step (task); } -UINT_REPLY_READY_FN (power_state, "Power State") +UINT_REPLY_READY_FN (power_state, "power state") + +static void +setup_sim_hot_swap_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + InitializationContext *ctx; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + + MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish (self, res, &error); + if (error) + mm_obj_warn (self, "SIM hot swap setup failed: %s", error->message); + else { + mm_obj_dbg (self, "SIM hot swap setup succeeded"); + g_object_set (self, + MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, TRUE, + NULL); + } + + /* Go on to next step */ + ctx->step++; + interface_initialization_step (task); +} + +static void +load_sim_slots_ready (MMIfaceModem *self, + GAsyncResult *res, + GTask *task) +{ + InitializationContext *ctx; + g_autoptr(GPtrArray) sim_slots = NULL; + g_autoptr(GError) error = NULL; + guint primary_sim_slot = 0; + + ctx = g_task_get_task_data (task); + + if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish (self, + res, + &sim_slots, + &primary_sim_slot, + &error)) + mm_obj_warn (self, "couldn't query SIM slots: %s", error->message); + + if (sim_slots) { + MMBaseSim *primary_sim = NULL; + GPtrArray *sim_slot_paths_array; + g_auto(GStrv) sim_slot_paths = NULL; + guint i; + + g_assert (primary_sim_slot); + g_assert_cmpuint (primary_sim_slot, <=, sim_slots->len); + + sim_slot_paths_array = g_ptr_array_new (); + for (i = 0; i < sim_slots->len; i++) { + MMBaseSim *sim; + const gchar *sim_path; + + sim = MM_BASE_SIM (g_ptr_array_index (sim_slots, i)); + if (!sim) { + g_ptr_array_add (sim_slot_paths_array, g_strdup ("/")); + continue; + } + + sim_path = mm_base_sim_get_path (sim); + g_ptr_array_add (sim_slot_paths_array, g_strdup (sim_path)); + } + g_ptr_array_add (sim_slot_paths_array, NULL); + sim_slot_paths = (GStrv) g_ptr_array_free (sim_slot_paths_array, FALSE); + + mm_gdbus_modem_set_sim_slots (ctx->skeleton, (const gchar *const *)sim_slot_paths); + mm_gdbus_modem_set_primary_sim_slot (ctx->skeleton, primary_sim_slot); + + /* If loading SIM slots is supported, we also expose already the primary active SIM object */ + if (primary_sim_slot) { + primary_sim = g_ptr_array_index (sim_slots, primary_sim_slot - 1); + if (primary_sim) + g_object_bind_property (primary_sim, MM_BASE_SIM_PATH, + ctx->skeleton, "sim", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + } + g_object_set (self, + MM_IFACE_MODEM_SIM, primary_sim, + MM_IFACE_MODEM_SIM_SLOTS, sim_slots, + NULL); + } + + /* Go on to next step */ + ctx->step++; + interface_initialization_step (task); +} static void modem_update_lock_info_ready (MMIfaceModem *self, @@ -4453,7 +4714,7 @@ sim_new_ready (GAsyncInitable *initable, sim = MM_IFACE_MODEM_GET_INTERFACE (self)->create_sim_finish (self, res, &error); if (error) { - mm_warn ("couldn't create SIM: '%s'", error->message); + mm_obj_warn (self, "couldn't create SIM: %s", error->message); g_task_return_error (task, error); g_object_unref (task); return; @@ -4482,14 +4743,16 @@ sim_reinit_ready (MMBaseSim *sim, GAsyncResult *res, GTask *task) { + MMIfaceModem *self; InitializationContext *ctx; - GError *error = NULL; + GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!mm_base_sim_initialize_finish (sim, res, &error)) { - mm_warn ("SIM re-initialization failed: '%s'", - error ? error->message : "Unknown error"); + mm_obj_warn (self, "SIM re-initialization failed: %s", + error ? error->message : "Unknown error"); g_clear_error (&error); } @@ -4509,7 +4772,7 @@ setup_carrier_config_ready (MMIfaceModem *self, ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_GET_INTERFACE (self)->setup_carrier_config_finish (self, res, &error)) { - mm_warn ("couldn't setup carrier config: '%s'", error->message); + mm_obj_warn (self, "couldn't setup carrier config: %s", error->message); g_error_free (error); } @@ -4531,7 +4794,7 @@ load_carrier_config_ready (MMIfaceModem *self, ctx = g_task_get_task_data (task); if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_carrier_config_finish (self, res, &name, &revision, &error)) { - mm_warn ("couldn't load carrier config: '%s'", error->message); + mm_obj_warn (self, "couldn't load carrier config: %s", error->message); g_error_free (error); } else { mm_gdbus_modem_set_carrier_configuration (ctx->skeleton, name); @@ -4573,7 +4836,7 @@ load_own_numbers_ready (MMIfaceModem *self, str_list = MM_IFACE_MODEM_GET_INTERFACE (self)->load_own_numbers_finish (self, res, &error); if (error) { - mm_warn ("couldn't load list of Own Numbers: '%s'", error->message); + mm_obj_warn (self, "couldn't load list of own numbers: %s", error->message); g_error_free (error); } @@ -4605,7 +4868,7 @@ load_current_modes_ready (MMIfaceModem *self, &preferred, &error)) { /* Errors when getting allowed/preferred won't be critical */ - mm_warn ("couldn't load current allowed/preferred modes: '%s'", error->message); + mm_obj_warn (self, "couldn't load current allowed/preferred modes: %s", error->message); g_error_free (error); } else mm_gdbus_modem_set_current_modes (ctx->skeleton, g_variant_new ("(uu)", allowed, preferred)); @@ -4629,7 +4892,7 @@ load_current_bands_ready (MMIfaceModem *self, current_bands = MM_IFACE_MODEM_GET_INTERFACE (self)->load_current_bands_finish (self, res, &error); if (!current_bands) { /* Errors when getting current bands won't be critical */ - mm_warn ("couldn't load current Bands: '%s'", error->message); + mm_obj_warn (self, "couldn't load current bands: %s", error->message); g_error_free (error); } else { GArray *filtered_bands; @@ -4656,34 +4919,6 @@ load_current_bands_ready (MMIfaceModem *self, interface_initialization_step (task); } -/*****************************************************************************/ -/* Setup SIM hot swap (Modem interface) */ -static void -setup_sim_hot_swap_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - InitializationContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish (self, res, &error); - if (error) { - mm_warn ("Iface modem: SIM hot swap setup failed: '%s'", error->message); - g_error_free (error); - } else { - mm_dbg ("Iface modem: SIM hot swap setup succeeded"); - g_object_set (self, - MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, TRUE, - NULL); - } - - /* Go on to next step */ - ctx->step++; - interface_initialization_step (task); -} - static void interface_initialization_step (GTask *task) { @@ -4741,11 +4976,12 @@ interface_initialization_step (GTask *task) MMPort *primary = NULL; #if defined WITH_QMI - primary = MM_PORT (mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self))); + if (MM_IS_BROADBAND_MODEM_QMI (self)) + primary = MM_PORT (mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self))); #endif #if defined WITH_MBIM - if (!primary) - primary = MM_PORT (mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self))); + if (!primary && MM_IS_BROADBAND_MODEM_MBIM (self)) + primary = MM_PORT (mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self))); #endif if (!primary) primary = MM_PORT (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self))); @@ -4819,6 +5055,54 @@ interface_initialization_step (GTask *task) ctx->step++; } /* fall-through */ + case INITIALIZATION_STEP_SUPPORTED_CHARSETS: + if (MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets_finish) { + MM_IFACE_MODEM_GET_INTERFACE (self)->load_supported_charsets ( + self, + (GAsyncReadyCallback)load_supported_charsets_ready, + task); + return; + } + ctx->step++; + /* fall-through */ + + case INITIALIZATION_STEP_CHARSET: + /* Only try to set charsets if we were able to load supported ones */ + if (ctx->supported_charsets > 0 && + MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset && + MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset_finish) { + gboolean next_to_try = FALSE; + + while (!next_to_try) { + if (!ctx->current_charset) + /* Switch the device's charset; we prefer UTF-8, but UCS2 will do too */ + ctx->current_charset = &best_charsets[0]; + else + /* Try with the next one */ + ctx->current_charset++; + + if (*ctx->current_charset == MM_MODEM_CHARSET_UNKNOWN) + break; + + if (ctx->supported_charsets & (*ctx->current_charset)) + next_to_try = TRUE; + } + + if (next_to_try) { + MM_IFACE_MODEM_GET_INTERFACE (self)->setup_charset ( + self, + *ctx->current_charset, + (GAsyncReadyCallback)setup_charset_ready, + task); + return; + } + + mm_obj_warn (self, "Failed to find usable modem character set, let it to UNKNOWN"); + } + ctx->step++; + /* fall-through */ + case INITIALIZATION_STEP_BEARERS: { MMBearerList *list = NULL; @@ -4835,7 +5119,7 @@ interface_initialization_step (GTask *task) /* The maximum number of available/connected modems is guessed from * the size of the data ports list. */ n = g_list_length (mm_base_modem_peek_data_ports (MM_BASE_MODEM (self))); - mm_dbg ("Modem allows up to %u bearers", n); + mm_obj_dbg (self, "allowed up to %u bearers", n); /* Create new default list */ list = mm_bearer_list_new (n, n); @@ -5066,8 +5350,14 @@ interface_initialization_step (GTask *task) ctx->step++; /* fall-through */ - case INITIALIZATION_STEP_SIM_HOT_SWAP: - if (MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap && + case INITIALIZATION_STEP_SIM_HOT_SWAP: { + gboolean sim_hot_swap_configured = FALSE; + + g_object_get (self, + MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, &sim_hot_swap_configured, + NULL); + if (!sim_hot_swap_configured && + MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap && MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap_finish) { MM_IFACE_MODEM_GET_INTERFACE (self)->setup_sim_hot_swap ( MM_IFACE_MODEM (self), @@ -5076,6 +5366,22 @@ interface_initialization_step (GTask *task) return; } ctx->step++; + } /* fall-through */ + + case INITIALIZATION_STEP_SIM_SLOTS: + /* If the modem doesn't need any SIM (not implemented by plugin, or not + * needed in CDMA-only modems), or if we don't know how to query + * for SIM slots */ + if (!mm_gdbus_modem_get_sim_slots (ctx->skeleton) && + !mm_iface_modem_is_cdma_only (self) && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots && + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots_finish) { + MM_IFACE_MODEM_GET_INTERFACE (self)->load_sim_slots (MM_IFACE_MODEM (self), + (GAsyncReadyCallback)load_sim_slots_ready, + task); + return; + } + ctx->step++; /* fall-through */ case INITIALIZATION_STEP_UNLOCK_REQUIRED: @@ -5140,9 +5446,9 @@ interface_initialization_step (GTask *task) /* If we have a SIM object, and carrier config switching is supported, * validate whether we're already using the best config or not. */ if (!sim) - mm_dbg ("not setting up carrier config: SIM not found"); + mm_obj_dbg (self, "not setting up carrier config: SIM not found"); else if (!carrier_config_mapping) - mm_dbg ("not setting up carrier config: mapping file not configured"); + mm_obj_dbg (self, "not setting up carrier config: mapping file not configured"); else { const gchar *imsi; @@ -5157,7 +5463,7 @@ interface_initialization_step (GTask *task) g_free (carrier_config_mapping); return; } - mm_warn ("couldn't setup carrier config: unknown IMSI"); + mm_obj_warn (self, "couldn't setup carrier config: unknown IMSI"); } g_clear_object (&sim); g_free (carrier_config_mapping); @@ -5266,6 +5572,7 @@ interface_initialization_step (GTask *task) "signal::handle-enable", G_CALLBACK (handle_enable), self, "signal::handle-set-current-bands", G_CALLBACK (handle_set_current_bands), self, "signal::handle-set-current-modes", G_CALLBACK (handle_set_current_modes), self, + "signal::handle-set-primary-sim-slot", G_CALLBACK (handle_set_primary_sim_slot), self, NULL); /* Finally, export the new interface, even if we got errors, but only if not @@ -5511,6 +5818,22 @@ mm_iface_modem_is_4g_only (MMIfaceModem *self) FALSE); } +gboolean +mm_iface_modem_is_5g (MMIfaceModem *self) +{ + return find_supported_mode (self, MM_MODEM_MODE_5G, NULL); +} + +gboolean +mm_iface_modem_is_5g_only (MMIfaceModem *self) +{ + gboolean only; + + return (find_supported_mode (self, MM_MODEM_MODE_5G, &only) ? + only : + FALSE); +} + /*****************************************************************************/ MMModemCapability @@ -5540,40 +5863,34 @@ mm_iface_modem_is_3gpp (MMIfaceModem *self) gboolean mm_iface_modem_is_3gpp_lte (MMIfaceModem *self) { - return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_3GPP_LTE); + return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_LTE); } gboolean -mm_iface_modem_is_cdma (MMIfaceModem *self) +mm_iface_modem_is_3gpp_5gnr (MMIfaceModem *self) { - return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_CDMA_EVDO); + return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_5GNR); } gboolean -mm_iface_modem_is_3gpp_only (MMIfaceModem *self) +mm_iface_modem_is_cdma (MMIfaceModem *self) { - MMModemCapability capabilities; - - capabilities = mm_iface_modem_get_current_capabilities (self); - return (capabilities & MM_MODEM_CAPABILITY_3GPP) && !((MM_MODEM_CAPABILITY_3GPP ^ capabilities) & capabilities); + return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_CDMA_EVDO); } gboolean -mm_iface_modem_is_3gpp_lte_only (MMIfaceModem *self) +mm_iface_modem_is_3gpp_only (MMIfaceModem *self) { MMModemCapability capabilities; capabilities = mm_iface_modem_get_current_capabilities (self); - return (capabilities & MM_MODEM_CAPABILITY_3GPP_LTE) && !((MM_MODEM_CAPABILITY_3GPP_LTE ^ capabilities) & capabilities); + return (capabilities & MM_MODEM_CAPABILITY_3GPP) && !((MM_MODEM_CAPABILITY_3GPP ^ capabilities) & capabilities); } gboolean mm_iface_modem_is_cdma_only (MMIfaceModem *self) { - MMModemCapability capabilities; - - capabilities = mm_iface_modem_get_current_capabilities (self); - return (capabilities & MM_MODEM_CAPABILITY_CDMA_EVDO) && !((MM_MODEM_CAPABILITY_CDMA_EVDO ^ capabilities) & capabilities); + return (mm_iface_modem_get_current_capabilities (self) == MM_MODEM_CAPABILITY_CDMA_EVDO); } /*****************************************************************************/ @@ -5662,6 +5979,14 @@ iface_modem_init (gpointer g_iface) MM_TYPE_BASE_SIM, G_PARAM_READWRITE)); + g_object_interface_install_property + (g_iface, + g_param_spec_boxed (MM_IFACE_MODEM_SIM_SLOTS, + "SIM slots", + "SIM objects in SIM slots", + MM_TYPE_OBJECT_ARRAY, + G_PARAM_READWRITE)); + g_object_interface_install_property (g_iface, g_param_spec_enum (MM_IFACE_MODEM_STATE, diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h index c4aba7aa..84495db7 100644 --- a/src/mm-iface-modem.h +++ b/src/mm-iface-modem.h @@ -35,6 +35,7 @@ #define MM_IFACE_MODEM_DBUS_SKELETON "iface-modem-dbus-skeleton" #define MM_IFACE_MODEM_STATE "iface-modem-state" #define MM_IFACE_MODEM_SIM "iface-modem-sim" +#define MM_IFACE_MODEM_SIM_SLOTS "iface-modem-sim-slots" #define MM_IFACE_MODEM_BEARER_LIST "iface-modem-bearer-list" #define MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED "iface-modem-sim-hot-swap-supported" #define MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED "iface-modem-sim-hot-swap-configured" @@ -268,6 +269,14 @@ struct _MMIfaceModem { GAsyncResult *res, GError **error); + /* Asynchronous FCC unlock operation */ + void (* fcc_unlock) (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* fcc_unlock_finish) (MMIfaceModem *self, + GAsyncResult *res, + GError **error); + /* Asynchronous modem power-up operation */ void (*modem_power_up) (MMIfaceModem *self, GAsyncReadyCallback callback, @@ -289,6 +298,7 @@ struct _MMIfaceModem { * Useful for when the modem changes power states since we might * not get the relevant notifications from the modem. */ void (*check_for_sim_swap) (MMIfaceModem *self, + const gchar *iccid, GAsyncReadyCallback callback, gpointer user_data); gboolean (*check_for_sim_swap_finish) (MMIfaceModem *self, @@ -343,6 +353,25 @@ struct _MMIfaceModem { GAsyncResult *res, GError **error); + /* Create SIMs in all SIM slots */ + void (* load_sim_slots) (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* load_sim_slots_finish) (MMIfaceModem *self, + GAsyncResult *res, + GPtrArray **sim_slots, + guint *primary_sim_slot, + GError **error); + + /* Set primary SIM slot */ + void (* set_primary_sim_slot) (MMIfaceModem *self, + guint sim_slot, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* set_primary_sim_slot_finish) (MMIfaceModem *self, + GAsyncResult *res, + GError **error); + /* Create bearer */ void (*create_bearer) (MMIfaceModem *self, MMBearerProperties *properties, @@ -382,6 +411,7 @@ struct _MMIfaceModem { }; GType mm_iface_modem_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMIfaceModem, g_object_unref) /* Helpers to query access technologies */ MMModemAccessTechnology mm_iface_modem_get_access_technologies (MMIfaceModem *self); @@ -391,7 +421,7 @@ MMModemCapability mm_iface_modem_get_current_capabilities (MMIfaceModem *self); gboolean mm_iface_modem_is_3gpp (MMIfaceModem *self); gboolean mm_iface_modem_is_3gpp_only (MMIfaceModem *self); gboolean mm_iface_modem_is_3gpp_lte (MMIfaceModem *self); -gboolean mm_iface_modem_is_3gpp_lte_only (MMIfaceModem *self); +gboolean mm_iface_modem_is_3gpp_5gnr (MMIfaceModem *self); gboolean mm_iface_modem_is_cdma (MMIfaceModem *self); gboolean mm_iface_modem_is_cdma_only (MMIfaceModem *self); @@ -402,6 +432,8 @@ gboolean mm_iface_modem_is_3g (MMIfaceModem *self); gboolean mm_iface_modem_is_3g_only (MMIfaceModem *self); gboolean mm_iface_modem_is_4g (MMIfaceModem *self); gboolean mm_iface_modem_is_4g_only (MMIfaceModem *self); +gboolean mm_iface_modem_is_5g (MMIfaceModem *self); +gboolean mm_iface_modem_is_5g_only (MMIfaceModem *self); /* Helpers to query properties */ const gchar *mm_iface_modem_get_model (MMIfaceModem *self); @@ -460,7 +492,8 @@ MMModemLock mm_iface_modem_update_lock_info_finish (MMIfaceModem *self, GAsyncResult *res, GError **error); -MMUnlockRetries *mm_iface_modem_get_unlock_retries (MMIfaceModem *self); +MMModemLock mm_iface_modem_get_unlock_required (MMIfaceModem *self); +MMUnlockRetries *mm_iface_modem_get_unlock_retries (MMIfaceModem *self); void mm_iface_modem_update_unlock_retries (MMIfaceModem *self, MMUnlockRetries *unlock_retries); @@ -543,4 +576,14 @@ MMModemState mm_iface_modem_wait_for_final_state_finish (MMIfaceModem *self, void mm_iface_modem_bind_simple_status (MMIfaceModem *self, MMSimpleStatus *status); +/* Check if the SIM or eSIM profile has changed */ +void mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, + guint slot_index, + const gchar *iccid, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_iface_modem_check_for_sim_swap_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); + #endif /* MM_IFACE_MODEM_H */ diff --git a/src/mm-log-object.c b/src/mm-log-object.c new file mode 100644 index 00000000..ed41355f --- /dev/null +++ b/src/mm-log-object.c @@ -0,0 +1,89 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2020 Aleksander Morgado + */ + +#include "mm-log-object.h" + +G_DEFINE_INTERFACE (MMLogObject, mm_log_object, G_TYPE_OBJECT) + +/*****************************************************************************/ +/* Private data context */ + +#define PRIVATE_TAG "log-object" +static GQuark private_quark; + +typedef struct { + gchar *owner_id; + gchar *id; +} Private; + +static void +private_free (Private *priv) +{ + g_free (priv->owner_id); + g_free (priv->id); + g_slice_free (Private, priv); +} + +static Private * +get_private (MMLogObject *self) +{ + Private *priv; + + if (G_UNLIKELY (!private_quark)) + private_quark = g_quark_from_static_string (PRIVATE_TAG); + + priv = g_object_get_qdata (G_OBJECT (self), private_quark); + if (!priv) { + priv = g_slice_new0 (Private); + g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free); + } + + return priv; +} + +const gchar * +mm_log_object_get_id (MMLogObject *self) +{ + Private *priv; + + priv = get_private (self); + if (!priv->id) { + gchar *self_id; + + self_id = MM_LOG_OBJECT_GET_IFACE (self)->build_id (self); + if (priv->owner_id) { + priv->id = g_strdup_printf ("%s/%s", priv->owner_id, self_id); + g_free (self_id); + } else + priv->id = self_id; + } + return priv->id; +} + +void +mm_log_object_set_owner_id (MMLogObject *self, + const gchar *owner_id) +{ + Private *priv; + + priv = get_private (self); + g_free (priv->owner_id); + priv->owner_id = g_strdup (owner_id); +} + +static void +mm_log_object_default_init (MMLogObjectInterface *iface) +{ +} diff --git a/src/mm-log-object.h b/src/mm-log-object.h new file mode 100644 index 00000000..21ffc05e --- /dev/null +++ b/src/mm-log-object.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2020 Aleksander Morgado + */ + +#ifndef MM_LOG_OBJECT_H +#define MM_LOG_OBJECT_H + +#include +#include + +#include "mm-log.h" + +#define MM_TYPE_LOG_OBJECT mm_log_object_get_type () +G_DECLARE_INTERFACE (MMLogObject, mm_log_object, MM, LOG_OBJECT, GObject) + +struct _MMLogObjectInterface +{ + GTypeInterface g_iface; + + gchar * (* build_id) (MMLogObject *self); +}; + +const gchar *mm_log_object_get_id (MMLogObject *self); +void mm_log_object_set_owner_id (MMLogObject *self, + const gchar *owner_id); + +#endif /* MM_LOG_OBJECT_H */ diff --git a/src/mm-log-test.h b/src/mm-log-test.h new file mode 100644 index 00000000..22493d6d --- /dev/null +++ b/src/mm-log-test.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2020 Aleksander Morgado + */ + +#ifndef MM_LOG_TEST_H +#define MM_LOG_TEST_H + +#include +#include "mm-log.h" + +/* This is a common logging method to be used by all test applications */ + +void +_mm_log (gpointer obj, + const gchar *module, + const gchar *loc, + const gchar *func, + guint32 level, + const gchar *fmt, + ...) +{ + va_list args; + gchar *msg; + + if (!g_test_verbose ()) + return; + + va_start (args, fmt); + msg = g_strdup_vprintf (fmt, args); + va_end (args); + g_print ("%s\n", msg); + g_free (msg); +} + +#endif /* MM_LOG_TEST_H */ diff --git a/src/mm-log.c b/src/mm-log.c index 470f1881..c59af2e0 100644 --- a/src/mm-log.c +++ b/src/mm-log.c @@ -10,7 +10,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011-2020 Red Hat, Inc. + * Copyright (C) 2020 Aleksander Morgado */ #define _GNU_SOURCE @@ -41,6 +42,7 @@ #endif #include "mm-log.h" +#include "mm-log-object.h" enum { TS_FLAG_NONE = 0, @@ -74,7 +76,7 @@ static const LogDesc level_descs[] = { }; static GString *msgbuf = NULL; -static volatile gsize msgbuf_once = 0; +static gsize msgbuf_once = 0; static int mm_to_syslog_priority (MMLogLevel level) @@ -98,6 +100,11 @@ mm_to_syslog_priority (MMLogLevel level) static int glib_to_syslog_priority (GLogLevelFlags level) { + /* if the log was flagged as fatal (e.g. G_DEBUG=fatal-warnings), ignore + * the fatal flag for logging purposes */ + if (level & G_LOG_FLAG_FATAL) + level &= ~G_LOG_FLAG_FATAL; + switch (level) { case G_LOG_LEVEL_ERROR: return LOG_CRIT; @@ -200,10 +207,12 @@ log_backend_systemd_journal (const char *loc, #endif void -_mm_log (const char *loc, - const char *func, - MMLogLevel level, - const char *fmt, +_mm_log (gpointer obj, + const gchar *module, + const gchar *loc, + const gchar *func, + MMLogLevel level, + const gchar *fmt, ...) { va_list args; @@ -243,6 +252,11 @@ _mm_log (const char *loc, g_string_append_printf (msgbuf, "[%s] %s(): ", loc, func); #endif + if (obj) + g_string_append_printf (msgbuf, "[%s] ", mm_log_object_get_id (MM_LOG_OBJECT (obj))); + if (module) + g_string_append_printf (msgbuf, "(%s) ", module); + va_start (args, fmt); g_string_append_vprintf (msgbuf, fmt, args); va_end (args); diff --git a/src/mm-log.h b/src/mm-log.h index d9f11f27..d0b5c607 100644 --- a/src/mm-log.h +++ b/src/mm-log.h @@ -10,7 +10,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011-2020 Red Hat, Inc. + * Copyright (C) 2020 Aleksander Morgado */ #ifndef MM_LOG_H @@ -26,26 +27,31 @@ typedef enum { MM_LOG_LEVEL_DEBUG = 0x00000008 } MMLogLevel; -#define mm_err(...) \ - _mm_log (G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_ERR, ## __VA_ARGS__ ) +#if !defined MM_MODULE_NAME +# define MM_MODULE_NAME (const gchar *)NULL +#endif -#define mm_warn(...) \ - _mm_log (G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_WARN, ## __VA_ARGS__ ) +#define mm_obj_err(obj, ...) _mm_log (obj, MM_MODULE_NAME, G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_ERR, ## __VA_ARGS__ ) +#define mm_obj_warn(obj, ...) _mm_log (obj, MM_MODULE_NAME, G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_WARN, ## __VA_ARGS__ ) +#define mm_obj_info(obj, ...) _mm_log (obj, MM_MODULE_NAME, G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_INFO, ## __VA_ARGS__ ) +#define mm_obj_dbg(obj, ...) _mm_log (obj, MM_MODULE_NAME, G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_DEBUG, ## __VA_ARGS__ ) -#define mm_info(...) \ - _mm_log (G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_INFO, ## __VA_ARGS__ ) +/* only allow using non-object logging API if explicitly requested + * (e.g. in the main daemon source) */ +#if defined MM_LOG_NO_OBJECT +# define mm_err(...) mm_obj_err (NULL, ## __VA_ARGS__ ) +# define mm_warn(...) mm_obj_warn (NULL, ## __VA_ARGS__ ) +# define mm_info(...) mm_obj_info (NULL, ## __VA_ARGS__ ) +# define mm_dbg(...) mm_obj_dbg (NULL, ## __VA_ARGS__ ) +#endif -#define mm_dbg(...) \ - _mm_log (G_STRLOC, G_STRFUNC, MM_LOG_LEVEL_DEBUG, ## __VA_ARGS__ ) - -#define mm_log(level, ...) \ - _mm_log (G_STRLOC, G_STRFUNC, level, ## __VA_ARGS__ ) - -void _mm_log (const char *loc, - const char *func, - MMLogLevel level, - const char *fmt, - ...) __attribute__((__format__ (__printf__, 4, 5))); +void _mm_log (gpointer obj, + const gchar *module, + const gchar *loc, + const gchar *func, + MMLogLevel level, + const gchar *fmt, + ...) __attribute__((__format__ (__printf__, 6, 7))); gboolean mm_log_set_level (const char *level, GError **error); diff --git a/src/mm-modem-helpers-mbim.c b/src/mm-modem-helpers-mbim.c index eb68467e..e418969f 100644 --- a/src/mm-modem-helpers-mbim.c +++ b/src/mm-modem-helpers-mbim.c @@ -17,13 +17,16 @@ #include "mm-modem-helpers.h" #include "mm-enums-types.h" #include "mm-errors-types.h" -#include "mm-log.h" +#include "mm-log-object.h" + +#include /*****************************************************************************/ MMModemCapability -mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class, - MbimDataClass caps_data_class) +mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class, + MbimDataClass caps_data_class, + const gchar *caps_custom_data_class) { MMModemCapability mask = 0; @@ -38,6 +41,12 @@ mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class if (caps_data_class & MBIM_DATA_CLASS_LTE) mask |= MM_MODEM_CAPABILITY_LTE; + if ((caps_data_class & MBIM_DATA_CLASS_CUSTOM) && caps_custom_data_class) { + /* e.g. Gosuncn GM800 reports MBIM custom data class "5G/TDS" */ + if (strstr (caps_custom_data_class, "5G")) + mask |= MM_MODEM_CAPABILITY_5GNR; + } + return mask; } @@ -367,6 +376,7 @@ mm_bearer_allowed_auth_from_mbim_auth_protocol (MbimAuthProtocol auth_protocol) MbimAuthProtocol mm_bearer_allowed_auth_to_mbim_auth_protocol (MMBearerAllowedAuth bearer_auth, + gpointer log_object, GError **error) { gchar *str; @@ -374,13 +384,13 @@ mm_bearer_allowed_auth_to_mbim_auth_protocol (MMBearerAllowedAuth bearer_auth, /* NOTE: the input is a BITMASK, so we try to find a "best match" */ if (bearer_auth == MM_BEARER_ALLOWED_AUTH_UNKNOWN) { - mm_dbg ("Using default (PAP) authentication method"); - return MBIM_AUTH_PROTOCOL_PAP; + mm_obj_dbg (log_object, "using default (CHAP) authentication method"); + return MBIM_AUTH_PROTOCOL_CHAP; } - if (bearer_auth & MM_BEARER_ALLOWED_AUTH_PAP) - return MBIM_AUTH_PROTOCOL_PAP; if (bearer_auth & MM_BEARER_ALLOWED_AUTH_CHAP) return MBIM_AUTH_PROTOCOL_CHAP; + if (bearer_auth & MM_BEARER_ALLOWED_AUTH_PAP) + return MBIM_AUTH_PROTOCOL_PAP; if (bearer_auth & MM_BEARER_ALLOWED_AUTH_MSCHAPV2) return MBIM_AUTH_PROTOCOL_MSCHAPV2; if (bearer_auth & MM_BEARER_ALLOWED_AUTH_NONE) diff --git a/src/mm-modem-helpers-mbim.h b/src/mm-modem-helpers-mbim.h index a648cac9..9cebe95f 100644 --- a/src/mm-modem-helpers-mbim.h +++ b/src/mm-modem-helpers-mbim.h @@ -24,8 +24,9 @@ /*****************************************************************************/ /* MBIM/BasicConnect to MM translations */ -MMModemCapability mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class, - MbimDataClass caps_data_class); +MMModemCapability mm_modem_capability_from_mbim_device_caps (MbimCellularClass caps_cellular_class, + MbimDataClass caps_data_class, + const gchar *caps_custom_data_class); MMModemLock mm_modem_lock_from_mbim_pin_type (MbimPinType pin_type); @@ -41,6 +42,7 @@ GError *mm_mobile_equipment_error_from_mbim_nw_error (MbimNwError nw_error); MMBearerAllowedAuth mm_bearer_allowed_auth_from_mbim_auth_protocol (MbimAuthProtocol auth_protocol); MbimAuthProtocol mm_bearer_allowed_auth_to_mbim_auth_protocol (MMBearerAllowedAuth bearer_auth, + gpointer log_object, GError **error); MMBearerIpFamily mm_bearer_ip_family_from_mbim_context_ip_type (MbimContextIpType ip_type); MbimContextIpType mm_bearer_ip_family_to_mbim_context_ip_type (MMBearerIpFamily ip_family, diff --git a/src/mm-modem-helpers-qmi.c b/src/mm-modem-helpers-qmi.c index baf6f3d2..27dbeab6 100644 --- a/src/mm-modem-helpers-qmi.c +++ b/src/mm-modem-helpers-qmi.c @@ -22,12 +22,13 @@ #include "mm-modem-helpers-qmi.h" #include "mm-modem-helpers.h" #include "mm-enums-types.h" -#include "mm-log.h" +#include "mm-log-object.h" /*****************************************************************************/ MMModemCapability -mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network) +mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network, + gpointer log_object) { switch (network) { case QMI_DMS_RADIO_INTERFACE_CDMA20001X: @@ -41,9 +42,9 @@ mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network) case QMI_DMS_RADIO_INTERFACE_LTE: return MM_MODEM_CAPABILITY_LTE; case QMI_DMS_RADIO_INTERFACE_5GNR: + return MM_MODEM_CAPABILITY_5GNR; default: - mm_warn ("Unhandled QMI radio interface (%u)", - (guint)network); + mm_obj_warn (log_object, "unhandled QMI radio interface '%u'", (guint)network); return MM_MODEM_CAPABILITY_NONE; } } @@ -51,7 +52,8 @@ mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network) /*****************************************************************************/ MMModemMode -mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network) +mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network, + gpointer log_object) { switch (network) { case QMI_DMS_RADIO_INTERFACE_CDMA20001X: @@ -65,9 +67,9 @@ mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network) case QMI_DMS_RADIO_INTERFACE_LTE: return MM_MODEM_MODE_4G; case QMI_DMS_RADIO_INTERFACE_5GNR: + return MM_MODEM_MODE_5G; default: - mm_warn ("Unhandled QMI radio interface (%u)", - (guint)network); + mm_obj_warn (log_object, "unhandled QMI radio interface '%u'", (guint)network); return MM_MODEM_MODE_NONE; } } @@ -217,8 +219,9 @@ static const DmsBandsMap dms_bands_map [] = { }; static void -dms_add_qmi_bands (GArray *mm_bands, - QmiDmsBandCapability qmi_bands) +dms_add_qmi_bands (GArray *mm_bands, + QmiDmsBandCapability qmi_bands, + gpointer log_object) { static QmiDmsBandCapability qmi_bands_expected = 0; QmiDmsBandCapability not_expected; @@ -236,11 +239,10 @@ dms_add_qmi_bands (GArray *mm_bands, /* Log about the bands that cannot be represented in ModemManager */ not_expected = ((qmi_bands_expected ^ qmi_bands) & qmi_bands); if (not_expected) { - gchar *aux; + g_autofree gchar *aux = NULL; aux = qmi_dms_band_capability_build_string_from_mask (not_expected); - mm_dbg ("Cannot add the following bands: '%s'", aux); - g_free (aux); + mm_obj_dbg (log_object, "cannot add the following bands: '%s'", aux); } /* And add the expected ones */ @@ -314,8 +316,9 @@ dms_add_qmi_lte_bands (GArray *mm_bands, } static void -dms_add_extended_qmi_lte_bands (GArray *mm_bands, - GArray *extended_qmi_bands) +dms_add_extended_qmi_lte_bands (GArray *mm_bands, + GArray *extended_qmi_bands, + gpointer log_object) { guint i; @@ -334,7 +337,7 @@ dms_add_extended_qmi_lte_bands (GArray *mm_bands, * MM_MODEM_BAND_EUTRAN_71 = 101 */ if (val < 1 || val > 71) - mm_dbg ("Unexpected LTE band supported by module: EUTRAN %u", val); + mm_obj_dbg (log_object, "unexpected LTE band supported by module: EUTRAN %u", val); else { MMModemBand band; @@ -345,17 +348,18 @@ dms_add_extended_qmi_lte_bands (GArray *mm_bands, } GArray * -mm_modem_bands_from_qmi_band_capabilities (QmiDmsBandCapability qmi_bands, - QmiDmsLteBandCapability qmi_lte_bands, - GArray *extended_qmi_lte_bands) +mm_modem_bands_from_qmi_band_capabilities (QmiDmsBandCapability qmi_bands, + QmiDmsLteBandCapability qmi_lte_bands, + GArray *extended_qmi_lte_bands, + gpointer log_object) { GArray *mm_bands; mm_bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); - dms_add_qmi_bands (mm_bands, qmi_bands); + dms_add_qmi_bands (mm_bands, qmi_bands, log_object); if (extended_qmi_lte_bands) - dms_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands); + dms_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands, log_object); else dms_add_qmi_lte_bands (mm_bands, qmi_lte_bands); @@ -421,8 +425,9 @@ static const NasBandsMap nas_bands_map [] = { }; static void -nas_add_qmi_bands (GArray *mm_bands, - QmiNasBandPreference qmi_bands) +nas_add_qmi_bands (GArray *mm_bands, + QmiNasBandPreference qmi_bands, + gpointer log_object) { static QmiNasBandPreference qmi_bands_expected = 0; QmiNasBandPreference not_expected; @@ -440,11 +445,10 @@ nas_add_qmi_bands (GArray *mm_bands, /* Log about the bands that cannot be represented in ModemManager */ not_expected = ((qmi_bands_expected ^ qmi_bands) & qmi_bands); if (not_expected) { - gchar *aux; + g_autofree gchar *aux = NULL; aux = qmi_nas_band_preference_build_string_from_mask (not_expected); - mm_dbg ("Cannot add the following bands: '%s'", aux); - g_free (aux); + mm_obj_dbg (log_object, "cannot add the following bands: '%s'", aux); } /* And add the expected ones */ @@ -518,9 +522,10 @@ nas_add_qmi_lte_bands (GArray *mm_bands, } static void -nas_add_extended_qmi_lte_bands (GArray *mm_bands, +nas_add_extended_qmi_lte_bands (GArray *mm_bands, const guint64 *extended_qmi_lte_bands, - guint extended_qmi_lte_bands_size) + guint extended_qmi_lte_bands_size, + gpointer log_object) { guint i; @@ -542,7 +547,7 @@ nas_add_extended_qmi_lte_bands (GArray *mm_bands, * MM_MODEM_BAND_EUTRAN_71 = 101 */ if (val < 1 || val > 71) - mm_dbg ("Unexpected LTE band supported by module: EUTRAN %u", val); + mm_obj_dbg (log_object, "unexpected LTE band supported by module: EUTRAN %u", val); else { MMModemBand band; @@ -554,18 +559,19 @@ nas_add_extended_qmi_lte_bands (GArray *mm_bands, } GArray * -mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, - QmiNasLteBandPreference qmi_lte_bands, - const guint64 *extended_qmi_lte_bands, - guint extended_qmi_lte_bands_size) +mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, + QmiNasLteBandPreference qmi_lte_bands, + const guint64 *extended_qmi_lte_bands, + guint extended_qmi_lte_bands_size, + gpointer log_object) { GArray *mm_bands; mm_bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); - nas_add_qmi_bands (mm_bands, qmi_bands); + nas_add_qmi_bands (mm_bands, qmi_bands, log_object); if (extended_qmi_lte_bands && extended_qmi_lte_bands_size) - nas_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands, extended_qmi_lte_bands_size); + nas_add_extended_qmi_lte_bands (mm_bands, extended_qmi_lte_bands, extended_qmi_lte_bands_size, log_object); else nas_add_qmi_lte_bands (mm_bands, qmi_lte_bands); @@ -573,11 +579,12 @@ mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, } void -mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, - QmiNasBandPreference *qmi_bands, +mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, + QmiNasBandPreference *qmi_bands, QmiNasLteBandPreference *qmi_lte_bands, - guint64 *extended_qmi_lte_bands, - guint extended_qmi_lte_bands_size) + guint64 *extended_qmi_lte_bands, + guint extended_qmi_lte_bands_size, + gpointer log_object) { guint i; @@ -618,8 +625,8 @@ mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, } if (j == G_N_ELEMENTS (nas_lte_bands_map)) - mm_dbg ("Cannot add the following LTE band: '%s'", - mm_modem_band_get_string (band)); + mm_obj_dbg (log_object, "cannot add the following LTE band: '%s'", + mm_modem_band_get_string (band)); } } else { /* Add non-LTE band preference */ @@ -633,8 +640,8 @@ mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, } if (j == G_N_ELEMENTS (nas_bands_map)) - mm_dbg ("Cannot add the following band: '%s'", - mm_modem_band_get_string (band)); + mm_obj_dbg (log_object, "cannot add the following band: '%s'", + mm_modem_band_get_string (band)); } } } @@ -788,6 +795,7 @@ mm_modem_access_technology_from_qmi_radio_interface (QmiNasRadioInterface interf case QMI_NAS_RADIO_INTERFACE_LTE: return MM_MODEM_ACCESS_TECHNOLOGY_LTE; case QMI_NAS_RADIO_INTERFACE_5GNR: + return MM_MODEM_ACCESS_TECHNOLOGY_5GNR; case QMI_NAS_RADIO_INTERFACE_UNKNOWN: case QMI_NAS_RADIO_INTERFACE_TD_SCDMA: case QMI_NAS_RADIO_INTERFACE_AMPS: @@ -885,6 +893,7 @@ mm_modem_mode_from_qmi_nas_radio_interface (QmiNasRadioInterface iface) case QMI_NAS_RADIO_INTERFACE_LTE: return MM_MODEM_MODE_4G; case QMI_NAS_RADIO_INTERFACE_5GNR: + return MM_MODEM_MODE_5G; case QMI_NAS_RADIO_INTERFACE_NONE: case QMI_NAS_RADIO_INTERFACE_AMPS: case QMI_NAS_RADIO_INTERFACE_TD_SCDMA: @@ -970,6 +979,9 @@ mm_modem_mode_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi) if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_LTE) mode |= MM_MODEM_MODE_4G; + if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_5GNR) + mode |= MM_MODEM_MODE_5G; + return mode; } @@ -997,6 +1009,9 @@ mm_modem_mode_to_qmi_rat_mode_preference (MMModemMode mode, if (mode & MM_MODEM_MODE_4G) pref |= QMI_NAS_RAT_MODE_PREFERENCE_LTE; + + if (mode & MM_MODEM_MODE_5G) + pref |= QMI_NAS_RAT_MODE_PREFERENCE_5GNR; } return pref; @@ -1024,7 +1039,8 @@ mm_modem_capability_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi) if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_LTE) caps |= MM_MODEM_CAPABILITY_LTE; - /* FIXME: LTE Advanced? */ + if (qmi & QMI_NAS_RAT_MODE_PREFERENCE_5GNR) + caps |= MM_MODEM_CAPABILITY_5GNR; return caps; } @@ -1047,6 +1063,9 @@ mm_modem_capability_to_qmi_rat_mode_preference (MMModemCapability caps) if (caps & MM_MODEM_CAPABILITY_LTE) qmi |= QMI_NAS_RAT_MODE_PREFERENCE_LTE; + if (caps & MM_MODEM_CAPABILITY_5GNR) + qmi |= QMI_NAS_RAT_MODE_PREFERENCE_5GNR; + return qmi; } @@ -1060,6 +1079,11 @@ mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps) array = g_array_new (FALSE, FALSE, sizeof (QmiNasRadioInterface)); + if (caps & MM_MODEM_CAPABILITY_5GNR) { + value = QMI_NAS_RADIO_INTERFACE_5GNR; + g_array_append_val (array, value); + } + if (caps & MM_MODEM_CAPABILITY_LTE) { value = QMI_NAS_RADIO_INTERFACE_LTE; g_array_append_val (array, value); @@ -1082,58 +1106,74 @@ mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps) return array; } +static gboolean +radio_interface_array_contains (GArray *array, + QmiNasRadioInterface act) +{ + guint i; + + for (i = 0; i < array->len; i++) { + QmiNasRadioInterface value; + + value = g_array_index (array, QmiNasRadioInterface, i); + if (value == act) + return TRUE; + } + return FALSE; +} + +static void +radio_interface_array_add_missing (GArray *array, + GArray *all) +{ + guint i; + + for (i = 0; i < all->len; i++) { + QmiNasRadioInterface value; + + value = g_array_index (all, QmiNasRadioInterface, i); + if (!radio_interface_array_contains (array, value)) + g_array_append_val (array, value); + } +} + GArray * -mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed, - MMModemMode preferred, - gboolean is_cdma, - gboolean is_3gpp) +mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed, + MMModemMode preferred, + GArray *all) { GArray *array; + QmiNasRadioInterface preferred_radio = QMI_NAS_RADIO_INTERFACE_UNKNOWN; QmiNasRadioInterface value; - array = g_array_new (FALSE, FALSE, sizeof (QmiNasRadioInterface)); + array = g_array_sized_new (FALSE, FALSE, sizeof (QmiNasRadioInterface), all->len); - if (allowed & MM_MODEM_MODE_4G) { - value = QMI_NAS_RADIO_INTERFACE_LTE; - if (preferred == MM_MODEM_MODE_4G) - g_array_prepend_val (array, value); - else - g_array_append_val (array, value); +#define PROCESS_ALLOWED_PREFERRED_MODE(MODE,RADIO) \ + if ((allowed & MODE) && (radio_interface_array_contains (all, RADIO))) { \ + if ((preferred == MODE) && (preferred_radio == QMI_NAS_RADIO_INTERFACE_UNKNOWN)) \ + preferred_radio = RADIO; \ + else { \ + value = RADIO; \ + g_array_append_val (array, value); \ + } \ } - if (allowed & MM_MODEM_MODE_3G) { - if (is_cdma) { - value = QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO; - if (preferred == MM_MODEM_MODE_3G) - g_array_prepend_val (array, value); - else - g_array_append_val (array, value); - } - if (is_3gpp) { - value = QMI_NAS_RADIO_INTERFACE_UMTS; - if (preferred == MM_MODEM_MODE_3G) - g_array_prepend_val (array, value); - else - g_array_append_val (array, value); - } - } + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_5G, QMI_NAS_RADIO_INTERFACE_5GNR); + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_4G, QMI_NAS_RADIO_INTERFACE_LTE); + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_3G, QMI_NAS_RADIO_INTERFACE_UMTS); + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_3G, QMI_NAS_RADIO_INTERFACE_CDMA_1XEVDO); + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_2G, QMI_NAS_RADIO_INTERFACE_GSM); + PROCESS_ALLOWED_PREFERRED_MODE (MM_MODEM_MODE_2G, QMI_NAS_RADIO_INTERFACE_CDMA_1X); - if (allowed & MM_MODEM_MODE_2G) { - if (is_cdma) { - value = QMI_NAS_RADIO_INTERFACE_CDMA_1X; - if (preferred == MM_MODEM_MODE_2G) - g_array_prepend_val (array, value); - else - g_array_append_val (array, value); - } - if (is_3gpp) { - value = QMI_NAS_RADIO_INTERFACE_GSM; - if (preferred == MM_MODEM_MODE_2G) - g_array_prepend_val (array, value); - else - g_array_append_val (array, value); - } - } +#undef PROCESS_ALLOWED_PREFERRED_MODE + + if (preferred_radio != QMI_NAS_RADIO_INTERFACE_UNKNOWN) + g_array_prepend_val (array, preferred_radio); + + /* the acquisition order preference is a TLV that must ALWAYS contain the + * same list of QmiNasRadioInterface values, just with a different order. */ + radio_interface_array_add_missing (array, all); + g_assert_cmpuint (array->len, ==, all->len); return array; } @@ -1163,7 +1203,7 @@ mm_modem_capability_from_qmi_radio_technology_preference (QmiNasRadioTechnologyP if (qmi & QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_LTE) caps |= MM_MODEM_CAPABILITY_LTE; - /* FIXME: LTE Advanced? */ + /* NOTE: no 5GNR defined in Technology Preference */ return caps; } @@ -1252,7 +1292,8 @@ mm_modem_capability_from_qmi_band_preference (QmiNasBandPreference qmi) /*****************************************************************************/ MMModemMode -mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi) +mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi, + gpointer log_object) { switch (qmi) { case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC: @@ -1262,16 +1303,17 @@ mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcq case QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_WCDMA: return MM_MODEM_MODE_3G; default: - mm_dbg ("Unknown acquisition order preference: '%s'", - qmi_nas_gsm_wcdma_acquisition_order_preference_get_string (qmi)); + mm_obj_dbg (log_object, "unknown acquisition order preference: '%s'", + qmi_nas_gsm_wcdma_acquisition_order_preference_get_string (qmi)); return MM_MODEM_MODE_NONE; } } QmiNasGsmWcdmaAcquisitionOrderPreference -mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode) +mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode, + gpointer log_object) { - gchar *str; + g_autofree gchar *str = NULL; /* mode is not a mask in this case, only a value */ @@ -1284,14 +1326,14 @@ mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode) return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC; case MM_MODEM_MODE_CS: case MM_MODEM_MODE_4G: + case MM_MODEM_MODE_5G: case MM_MODEM_MODE_ANY: default: break; } str = mm_modem_mode_build_string_from_mask (mode); - mm_dbg ("Unhandled modem mode: '%s'", str); - g_free (str); + mm_obj_dbg (log_object, "unhandled modem mode: '%s'", str); return QMI_NAS_GSM_WCDMA_ACQUISITION_ORDER_PREFERENCE_AUTOMATIC; } @@ -1438,6 +1480,72 @@ mm_bearer_allowed_auth_to_qmi_authentication (MMBearerAllowedAuth auth) return out; } +MMBearerAllowedAuth +mm_bearer_allowed_auth_from_qmi_authentication (QmiWdsAuthentication auth) +{ + MMBearerAllowedAuth out = 0; + + if (auth & QMI_WDS_AUTHENTICATION_PAP) + out |= MM_BEARER_ALLOWED_AUTH_PAP; + if (auth & QMI_WDS_AUTHENTICATION_CHAP) + out |= MM_BEARER_ALLOWED_AUTH_CHAP; + + return out; +} + +MMBearerIpFamily +mm_bearer_ip_family_from_qmi_ip_support_type (QmiWdsIpSupportType ip_support_type) +{ + switch (ip_support_type) { + case QMI_WDS_IP_SUPPORT_TYPE_IPV4: + return MM_BEARER_IP_FAMILY_IPV4; + case QMI_WDS_IP_SUPPORT_TYPE_IPV6: + return MM_BEARER_IP_FAMILY_IPV6; + case QMI_WDS_IP_SUPPORT_TYPE_IPV4V6: + return MM_BEARER_IP_FAMILY_IPV4V6; + default: + return MM_BEARER_IP_FAMILY_NONE; + } +} + +MMBearerIpFamily +mm_bearer_ip_family_from_qmi_pdp_type (QmiWdsPdpType pdp_type) +{ + switch (pdp_type) { + case QMI_WDS_PDP_TYPE_IPV4: + return MM_BEARER_IP_FAMILY_IPV4; + case QMI_WDS_PDP_TYPE_IPV6: + return MM_BEARER_IP_FAMILY_IPV6; + case QMI_WDS_PDP_TYPE_IPV4_OR_IPV6: + return MM_BEARER_IP_FAMILY_IPV4V6; + case QMI_WDS_PDP_TYPE_PPP: + default: + return MM_BEARER_IP_FAMILY_NONE; + } +} + +gboolean +mm_bearer_ip_family_to_qmi_pdp_type (MMBearerIpFamily ip_family, + QmiWdsPdpType *out_pdp_type) +{ + switch (ip_family) { + case MM_BEARER_IP_FAMILY_IPV4: + *out_pdp_type = QMI_WDS_PDP_TYPE_IPV4; + return TRUE; + case MM_BEARER_IP_FAMILY_IPV6: + *out_pdp_type = QMI_WDS_PDP_TYPE_IPV6; + return TRUE; + case MM_BEARER_IP_FAMILY_IPV4V6: + *out_pdp_type = QMI_WDS_PDP_TYPE_IPV4_OR_IPV6; + return TRUE; + case MM_BEARER_IP_FAMILY_NONE: + case MM_BEARER_IP_FAMILY_ANY: + default: + /* there is no valid conversion, so just return FALSE to indicate it */ + return FALSE; + } +} + /*****************************************************************************/ /** @@ -1450,56 +1558,55 @@ mm_bearer_allowed_auth_to_qmi_authentication (MMBearerAllowedAuth auth) * as there would be no capability switching support. */ MMModemCapability -mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx) +mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx, + gpointer log_object) { MMModemCapability tmp = MM_MODEM_CAPABILITY_NONE; - gchar *nas_ssp_mode_preference_str; - gchar *nas_tp_str; - gchar *dms_capabilities_str; - gchar *tmp_str; + g_autofree gchar *nas_ssp_mode_preference_str = NULL; + g_autofree gchar *nas_tp_str = NULL; + g_autofree gchar *dms_capabilities_str = NULL; + g_autofree gchar *tmp_str = NULL; /* If not a multimode device, we're done */ #define MULTIMODE (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_CDMA_EVDO) if ((ctx->dms_capabilities & MULTIMODE) != MULTIMODE) - return ctx->dms_capabilities; - - /* We have a multimode CDMA/EVDO+GSM/UMTS device, check SSP and TP */ - - /* SSP logic to gather capabilities uses the Mode Preference TLV if available */ - if (ctx->nas_ssp_mode_preference_mask) - tmp = mm_modem_capability_from_qmi_rat_mode_preference (ctx->nas_ssp_mode_preference_mask); - /* If no value retrieved from SSP, check TP. We only process TP - * values if not 'auto' (0). */ - else if (ctx->nas_tp_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) - tmp = mm_modem_capability_from_qmi_radio_technology_preference (ctx->nas_tp_mask); - - /* Final capabilities are the intersection between the Technology - * Preference or SSP and the device's capabilities. - * If the Technology Preference was "auto" or unknown we just fall back - * to the Get Capabilities response. - */ - if (tmp == MM_MODEM_CAPABILITY_NONE) tmp = ctx->dms_capabilities; - else - tmp &= ctx->dms_capabilities; + else { + /* We have a multimode CDMA/EVDO+GSM/UMTS device, check SSP and TP */ + + /* SSP logic to gather capabilities uses the Mode Preference TLV if available */ + if (ctx->nas_ssp_mode_preference_mask) + tmp = mm_modem_capability_from_qmi_rat_mode_preference (ctx->nas_ssp_mode_preference_mask); + /* If no value retrieved from SSP, check TP. We only process TP + * values if not 'auto' (0). */ + else if (ctx->nas_tp_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) + tmp = mm_modem_capability_from_qmi_radio_technology_preference (ctx->nas_tp_mask); + + /* Final capabilities are the intersection between the Technology + * Preference or SSP and the device's capabilities. + * If the Technology Preference was "auto" or unknown we just fall back + * to the Get Capabilities response. + */ + if (tmp == MM_MODEM_CAPABILITY_NONE) + tmp = ctx->dms_capabilities; + else + tmp &= ctx->dms_capabilities; + } /* Log about the logic applied */ nas_ssp_mode_preference_str = qmi_nas_rat_mode_preference_build_string_from_mask (ctx->nas_ssp_mode_preference_mask); nas_tp_str = qmi_nas_radio_technology_preference_build_string_from_mask (ctx->nas_tp_mask); dms_capabilities_str = mm_modem_capability_build_string_from_mask (ctx->dms_capabilities); tmp_str = mm_modem_capability_build_string_from_mask (tmp); - mm_dbg ("Current capabilities built: '%s'\n" - " SSP mode preference: '%s'\n" - " TP: '%s'\n" - " DMS Capabilities: '%s'", - tmp_str, - nas_ssp_mode_preference_str ? nas_ssp_mode_preference_str : "unknown", - nas_tp_str ? nas_tp_str : "unknown", - dms_capabilities_str); - g_free (nas_ssp_mode_preference_str); - g_free (nas_tp_str); - g_free (dms_capabilities_str); - g_free (tmp_str); + mm_obj_dbg (log_object, + "Current capabilities built: '%s'\n" + " SSP mode preference: '%s'\n" + " TP: '%s'\n" + " DMS Capabilities: '%s'", + tmp_str, + nas_ssp_mode_preference_str ? nas_ssp_mode_preference_str : "unknown", + nas_tp_str ? nas_tp_str : "unknown", + dms_capabilities_str); return tmp; } @@ -1712,25 +1819,19 @@ mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id, /* The length will be exactly EXPECTED_QMI_UNIQUE_ID_LENGTH*2 if given in HEX */ if (len == (2 * EXPECTED_QMI_UNIQUE_ID_LENGTH)) { - guint8 *tmp; - gsize tmp_len; - guint i; - - for (i = 0; i < len; i++) { - if (!g_ascii_isxdigit (unique_id[i])) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unexpected character found in unique id (not HEX): %c", unique_id[i]); - return NULL; - } - } + g_autofree guint8 *tmp = NULL; + gsize tmp_len; tmp_len = 0; - tmp = (guint8 *) mm_utils_hexstr2bin (unique_id, &tmp_len); + tmp = mm_utils_hexstr2bin (unique_id, -1, &tmp_len, error); + if (!tmp) { + g_prefix_error (error, "Unexpected character found in unique id: "); + return NULL; + } g_assert (tmp_len == EXPECTED_QMI_UNIQUE_ID_LENGTH); qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len); g_array_insert_vals (qmi_unique_id, 0, tmp, tmp_len); - g_free (tmp); return qmi_unique_id; } @@ -1758,3 +1859,257 @@ mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id, "Unexpected unique id length: %u", len); return NULL; } + +/*****************************************************************************/ + +gboolean +mm_qmi_uim_get_card_status_output_parse (gpointer log_object, + QmiMessageUimGetCardStatusOutput *output, + MMModemLock *o_lock, + QmiUimPinState *o_pin1_state, + guint *o_pin1_retries, + guint *o_puk1_retries, + QmiUimPinState *o_pin2_state, + guint *o_pin2_retries, + guint *o_puk2_retries, + GError **error) +{ + QmiMessageUimGetCardStatusOutputCardStatusCardsElement *card; + QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement *app; + GArray *cards; + guint16 index_gw_primary = 0xFFFF; + guint8 gw_primary_slot_i = 0; + guint8 gw_primary_application_i = 0; + MMModemLock lock = MM_MODEM_LOCK_UNKNOWN; + + /* This command supports MULTIPLE cards with MULTIPLE applications each. For our + * purposes, we're going to consider as the SIM to use the one identified as + * 'primary GW' exclusively. We don't really support Dual Sim Dual Standby yet. */ + + qmi_message_uim_get_card_status_output_get_card_status ( + output, + &index_gw_primary, + NULL, /* index_1x_primary */ + NULL, /* index_gw_secondary */ + NULL, /* index_1x_secondary */ + &cards, + NULL); + + if (cards->len == 0) { + g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED, + "No cards reported"); + return FALSE; + } + + /* Look for the primary GW slot and application. + * If we don't have valid GW primary slot index and application index, assume + * we're missing the SIM altogether */ + gw_primary_slot_i = ((index_gw_primary & 0xFF00) >> 8); + gw_primary_application_i = ((index_gw_primary & 0x00FF)); + + if (gw_primary_slot_i == 0xFF) { + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, + "GW primary session index unknown"); + return FALSE; + } + mm_obj_dbg (log_object, "GW primary session index: %u", gw_primary_slot_i); + + if (gw_primary_application_i == 0xFF) { + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, + "GW primary application index unknown"); + return FALSE; + } + mm_obj_dbg (log_object, "GW primary application index: %u", gw_primary_application_i); + + /* Validate slot index */ + if (gw_primary_slot_i >= cards->len) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Invalid GW primary session index: %u", + gw_primary_slot_i); + return FALSE; + } + + /* Get card at slot */ + card = &g_array_index (cards, QmiMessageUimGetCardStatusOutputCardStatusCardsElement, gw_primary_slot_i); + + if (card->card_state == QMI_UIM_CARD_STATE_ABSENT) { + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED, + "No card found"); + return FALSE; + } + + if (card->card_state == QMI_UIM_CARD_STATE_ERROR) { + const gchar *card_error; + + card_error = qmi_uim_card_error_get_string (card->error_code); + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "Card error: %s", card_error ? card_error : "unknown error"); + return FALSE; + } + + if (card->card_state != QMI_UIM_CARD_STATE_PRESENT) { + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "Card error: unexpected card state: 0x%x", card->card_state); + return FALSE; + } + + /* Card is present */ + + if (card->applications->len == 0) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "No applications reported in card"); + return FALSE; + } + + /* Validate application index */ + if (gw_primary_application_i >= card->applications->len) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Invalid GW primary application index: %u", + gw_primary_application_i); + return FALSE; + } + + app = &g_array_index (card->applications, QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement, gw_primary_application_i); + if ((app->type != QMI_UIM_CARD_APPLICATION_TYPE_SIM) && (app->type != QMI_UIM_CARD_APPLICATION_TYPE_USIM)) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Unsupported application type found in GW primary application index: %s", + qmi_uim_card_application_type_get_string (app->type)); + return FALSE; + } + + /* Illegal application state is fatal, consider it as a failed SIM right + * away and don't even attempt to retry */ + if (app->state == QMI_UIM_CARD_APPLICATION_STATE_ILLEGAL) { + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "Illegal SIM/USIM application state"); + return FALSE; + } + + /* If card not ready yet, return RETRY error. + * If the application state reports needing PIN/PUk, consider that ready as + * well, and let the logic fall down to check PIN1/PIN2. */ + if (app->state != QMI_UIM_CARD_APPLICATION_STATE_READY && + app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_OR_UPIN_PIN_REQUIRED && + app->state != QMI_UIM_CARD_APPLICATION_STATE_PUK1_OR_UPIN_PUK_REQUIRED && + app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_BLOCKED) { + mm_obj_dbg (log_object, "neither SIM nor USIM are ready"); + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY, + "SIM not ready yet (retry)"); + return FALSE; + } + + /* Report state and retries if requested to do so */ + if (o_pin1_state) + *o_pin1_state = app->pin1_state; + if (o_pin1_retries) + *o_pin1_retries = app->pin1_retries; + if (o_puk1_retries) + *o_puk1_retries = app->puk1_retries; + if (o_pin2_state) + *o_pin2_state = app->pin2_state; + if (o_pin2_retries) + *o_pin2_retries = app->pin2_retries; + if (o_puk2_retries) + *o_puk2_retries = app->puk2_retries; + + /* Early bail out if lock status isn't wanted at this point, so that we + * don't fail with an error the unlock retries check */ + if (!o_lock) + return TRUE; + + /* Card is ready, what's the lock status? */ + + /* PIN1 */ + switch (app->pin1_state) { + case QMI_UIM_PIN_STATE_NOT_INITIALIZED: + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "SIM PIN/PUK status not known yet"); + return FALSE; + + case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "SIM PIN/PUK permanently blocked"); + return FALSE; + + case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: + lock = MM_MODEM_LOCK_SIM_PIN; + break; + + case QMI_UIM_PIN_STATE_BLOCKED: + lock = MM_MODEM_LOCK_SIM_PUK; + break; + + case QMI_UIM_PIN_STATE_DISABLED: + case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: + lock = MM_MODEM_LOCK_NONE; + break; + + default: + g_set_error (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, + "Unknown SIM PIN/PUK status"); + return FALSE; + } + + /* PIN2 */ + if (lock == MM_MODEM_LOCK_NONE) { + switch (app->pin2_state) { + case QMI_UIM_PIN_STATE_NOT_INITIALIZED: + mm_obj_warn (log_object, "SIM PIN2/PUK2 status not known yet"); + break; + + case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED: + lock = MM_MODEM_LOCK_SIM_PIN2; + break; + + case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED: + mm_obj_warn (log_object, "PUK2 permanently blocked"); + /* Fall through */ + case QMI_UIM_PIN_STATE_BLOCKED: + lock = MM_MODEM_LOCK_SIM_PUK2; + break; + + case QMI_UIM_PIN_STATE_DISABLED: + case QMI_UIM_PIN_STATE_ENABLED_VERIFIED: + break; + + default: + mm_obj_warn (log_object, "unknown SIM PIN2/PUK2 status"); + break; + } + } + + *o_lock = lock; + return TRUE; +} + +/*************************************************************************/ +/* EID parsing */ + +#define EID_BYTE_LENGTH 16 + +gchar * +mm_qmi_uim_decode_eid (const gchar *eid, gsize eid_len) +{ + if (eid_len != EID_BYTE_LENGTH) + return NULL; + + return mm_bcd_to_string ((const guint8 *) eid, eid_len, FALSE /* low_nybble_first */); +} diff --git a/src/mm-modem-helpers-qmi.h b/src/mm-modem-helpers-qmi.h index 5c0200e4..430ac3cf 100644 --- a/src/mm-modem-helpers-qmi.h +++ b/src/mm-modem-helpers-qmi.h @@ -24,9 +24,11 @@ /*****************************************************************************/ /* QMI/DMS to MM translations */ -MMModemCapability mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network); +MMModemCapability mm_modem_capability_from_qmi_radio_interface (QmiDmsRadioInterface network, + gpointer log_object); -MMModemMode mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network); +MMModemMode mm_modem_mode_from_qmi_radio_interface (QmiDmsRadioInterface network, + gpointer log_object); MMModemLock mm_modem_lock_from_qmi_uim_pin_status (QmiDmsUimPinStatus status, gboolean pin1); @@ -34,9 +36,10 @@ MMModemLock mm_modem_lock_from_qmi_uim_pin_status (QmiDmsUimPinStatus status, gboolean mm_pin_enabled_from_qmi_uim_pin_status (QmiDmsUimPinStatus status); QmiDmsUimFacility mm_3gpp_facility_to_qmi_uim_facility (MMModem3gppFacility mm); -GArray *mm_modem_bands_from_qmi_band_capabilities (QmiDmsBandCapability qmi_bands, - QmiDmsLteBandCapability qmi_lte_bands, - GArray *extended_qmi_lte_bands); +GArray *mm_modem_bands_from_qmi_band_capabilities (QmiDmsBandCapability qmi_bands, + QmiDmsLteBandCapability qmi_lte_bands, + GArray *extended_qmi_lte_bands, + gpointer log_object); /*****************************************************************************/ /* QMI/NAS to MM translations */ @@ -61,31 +64,34 @@ QmiNasRatModePreference mm_modem_mode_to_qmi_rat_mode_preference (MMModemMode mo MMModemCapability mm_modem_capability_from_qmi_rat_mode_preference (QmiNasRatModePreference qmi); QmiNasRatModePreference mm_modem_capability_to_qmi_rat_mode_preference (MMModemCapability caps); -GArray *mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps); -GArray *mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed, - MMModemMode preferred, - gboolean is_cdma, - gboolean is_3gpp); +GArray *mm_modem_capability_to_qmi_acquisition_order_preference (MMModemCapability caps); +GArray *mm_modem_mode_to_qmi_acquisition_order_preference (MMModemMode allowed, + MMModemMode preferred, + GArray *all); MMModemCapability mm_modem_capability_from_qmi_radio_technology_preference (QmiNasRadioTechnologyPreference qmi); QmiNasRadioTechnologyPreference mm_modem_capability_to_qmi_radio_technology_preference (MMModemCapability caps); MMModemCapability mm_modem_capability_from_qmi_band_preference (QmiNasBandPreference qmi); -MMModemMode mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi); -QmiNasGsmWcdmaAcquisitionOrderPreference mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode); +MMModemMode mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (QmiNasGsmWcdmaAcquisitionOrderPreference qmi, + gpointer log_object); +QmiNasGsmWcdmaAcquisitionOrderPreference mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (MMModemMode mode, + gpointer log_object); GArray *mm_modem_bands_from_qmi_rf_band_information_array (GArray *info_array); -GArray *mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, - QmiNasLteBandPreference qmi_lte_bands, - const guint64 *extended_qmi_lte_bands, - guint extended_qmi_lte_bands_size); -void mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, - QmiNasBandPreference *qmi_bands, +GArray *mm_modem_bands_from_qmi_band_preference (QmiNasBandPreference qmi_bands, + QmiNasLteBandPreference qmi_lte_bands, + const guint64 *extended_qmi_lte_bands, + guint extended_qmi_lte_bands_size, + gpointer log_object); +void mm_modem_bands_to_qmi_band_preference (GArray *mm_bands, + QmiNasBandPreference *qmi_bands, QmiNasLteBandPreference *qmi_lte_bands, - guint64 *extended_qmi_lte_bands, - guint extended_qmi_lte_bands_size); + guint64 *extended_qmi_lte_bands, + guint extended_qmi_lte_bands_size, + gpointer log_object); MMModem3gppRegistrationState mm_modem_3gpp_registration_state_from_qmi_registration_state (QmiNasAttachState attach_state, QmiNasRegistrationState registration_state, @@ -106,7 +112,12 @@ MMSmsState mm_sms_state_from_qmi_message_tag (QmiWmsMessageTagType tag); /*****************************************************************************/ /* QMI/WDS to MM translations */ -QmiWdsAuthentication mm_bearer_allowed_auth_to_qmi_authentication (MMBearerAllowedAuth auth); +QmiWdsAuthentication mm_bearer_allowed_auth_to_qmi_authentication (MMBearerAllowedAuth auth); +MMBearerAllowedAuth mm_bearer_allowed_auth_from_qmi_authentication (QmiWdsAuthentication auth); +MMBearerIpFamily mm_bearer_ip_family_from_qmi_ip_support_type (QmiWdsIpSupportType ip_support_type); +MMBearerIpFamily mm_bearer_ip_family_from_qmi_pdp_type (QmiWdsPdpType pdp_type); +gboolean mm_bearer_ip_family_to_qmi_pdp_type (MMBearerIpFamily ip_family, + QmiWdsPdpType *out_pdp_type); /*****************************************************************************/ /* QMI/OMA to MM translations */ @@ -136,7 +147,8 @@ typedef struct { MMModemCapability dms_capabilities; } MMQmiCapabilitiesContext; -MMModemCapability mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx); +MMModemCapability mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx, + gpointer log_object); /*****************************************************************************/ /* QMI unique id manipulation */ @@ -146,4 +158,22 @@ gchar *mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id, GArray *mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id, GError **error); +/*****************************************************************************/ +/* Common UIM Get Card Status parsing */ + +gboolean mm_qmi_uim_get_card_status_output_parse (gpointer log_object, + QmiMessageUimGetCardStatusOutput *output, + MMModemLock *o_lock, + QmiUimPinState *o_pin1_state, + guint *o_pin1_retries, + guint *o_puk1_retries, + QmiUimPinState *o_pin2_state, + guint *o_pin2_retries, + guint *o_puk2_retries, + GError **error); + +/*****************************************************************************/ +/* UIM Get Slot Status parsing */ +gchar *mm_qmi_uim_decode_eid (const gchar *eid, gsize eid_len); + #endif /* MM_MODEM_HELPERS_QMI_H */ diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 15fba359..26b55f71 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -31,7 +31,7 @@ #include "mm-sms-part.h" #include "mm-modem-helpers.h" #include "mm-helper-enums-types.h" -#include "mm-log.h" +#include "mm-log-object.h" /*****************************************************************************/ @@ -254,8 +254,9 @@ mm_find_bit_set (gulong number) /*****************************************************************************/ gchar * -mm_create_device_identifier (guint vid, - guint pid, +mm_create_device_identifier (guint vid, + guint pid, + gpointer log_object, const gchar *ati, const gchar *ati1, const gchar *gsn, @@ -263,9 +264,11 @@ mm_create_device_identifier (guint vid, const gchar *model, const gchar *manf) { - GString *devid, *msg = NULL; - GChecksum *sum; - gchar *p, *ret = NULL; + g_autoptr(GString) devid = NULL; + g_autoptr(GString) msg = NULL; + g_autoptr(GChecksum) sum = NULL; + const gchar *ret; + gchar *p = NULL; gchar str_vid[10], str_pid[10]; /* Build up the device identifier */ @@ -286,14 +289,11 @@ mm_create_device_identifier (guint vid, if (manf) g_string_append (devid, manf); - if (!strlen (devid->str)) { - g_string_free (devid, TRUE); + if (!strlen (devid->str)) return NULL; - } p = devid->str; msg = g_string_sized_new (strlen (devid->str) + 17); - sum = g_checksum_new (G_CHECKSUM_SHA1); if (vid) { @@ -315,15 +315,10 @@ mm_create_device_identifier (guint vid, } p++; } - ret = g_strdup (g_checksum_get_string (sum)); - g_checksum_free (sum); - - mm_dbg ("Device ID source '%s'", msg->str); - mm_dbg ("Device ID '%s'", ret); - g_string_free (msg, TRUE); - g_string_free (devid, TRUE); - return ret; + ret = g_checksum_get_string (sum); + mm_obj_dbg (log_object, "device identifier built: %s -> %s", msg->str, ret); + return g_strdup (ret); } /*****************************************************************************/ @@ -423,7 +418,8 @@ mm_new_iso8601_time (guint year, GArray * mm_filter_supported_modes (const GArray *all, - const GArray *supported_combinations) + const GArray *supported_combinations, + gpointer log_object) { MMModemModeCombination all_item; guint i; @@ -434,6 +430,9 @@ mm_filter_supported_modes (const GArray *all, g_return_val_if_fail (all->len == 1, NULL); g_return_val_if_fail (supported_combinations != NULL, NULL); + mm_obj_dbg (log_object, "filtering %u supported mode combinations with %u modes", + supported_combinations->len, all->len); + all_item = g_array_index (all, MMModemModeCombination, 0); g_return_val_if_fail (all_item.allowed != MM_MODEM_MODE_NONE, NULL); @@ -455,41 +454,16 @@ mm_filter_supported_modes (const GArray *all, } if (filtered_combinations->len == 0) - mm_warn ("All supported mode combinations were filtered out."); + mm_obj_warn (log_object, "all supported mode combinations were filtered out"); /* Add default entry with the generic mask including all items */ if (!all_item_added) { - mm_dbg ("Adding an explicit item with all supported modes allowed"); + mm_obj_dbg (log_object, "adding an explicit item with all supported modes allowed"); g_array_append_val (filtered_combinations, all_item); } - return filtered_combinations; -} - -/*****************************************************************************/ - -GArray * -mm_filter_supported_capabilities (MMModemCapability all, - const GArray *supported_combinations) -{ - guint i; - GArray *filtered_combinations; - - g_return_val_if_fail (all != MM_MODEM_CAPABILITY_NONE, NULL); - g_return_val_if_fail (supported_combinations != NULL, NULL); - - /* We will filter out all combinations which have modes not listed in 'all' */ - filtered_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), supported_combinations->len); - for (i = 0; i < supported_combinations->len; i++) { - MMModemCapability capability; - - capability = g_array_index (supported_combinations, MMModemCapability, i); - if (!(capability & ~all)) - g_array_append_val (filtered_combinations, capability); - } - - if (filtered_combinations->len == 0) - mm_warn ("All supported capability combinations were filtered out."); + mm_obj_dbg (log_object, "device supports %u different mode combinations", + filtered_combinations->len); return filtered_combinations; } @@ -499,7 +473,7 @@ mm_filter_supported_capabilities (MMModemCapability all, static const gchar bcd_chars[] = "0123456789\0\0\0\0\0\0"; gchar * -mm_bcd_to_string (const guint8 *bcd, gsize bcd_len) +mm_bcd_to_string (const guint8 *bcd, gsize bcd_len, gboolean low_nybble_first) { GString *str; gsize i; @@ -508,8 +482,11 @@ mm_bcd_to_string (const guint8 *bcd, gsize bcd_len) str = g_string_sized_new (bcd_len * 2 + 1); for (i = 0 ; i < bcd_len; i++) { - str = g_string_append_c (str, bcd_chars[bcd[i] & 0xF]); + if (low_nybble_first) + str = g_string_append_c (str, bcd_chars[bcd[i] & 0xF]); str = g_string_append_c (str, bcd_chars[(bcd[i] >> 4) & 0xF]); + if (!low_nybble_first) + str = g_string_append_c (str, bcd_chars[bcd[i] & 0xF]); } return g_string_free (str, FALSE); } @@ -586,6 +563,7 @@ call_info_free (MMCallInfo *info) gboolean mm_3gpp_parse_clcc_response (const gchar *str, + gpointer log_object, GList **out_list, GError **error) { @@ -649,20 +627,20 @@ mm_3gpp_parse_clcc_response (const gchar *str, call_info = g_slice_new0 (MMCallInfo); if (!mm_get_uint_from_match_info (match_info, 1, &call_info->index)) { - mm_warn ("couldn't parse call index from +CLCC line"); + mm_obj_warn (log_object, "couldn't parse call index from +CLCC line"); goto next; } if (!mm_get_uint_from_match_info (match_info, 2, &aux) || (aux >= G_N_ELEMENTS (call_direction))) { - mm_warn ("couldn't parse call direction from +CLCC line"); + mm_obj_warn (log_object, "couldn't parse call direction from +CLCC line"); goto next; } call_info->direction = call_direction[aux]; if (!mm_get_uint_from_match_info (match_info, 3, &aux) || (aux >= G_N_ELEMENTS (call_state))) { - mm_warn ("couldn't parse call state from +CLCC line"); + mm_obj_warn (log_object, "couldn't parse call state from +CLCC line"); goto next; } call_info->state = call_state[aux]; @@ -703,7 +681,8 @@ mm_3gpp_call_info_list_free (GList *call_info_list) static MMFlowControl flow_control_array_to_mask (GArray *array, - const gchar *item) + const gchar *item, + gpointer log_object) { MMFlowControl mask = MM_FLOW_CONTROL_UNKNOWN; guint i; @@ -714,15 +693,15 @@ flow_control_array_to_mask (GArray *array, mode = g_array_index (array, guint, i); switch (mode) { case 0: - mm_dbg ("%s supports no flow control", item); + mm_obj_dbg (log_object, "%s supports no flow control", item); mask |= MM_FLOW_CONTROL_NONE; break; case 1: - mm_dbg ("%s supports XON/XOFF flow control", item); + mm_obj_dbg (log_object, "%s supports XON/XOFF flow control", item); mask |= MM_FLOW_CONTROL_XON_XOFF; break; case 2: - mm_dbg ("%s supports RTS/CTS flow control", item); + mm_obj_dbg (log_object, "%s supports RTS/CTS flow control", item); mask |= MM_FLOW_CONTROL_RTS_CTS; break; default: @@ -737,6 +716,7 @@ static MMFlowControl flow_control_match_info_to_mask (GMatchInfo *match_info, guint index, const gchar *item, + gpointer log_object, GError **error) { MMFlowControl mask = MM_FLOW_CONTROL_UNKNOWN; @@ -754,7 +734,7 @@ flow_control_match_info_to_mask (GMatchInfo *match_info, goto out; } - if ((mask = flow_control_array_to_mask (array, item)) == MM_FLOW_CONTROL_UNKNOWN) { + if ((mask = flow_control_array_to_mask (array, item, log_object)) == MM_FLOW_CONTROL_UNKNOWN) { g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No known %s flow control method given", item); goto out; @@ -769,6 +749,7 @@ flow_control_match_info_to_mask (GMatchInfo *match_info, MMFlowControl mm_parse_ifc_test_response (const gchar *response, + gpointer log_object, GError **error) { GRegex *r; @@ -791,11 +772,11 @@ mm_parse_ifc_test_response (const gchar *response, } /* Parse TE flow control methods */ - if ((te_mask = flow_control_match_info_to_mask (match_info, 1, "TE", &inner_error)) == MM_FLOW_CONTROL_UNKNOWN) + if ((te_mask = flow_control_match_info_to_mask (match_info, 1, "TE", log_object, &inner_error)) == MM_FLOW_CONTROL_UNKNOWN) goto out; /* Parse TA flow control methods */ - if ((ta_mask = flow_control_match_info_to_mask (match_info, 2, "TA", &inner_error)) == MM_FLOW_CONTROL_UNKNOWN) + if ((ta_mask = flow_control_match_info_to_mask (match_info, 2, "TA", log_object, &inner_error)) == MM_FLOW_CONTROL_UNKNOWN) goto out; /* Only those methods in both TA and TE will be the ones we report */ @@ -842,150 +823,57 @@ mm_flow_control_from_string (const gchar *str, /*************************************************************************/ -/* +CREG: (GSM 07.07 CREG=1 unsolicited) */ -#define CREG1 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])" - -/* +CREG: , (GSM 07.07 CREG=1 solicited) */ -#define CREG2 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])" - -/* +CREG: ,, (GSM 07.07 CREG=2 unsolicited) */ -#define CREG3 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" -#define CREG11 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*(\"[^\"\\s]*\")\\s*,\\s*(\"[^\"\\s]*\")" - -/* +CREG: ,,, (GSM 07.07 solicited and some CREG=2 unsolicited) */ -#define CREG4 "\\+(CREG|CGREG|CEREG):\\s*([0-9]),\\s*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)" -#define CREG5 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*(\"[^,]*\")\\s*,\\s*(\"[^,\\s]*\")" - -/* +CREG: ,,, (ETSI 27.007 CREG=2 unsolicited) */ -#define CREG6 "\\+(CREG|CGREG|CEREG):\\s*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9])" -#define CREG7 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*0*([0-9])" - -/* +CREG: ,,,, (ETSI 27.007 solicited and some CREG=2 unsolicited) */ -#define CREG8 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" - -/* +CREG: ,,,,, (Samsung Wave S8500) */ -/* '+CREG: 2,1,000B,2816, B, C2816OK' */ -#define CREG9 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*" - -/* +CREG: ,,,, (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */ -#define CREG10 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)" - -/* +CEREG: ,,,, (ETSI 27.007 v8.6 CREG=2 unsolicited with RAC) */ -#define CEREG1 "\\+(CEREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" - -/* +CEREG: ,,,,, (ETSI 27.007 v8.6 CREG=2 solicited with RAC) */ -#define CEREG2 "\\+(CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" +static const gchar *creg_regex[] = { + /* +CREG: (GSM 07.07 CREG=1 unsolicited) */ + [0] = "\\+(CREG|CGREG|CEREG|C5GREG):\\s*0*([0-9])", + /* +CREG: , (GSM 07.07 CREG=1 solicited) */ + [1] = "\\+(CREG|CGREG|CEREG|C5GREG):\\s*0*([0-9]),\\s*0*([0-9])", + /* +CREG: ,, (GSM 07.07 CREG=2 unsolicited) */ + [2] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", + /* +CREG: ,,, (GSM 07.07 solicited and some CREG=2 unsolicited) */ + [3] = "\\+(CREG|CGREG|CEREG):\\s*([0-9]),\\s*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)", + [4] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*(\"[^,]*\")\\s*,\\s*(\"[^,\\s]*\")", + /* +CREG: ,,, (ETSI 27.007 CREG=2 unsolicited) */ + [5] = "\\+(CREG|CGREG|CEREG):\\s*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9])", + [6] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*0*([0-9])", + /* +CREG: ,,,, (ETSI 27.007 solicited and some CREG=2 unsolicited) */ + [7] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", + /* +CREG: ,,,,, (Samsung Wave S8500) */ + /* '+CREG: 2,1,000B,2816, B, C2816OK' */ + [8] = "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*", + /* +CREG: ,,,, (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */ + [9] = "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)", + /* +CEREG: ,,,, (ETSI 27.007 v8.6 CREG=2 unsolicited with RAC) */ + [10] = "\\+(CEREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", + /* +CEREG: ,,,,, (ETSI 27.007 v8.6 CREG=2 solicited with RAC) */ + [11] = "\\+(CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", + /* +C5GREG: ,,,,, (ETSI 27.007 CREG=2 unsolicited) */ + [12] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", + /* +C5GREG: ,,,,,, (ETSI 27.007 solicited) */ + [13] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([0-9+])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", +}; GPtrArray * mm_3gpp_creg_regex_get (gboolean solicited) { - GPtrArray *array = g_ptr_array_sized_new (13); - GRegex *regex; - - /* #1 */ - if (solicited) - regex = g_regex_new (CREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #2 */ - if (solicited) - regex = g_regex_new (CREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #3 */ - if (solicited) - regex = g_regex_new (CREG3 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG3 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #4 */ - if (solicited) - regex = g_regex_new (CREG4 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG4 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #5 */ - if (solicited) - regex = g_regex_new (CREG5 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG5 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #6 */ - if (solicited) - regex = g_regex_new (CREG6 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG6 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #7 */ - if (solicited) - regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #8 */ - if (solicited) - regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #9 */ - if (solicited) - regex = g_regex_new (CREG9 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG9 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #10 */ - if (solicited) - regex = g_regex_new (CREG10 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG10 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #11 */ - if (solicited) - regex = g_regex_new (CREG11 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG11 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* CEREG #1 */ - if (solicited) - regex = g_regex_new (CEREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CEREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); + GPtrArray *array; + guint i; - /* CEREG #2 */ - if (solicited) - regex = g_regex_new (CEREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CEREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); + array = g_ptr_array_sized_new (G_N_ELEMENTS (creg_regex)); + for (i = 0; i < G_N_ELEMENTS (creg_regex); i++) { + GRegex *regex; + g_autofree gchar *pattern = NULL; + if (solicited) { + pattern = g_strdup_printf ("%s$", creg_regex[i]); + regex = g_regex_new (pattern, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + } else { + pattern = g_strdup_printf ("\\r\\n%s\\r\\n", creg_regex[i]); + regex = g_regex_new (pattern, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + } + g_assert (regex); + g_ptr_array_add (array, regex); + } return array; } @@ -1061,7 +949,9 @@ mm_3gpp_cds_regex_get (void) * NOTE: ignore WS46 prefix or it will break Cinterion handling. * * For the specific case of '25', we will check if any other mode supports - * 4G, and if there is none, we'll remove 4G caps from it. + * 4G, and if there is none, we'll remove 4G caps from it. This is needed + * because pre-LTE modems used '25' to report GERAN+URAN instead of the + * new '29' value since LTE modems are around. */ typedef struct { @@ -1069,7 +959,7 @@ typedef struct { MMModemMode mode; } Ws46Mode; -/* 3GPP TS 27.007 r14, section 5.9: select wireless network +WS46 */ +/* 3GPP TS 27.007 v16.3.0, section 5.9: select wireless network +WS46 */ static const Ws46Mode ws46_modes[] = { /* GSM Digital Cellular Systems (GERAN only) */ { 12, MM_MODEM_MODE_2G }, @@ -1083,8 +973,24 @@ static const Ws46Mode ws46_modes[] = { { 29, MM_MODEM_MODE_2G | MM_MODEM_MODE_3G }, /* GERAN and E-UTRAN */ { 30, MM_MODEM_MODE_2G | MM_MODEM_MODE_4G }, - /* UERAN and E-UTRAN */ + /* UTRAN and E-UTRAN */ { 31, MM_MODEM_MODE_3G | MM_MODEM_MODE_4G }, + /* GERAN, UTRAN, E-UTRAN and NG-RAN */ + { 35, MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G | MM_MODEM_MODE_5G }, + /* NG-RAN only */ + { 36, MM_MODEM_MODE_5G }, + /* E-UTRAN and NG-RAN */ + { 37, MM_MODEM_MODE_4G | MM_MODEM_MODE_5G }, + /* UTRAN, E-UTRAN and NG-RAN */ + { 38, MM_MODEM_MODE_3G | MM_MODEM_MODE_4G | MM_MODEM_MODE_5G }, + /* GERAN, E-UTRAN and NG-RAN */ + { 39, MM_MODEM_MODE_2G | MM_MODEM_MODE_4G | MM_MODEM_MODE_5G }, + /* UTRAN and NG-RAN */ + { 40, MM_MODEM_MODE_3G | MM_MODEM_MODE_5G }, + /* GERAN, UTRAN and NG-RAN */ + { 41, MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_5G }, + /* GERAN and NG-RAN */ + { 42, MM_MODEM_MODE_2G | MM_MODEM_MODE_5G }, }; GArray * @@ -1100,9 +1006,12 @@ mm_3gpp_parse_ws46_test_response (const gchar *response, guint val; guint i; guint j; + gboolean supported_5g = FALSE; gboolean supported_4g = FALSE; gboolean supported_3g = FALSE; gboolean supported_2g = FALSE; + gboolean supported_mode_25 = FALSE; + gboolean supported_mode_29 = FALSE; r = g_regex_new ("(?:\\+WS46:)?\\s*\\((.*)\\)(?:\\r\\n)?", 0, 0, NULL); g_assert (r != NULL); @@ -1131,15 +1040,21 @@ mm_3gpp_parse_ws46_test_response (const gchar *response, for (j = 0; j < G_N_ELEMENTS (ws46_modes); j++) { if (ws46_modes[j].ws46 == val) { - if (val != 25) { + if (val == 25) + supported_mode_25 = TRUE; + else { + if (val == 29) + supported_mode_29 = TRUE; + if (ws46_modes[j].mode & MM_MODEM_MODE_5G) + supported_5g = TRUE; if (ws46_modes[j].mode & MM_MODEM_MODE_4G) supported_4g = TRUE; if (ws46_modes[j].mode & MM_MODEM_MODE_3G) supported_3g = TRUE; if (ws46_modes[j].mode & MM_MODEM_MODE_2G) supported_2g = TRUE; + g_array_append_val (modes, ws46_modes[j].mode); } - g_array_append_val (modes, ws46_modes[j].mode); break; } } @@ -1148,6 +1063,17 @@ mm_3gpp_parse_ws46_test_response (const gchar *response, g_warning ("Unknown +WS46 mode reported: %u", val); } + if (supported_mode_25) { + MMModemMode mode_25; + + mode_25 = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G; + if (supported_4g) { + mode_25 |= MM_MODEM_MODE_4G; + g_array_append_val (modes, mode_25); + } else if (!supported_mode_29) + g_array_append_val (modes, mode_25); + } + if (modes->len == 0) { inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No valid modes reported"); g_clear_pointer (&modes, g_array_unref); @@ -1167,6 +1093,8 @@ mm_3gpp_parse_ws46_test_response (const gchar *response, *mode |= MM_MODEM_MODE_3G; if (supported_4g) *mode |= MM_MODEM_MODE_4G; + if (supported_5g) + *mode |= MM_MODEM_MODE_5G; if (*mode == 0) { inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No way to fixup the ANY value"); @@ -1216,7 +1144,8 @@ get_mm_access_tech_from_etsi_access_tech (guint act) { /* See ETSI TS 27.007 */ switch (act) { - case 0: + case 0: /* GSM */ + case 8: /* EC-GSM-IoT (A/Gb mode) */ return MM_MODEM_ACCESS_TECHNOLOGY_GSM; case 1: return MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT; @@ -1230,22 +1159,30 @@ get_mm_access_tech_from_etsi_access_tech (guint act) return MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; case 6: return MM_MODEM_ACCESS_TECHNOLOGY_HSPA; - case 7: + case 7: /* E-UTRAN */ + case 9: /* E-UTRAN (NB-S1) */ + case 10: /* E-UTRA connected to a 5GCN */ return MM_MODEM_ACCESS_TECHNOLOGY_LTE; + case 11: /* NR connected to a 5G CN */ + case 12: /* NG-RAN */ + return MM_MODEM_ACCESS_TECHNOLOGY_5GNR; + case 13: /* E-UTRA-NR dual connectivity */ + return (MM_MODEM_ACCESS_TECHNOLOGY_5GNR | MM_MODEM_ACCESS_TECHNOLOGY_LTE); default: return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; } } static MMModem3gppNetworkAvailability -parse_network_status (const gchar *str) +parse_network_status (const gchar *str, + gpointer log_object) { /* Expecting a value between '0' and '3' inclusive */ if (!str || strlen (str) != 1 || str[0] < '0' || str[0] > '3') { - mm_warn ("Cannot parse network status: '%s'", str); + mm_obj_warn (log_object, "cannot parse network status value '%s'", str); return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN; } @@ -1253,14 +1190,15 @@ parse_network_status (const gchar *str) } static MMModemAccessTechnology -parse_access_tech (const gchar *str) +parse_access_tech (const gchar *str, + gpointer log_object) { /* Recognized access technologies are between '0' and '7' inclusive... */ if (!str || strlen (str) != 1 || str[0] < '0' || str[0] > '7') { - mm_warn ("Cannot parse access tech: '%s'", str); + mm_obj_warn (log_object, "cannot parse access technology value '%s'", str); return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; } @@ -1270,13 +1208,13 @@ parse_access_tech (const gchar *str) GList * mm_3gpp_parse_cops_test_response (const gchar *reply, MMModemCharset cur_charset, + gpointer log_object, GError **error) { GRegex *r; GList *info_list = NULL; GMatchInfo *match_info; gboolean umts_format = TRUE; - GError *inner_error = NULL; g_return_val_if_fail (reply != NULL, NULL); if (error) @@ -1305,15 +1243,8 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, * +COPS: (2,"","T-Mobile","31026",0),(1,"AT&T","AT&T","310410"),0) */ - r = g_regex_new ("\\((\\d),\"([^\"\\)]*)\",([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, &inner_error); - if (inner_error) { - mm_err ("Invalid regular expression: %s", inner_error->message); - g_error_free (inner_error); - g_set_error_literal (error, - MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Could not parse scan results"); - return NULL; - } + r = g_regex_new ("\\((\\d),\"([^\"\\)]*)\",([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, NULL); + g_assert (r); /* If we didn't get any hits, try the pre-UMTS format match */ if (!g_regex_match (r, reply, 0, &match_info)) { @@ -1334,15 +1265,8 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, * +COPS: (2,"T - Mobile",,"31026"),(1,"Einstein PCS",,"31064"),(1,"Cingular",,"31041"),,(0,1,3),(0,2) */ - r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, &inner_error); - if (inner_error) { - mm_err ("Invalid regular expression: %s", inner_error->message); - g_error_free (inner_error); - g_set_error_literal (error, - MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Could not parse scan results"); - return NULL; - } + r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, NULL); + g_assert (r); g_regex_match (r, reply, 0, &match_info); umts_format = FALSE; @@ -1357,7 +1281,7 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, info = g_new0 (MM3gppNetworkInfo, 1); tmp = mm_get_string_unquoted_from_match_info (match_info, 1); - info->status = parse_network_status (tmp); + info->status = parse_network_status (tmp, log_object); g_free (tmp); info->operator_long = mm_get_string_unquoted_from_match_info (match_info, 2); @@ -1365,9 +1289,9 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, info->operator_code = mm_get_string_unquoted_from_match_info (match_info, 4); /* The returned strings may be given in e.g. UCS2 */ - mm_3gpp_normalize_operator (&info->operator_long, cur_charset); - mm_3gpp_normalize_operator (&info->operator_short, cur_charset); - mm_3gpp_normalize_operator (&info->operator_code, cur_charset); + mm_3gpp_normalize_operator (&info->operator_long, cur_charset, log_object); + mm_3gpp_normalize_operator (&info->operator_short, cur_charset, log_object); + mm_3gpp_normalize_operator (&info->operator_code, cur_charset, log_object); /* Only try for access technology with UMTS-format matches. * If none give, assume GSM */ @@ -1375,7 +1299,7 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, mm_get_string_unquoted_from_match_info (match_info, 5) : NULL); info->access_tech = (tmp ? - parse_access_tech (tmp) : + parse_access_tech (tmp, log_object) : MM_MODEM_ACCESS_TECHNOLOGY_GSM); g_free (tmp); @@ -1397,17 +1321,15 @@ mm_3gpp_parse_cops_test_response (const gchar *reply, } if (valid) { - gchar *access_tech_str; + g_autofree gchar *access_tech_str = NULL; access_tech_str = mm_modem_access_technology_build_string_from_mask (info->access_tech); - mm_dbg ("Found network '%s' ('%s','%s'); availability: %s, access tech: %s", - info->operator_code, - info->operator_short ? info->operator_short : "no short name", - info->operator_long ? info->operator_long : "no long name", - mm_modem_3gpp_network_availability_get_string (info->status), - access_tech_str); - g_free (access_tech_str); - + mm_obj_dbg (log_object, "found network '%s' ('%s','%s'); availability: %s, access tech: %s", + info->operator_code, + info->operator_short ? info->operator_short : "no short name", + info->operator_long ? info->operator_long : "no long name", + mm_modem_3gpp_network_availability_get_string (info->status), + access_tech_str); info_list = g_list_prepend (info_list, info); } else @@ -1576,8 +1498,9 @@ mm_3gpp_select_best_cid (const gchar *apn, MMBearerIpFamily ip_family, GList *context_list, GList *context_format_list, - gboolean *cid_reused, - gboolean *cid_overwritten) + gpointer log_object, + gboolean *out_cid_reused, + gboolean *out_cid_overwritten) { GList *l; guint prev_cid = 0; @@ -1588,9 +1511,12 @@ mm_3gpp_select_best_cid (const gchar *apn, guint blank_cid = 0; gchar *ip_family_str; + g_assert (out_cid_reused); + g_assert (out_cid_overwritten); + ip_family_str = mm_bearer_ip_family_build_string_from_mask (ip_family); - mm_dbg ("Looking for best CID matching APN '%s' and PDP type '%s'...", - apn, ip_family_str); + mm_obj_dbg (log_object, "looking for best CID matching APN '%s' and PDP type '%s'...", + apn, ip_family_str); g_free (ip_family_str); /* Look for the exact PDP context we want */ @@ -1631,17 +1557,17 @@ mm_3gpp_select_best_cid (const gchar *apn, /* Always prefer an exact match */ if (exact_cid) { - mm_dbg ("Found exact context at CID %u", exact_cid); - *cid_reused = TRUE; - *cid_overwritten = FALSE; + mm_obj_dbg (log_object, "found exact context at CID %u", exact_cid); + *out_cid_reused = TRUE; + *out_cid_overwritten = FALSE; return exact_cid; } /* Try to use an unused CID detected in between the already defined contexts */ if (unused_cid) { - mm_dbg ("Found unused context at CID %u", unused_cid); - *cid_reused = FALSE; - *cid_overwritten = FALSE; + mm_obj_dbg (log_object, "found unused context at CID %u", unused_cid); + *out_cid_reused = FALSE; + *out_cid_overwritten = FALSE; return unused_cid; } @@ -1649,32 +1575,32 @@ mm_3gpp_select_best_cid (const gchar *apn, * CID, then we can use the next available CID because it's an unused one. */ max_allowed_cid = find_max_allowed_cid (context_format_list, ip_family); if (max_cid && (max_cid < max_allowed_cid)) { - mm_dbg ("Found unused context at CID %u (<%u)", max_cid + 1, max_allowed_cid); - *cid_reused = FALSE; - *cid_overwritten = FALSE; + mm_obj_dbg (log_object, "found unused context at CID %u (<%u)", max_cid + 1, max_allowed_cid); + *out_cid_reused = FALSE; + *out_cid_overwritten = FALSE; return (max_cid + 1); } /* Rewrite a context defined with no APN, if any */ if (blank_cid) { - mm_dbg ("Rewriting context with empty APN at CID %u", blank_cid); - *cid_reused = FALSE; - *cid_overwritten = TRUE; + mm_obj_dbg (log_object, "rewriting context with empty APN at CID %u", blank_cid); + *out_cid_reused = FALSE; + *out_cid_overwritten = TRUE; return blank_cid; } /* Rewrite the last existing one found */ if (max_cid) { - mm_dbg ("Rewriting last context detected at CID %u", max_cid); - *cid_reused = FALSE; - *cid_overwritten = TRUE; + mm_obj_dbg (log_object, "rewriting last context detected at CID %u", max_cid); + *out_cid_reused = FALSE; + *out_cid_overwritten = TRUE; return max_cid; } /* Otherwise, just fallback to CID=1 */ - mm_dbg ("Falling back to CID 1"); - *cid_reused = FALSE; - *cid_overwritten = TRUE; + mm_obj_dbg (log_object, "falling back to CID 1"); + *out_cid_reused = FALSE; + *out_cid_overwritten = TRUE; return 1; } @@ -1693,8 +1619,9 @@ mm_3gpp_pdp_context_format_list_free (GList *pdp_format_list) } GList * -mm_3gpp_parse_cgdcont_test_response (const gchar *response, - GError **error) +mm_3gpp_parse_cgdcont_test_response (const gchar *response, + gpointer log_object, + GError **error) { GRegex *r; GMatchInfo *match_info; @@ -1722,11 +1649,11 @@ mm_3gpp_parse_cgdcont_test_response (const gchar *response, pdp_type_str = mm_get_string_unquoted_from_match_info (match_info, 3); pdp_type = mm_3gpp_get_ip_family_from_pdp_type (pdp_type_str); if (pdp_type == MM_BEARER_IP_FAMILY_NONE) - mm_dbg ("Unhandled PDP type in CGDCONT=? reply: '%s'", pdp_type_str); + mm_obj_dbg (log_object, "unhandled PDP type in CGDCONT=? reply: '%s'", pdp_type_str); else { /* Read min CID */ if (!mm_get_uint_from_match_info (match_info, 1, &min_cid)) - mm_warn ("Invalid min CID in CGDCONT=? reply for PDP type '%s'", pdp_type_str); + mm_obj_warn (log_object, "invalid min CID in CGDCONT=? reply for PDP type '%s'", pdp_type_str); else { MM3gppPdpContextFormat *format; @@ -1751,7 +1678,7 @@ mm_3gpp_parse_cgdcont_test_response (const gchar *response, g_regex_unref (r); if (inner_error) { - mm_warn ("Unexpected error matching +CGDCONT response: '%s'", inner_error->message); + mm_obj_warn (log_object, "unexpected error matching +CGDCONT response: '%s'", inner_error->message); g_error_free (inner_error); } @@ -1807,9 +1734,7 @@ mm_3gpp_parse_cgdcont_read_response (const gchar *reply, str = mm_get_string_unquoted_from_match_info (match_info, 2); ip_family = mm_3gpp_get_ip_family_from_pdp_type (str); - if (ip_family == MM_BEARER_IP_FAMILY_NONE) - mm_dbg ("Ignoring PDP context type: '%s'", str); - else { + if (ip_family != MM_BEARER_IP_FAMILY_NONE) { MM3gppPdpContext *pdp; pdp = g_slice_new0 (MM3gppPdpContext); @@ -1931,35 +1856,6 @@ mm_3gpp_parse_cgact_read_response (const gchar *reply, /*************************************************************************/ -static gulong -parse_uint (gchar *str, - gint base, - gulong nmin, - gulong nmax, - gboolean *valid) -{ - gulong ret = 0; - gchar *endquote; - - *valid = FALSE; - if (!str) - return 0; - - /* Strip quotes */ - if (str[0] == '"') - str++; - endquote = strchr (str, '"'); - if (endquote) - *endquote = '\0'; - - if (strlen (str)) { - ret = strtol (str, NULL, base); - if ((nmin == nmax) || (ret >= nmin && ret <= nmax)) - *valid = TRUE; - } - return *valid ? (guint) ret : 0; -} - static gboolean item_is_lac_not_stat (GMatchInfo *info, guint32 item) { @@ -1975,32 +1871,36 @@ item_is_lac_not_stat (GMatchInfo *info, guint32 item) } gboolean -mm_3gpp_parse_creg_response (GMatchInfo *info, - MMModem3gppRegistrationState *out_reg_state, - gulong *out_lac, - gulong *out_ci, - MMModemAccessTechnology *out_act, - gboolean *out_cgreg, - gboolean *out_cereg, - GError **error) +mm_3gpp_parse_creg_response (GMatchInfo *info, + gpointer log_object, + MMModem3gppRegistrationState *out_reg_state, + gulong *out_lac, + gulong *out_ci, + MMModemAccessTechnology *out_act, + gboolean *out_cgreg, + gboolean *out_cereg, + gboolean *out_c5greg, + GError **error) { - gboolean success = FALSE, foo; gint n_matches, act = -1; - gulong stat = 0, lac = 0, ci = 0; + guint stat = 0; + guint64 lac = 0, ci = 0; guint istat = 0, ilac = 0, ici = 0, iact = 0; gchar *str; - g_return_val_if_fail (info != NULL, FALSE); - g_return_val_if_fail (out_reg_state != NULL, FALSE); - g_return_val_if_fail (out_lac != NULL, FALSE); - g_return_val_if_fail (out_ci != NULL, FALSE); - g_return_val_if_fail (out_act != NULL, FALSE); - g_return_val_if_fail (out_cgreg != NULL, FALSE); - g_return_val_if_fail (out_cereg != NULL, FALSE); + g_assert (info != NULL); + g_assert (out_reg_state != NULL); + g_assert (out_lac != NULL); + g_assert (out_ci != NULL); + g_assert (out_act != NULL); + g_assert (out_cgreg != NULL); + g_assert (out_cereg != NULL); + g_assert (out_c5greg != NULL); str = g_match_info_fetch (info, 1); *out_cgreg = (str && strstr (str, "CGREG")) ? TRUE : FALSE; *out_cereg = (str && strstr (str, "CEREG")) ? TRUE : FALSE; + *out_c5greg = (str && strstr (str, "C5GREG")) ? TRUE : FALSE; g_free (str); /* Normally the number of matches could be used to determine what each @@ -2045,88 +1945,85 @@ mm_3gpp_parse_creg_response (GMatchInfo *info, /* Check if the third item is the LAC to distinguish the two cases */ if (item_is_lac_not_stat (info, 3)) { istat = 2; - ilac = 3; + ilac = 3; } else { istat = 3; - ilac = 4; + ilac = 4; } - ici = 5; + ici = 5; iact = 6; } else { /* Check if the third item is the LAC to distinguish the two cases */ if (item_is_lac_not_stat (info, 3)) { istat = 2; - ilac = 3; - ici = 4; - iact = 5; + ilac = 3; + ici = 4; + iact = 5; } else { istat = 3; - ilac = 4; - ici = 5; - iact = 6; + ilac = 4; + ici = 5; + iact = 6; } } } else if (n_matches == 8) { /* CEREG=2 (solicited with RAC): +CEREG: ,,,,, + * C5GREG=2 (unsolicited): +C5GREG: ,,,,, */ if (*out_cereg) { istat = 3; - ilac = 4; - ici = 6; - iact = 7; + ilac = 4; + ici = 6; + iact = 7; + } else if (*out_c5greg) { + istat = 2; + ilac = 3; + ici = 4; + iact = 5; } - } + } else if (n_matches == 9) { + /* C5GREG=2 (solicited): +C5GREG: ,,,,,, */ + istat = 3; + ilac = 4; + ici = 5; + iact = 6; + } /* Status */ - str = g_match_info_fetch (info, istat); - stat = parse_uint (str, 10, 0, G_MAXUINT, &success); - g_free (str); - if (!success) { + if (!mm_get_uint_from_match_info (info, istat, &stat)) { g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse the registration status response"); return FALSE; } - /* 'roaming (csfb not preferred)' is the last valid state */ - if (stat > MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) { - mm_warn ("Registration State '%lu' is unknown", stat); + /* 'attached RLOS' is the last valid state */ + if (stat > MM_MODEM_3GPP_REGISTRATION_STATE_ATTACHED_RLOS) { + mm_obj_warn (log_object, "unknown registration state value '%u'", stat); stat = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; } - /* Location Area Code */ - if (ilac) { - /* FIXME: some phones apparently swap the LAC bytes (LG, SonyEricsson, - * Sagem). Need to handle that. - */ - str = g_match_info_fetch (info, ilac); - lac = parse_uint (str, 16, 1, 0xFFFF, &foo); - g_free (str); - } + /* Location Area Code/Tracking Area Code + * FIXME: some phones apparently swap the LAC bytes (LG, SonyEricsson, + * Sagem). Need to handle that. + */ + if (ilac) + mm_get_u64_from_hex_match_info (info, ilac, &lac); /* Cell ID */ - if (ici) { - str = g_match_info_fetch (info, ici); - ci = parse_uint (str, 16, 1, 0x0FFFFFFE, &foo); - g_free (str); - } + if (ici) + mm_get_u64_from_hex_match_info (info, ici, &ci); /* Access Technology */ - if (iact) { - str = g_match_info_fetch (info, iact); - act = (gint) parse_uint (str, 10, 0, 7, &foo); - g_free (str); - if (!foo) - act = -1; - } + if (iact) + mm_get_int_from_match_info (info, iact, &act); *out_reg_state = (MMModem3gppRegistrationState) stat; if (stat != MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) { /* Don't fill in lac/ci/act if the device's state is unknown */ - *out_lac = lac; - *out_ci = ci; - - *out_act = get_mm_access_tech_from_etsi_access_tech (act); + *out_lac = (gulong)lac; + *out_ci = (gulong)ci; + *out_act = (act >= 0 ? get_mm_access_tech_from_etsi_access_tech (act) : MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); } return TRUE; } @@ -2647,8 +2544,9 @@ mm_3gpp_parse_cesq_response (const gchar *response, } gboolean -mm_3gpp_rxlev_to_rssi (guint rxlev, - gdouble *out_rssi) +mm_3gpp_rxlev_to_rssi (guint rxlev, + gpointer log_object, + gdouble *out_rssi) { if (rxlev <= 63) { *out_rssi = -111.0 + rxlev; @@ -2656,13 +2554,14 @@ mm_3gpp_rxlev_to_rssi (guint rxlev, } if (rxlev != 99) - mm_warn ("unexpected rxlev: %u", rxlev); + mm_obj_warn (log_object, "unexpected rxlev: %u", rxlev); return FALSE; } gboolean -mm_3gpp_rscp_level_to_rscp (guint rscp_level, - gdouble *out_rscp) +mm_3gpp_rscp_level_to_rscp (guint rscp_level, + gpointer log_object, + gdouble *out_rscp) { if (rscp_level <= 96) { *out_rscp = -121.0 + rscp_level; @@ -2670,13 +2569,14 @@ mm_3gpp_rscp_level_to_rscp (guint rscp_level, } if (rscp_level != 255) - mm_warn ("unexpected rscp level: %u", rscp_level); + mm_obj_warn (log_object, "unexpected rscp level: %u", rscp_level); return FALSE; } gboolean -mm_3gpp_ecn0_level_to_ecio (guint ecn0_level, - gdouble *out_ecio) +mm_3gpp_ecn0_level_to_ecio (guint ecn0_level, + gpointer log_object, + gdouble *out_ecio) { if (ecn0_level <= 49) { *out_ecio = -24.5 + (((gdouble) ecn0_level) * 0.5); @@ -2684,13 +2584,14 @@ mm_3gpp_ecn0_level_to_ecio (guint ecn0_level, } if (ecn0_level != 255) - mm_warn ("unexpected Ec/N0 level: %u", ecn0_level); + mm_obj_warn (log_object, "unexpected Ec/N0 level: %u", ecn0_level); return FALSE; } gboolean -mm_3gpp_rsrq_level_to_rsrq (guint rsrq_level, - gdouble *out_rsrq) +mm_3gpp_rsrq_level_to_rsrq (guint rsrq_level, + gpointer log_object, + gdouble *out_rsrq) { if (rsrq_level <= 34) { *out_rsrq = -20.0 + (((gdouble) rsrq_level) * 0.5); @@ -2698,13 +2599,14 @@ mm_3gpp_rsrq_level_to_rsrq (guint rsrq_level, } if (rsrq_level != 255) - mm_warn ("unexpected RSRQ level: %u", rsrq_level); + mm_obj_warn (log_object, "unexpected RSRQ level: %u", rsrq_level); return FALSE; } gboolean -mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level, - gdouble *out_rsrp) +mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level, + gpointer log_object, + gdouble *out_rsrp) { if (rsrp_level <= 97) { *out_rsrp = -141.0 + rsrp_level; @@ -2712,12 +2614,13 @@ mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level, } if (rsrp_level != 255) - mm_warn ("unexpected RSRP level: %u", rsrp_level); + mm_obj_warn (log_object, "unexpected RSRP level: %u", rsrp_level); return FALSE; } gboolean mm_3gpp_cesq_response_to_signal_info (const gchar *response, + gpointer log_object, MMSignal **out_gsm, MMSignal **out_umts, MMSignal **out_lte, @@ -2746,7 +2649,7 @@ mm_3gpp_cesq_response_to_signal_info (const gchar *response, return FALSE; /* GERAN RSSI */ - if (mm_3gpp_rxlev_to_rssi (rxlev, &rssi)) { + if (mm_3gpp_rxlev_to_rssi (rxlev, log_object, &rssi)) { gsm = mm_signal_new (); mm_signal_set_rssi (gsm, rssi); } @@ -2754,26 +2657,26 @@ mm_3gpp_cesq_response_to_signal_info (const gchar *response, /* ignore BER */ /* UMTS RSCP */ - if (mm_3gpp_rscp_level_to_rscp (rscp_level, &rscp)) { + if (mm_3gpp_rscp_level_to_rscp (rscp_level, log_object, &rscp)) { umts = mm_signal_new (); mm_signal_set_rscp (umts, rscp); } /* UMTS EcIo (assumed EcN0) */ - if (mm_3gpp_ecn0_level_to_ecio (ecn0_level, &ecio)) { + if (mm_3gpp_ecn0_level_to_ecio (ecn0_level, log_object, &ecio)) { if (!umts) umts = mm_signal_new (); mm_signal_set_ecio (umts, ecio); } /* LTE RSRQ */ - if (mm_3gpp_rsrq_level_to_rsrq (rsrq_level, &rsrq)) { + if (mm_3gpp_rsrq_level_to_rsrq (rsrq_level, log_object, &rsrq)) { lte = mm_signal_new (); mm_signal_set_rsrq (lte, rsrq); } /* LTE RSRP */ - if (mm_3gpp_rsrp_level_to_rsrp (rsrp_level, &rsrp)) { + if (mm_3gpp_rsrp_level_to_rsrp (rsrp_level, log_object, &rsrp)) { if (!lte) lte = mm_signal_new (); mm_signal_set_rsrp (lte, rsrp); @@ -2872,6 +2775,7 @@ mm_3gpp_parse_cemode_query_response (const gchar *response, gboolean mm_3gpp_parse_ccwa_service_query_response (const gchar *response, + gpointer log_object, gboolean *status, GError **error) { @@ -2907,10 +2811,10 @@ mm_3gpp_parse_ccwa_service_query_response (const gchar *response, guint class; if (!mm_get_uint_from_match_info (match_info, 2, &class)) - mm_warn ("couldn't parse class from +CCWA line"); + mm_obj_warn (log_object, "couldn't parse class from +CCWA line"); else if (class == 1 || class == 255) { if (!mm_get_uint_from_match_info (match_info, 1, &st)) - mm_warn ("couldn't parse status from +CCWA line"); + mm_obj_warn (log_object, "couldn't parse status from +CCWA line"); else { class_1_status = st; break; @@ -2967,17 +2871,18 @@ storage_from_str (const gchar *str) } gboolean -mm_3gpp_parse_cpms_test_response (const gchar *reply, - GArray **mem1, - GArray **mem2, - GArray **mem3) +mm_3gpp_parse_cpms_test_response (const gchar *reply, + GArray **mem1, + GArray **mem2, + GArray **mem3, + GError **error) { - GRegex *r; - gchar **split; guint i; - GArray *tmp1 = NULL; - GArray *tmp2 = NULL; - GArray *tmp3 = NULL; + g_autoptr(GRegex) r = NULL; + g_autoptr(GArray) tmp1 = NULL; + g_autoptr(GArray) tmp2 = NULL; + g_autoptr(GArray) tmp3 = NULL; + g_auto(GStrv) split = NULL; g_assert (mem1 != NULL); g_assert (mem2 != NULL); @@ -2986,13 +2891,16 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply, #define N_EXPECTED_GROUPS 3 split = mm_split_string_groups (mm_strip_tag (reply, "+CPMS:")); - if (!split) + if (!split) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't split +CPMS test response in groups"); return FALSE; + } if (g_strv_length (split) != N_EXPECTED_GROUPS) { - mm_warn ("Cannot parse +CPMS test response: invalid number of groups (%u != %u)", - g_strv_length (split), N_EXPECTED_GROUPS); - g_strfreev (split); + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Cannot parse +CPMS test response: invalid number of groups (%u != %u)", + g_strv_length (split), N_EXPECTED_GROUPS); return FALSE; } @@ -3035,29 +2943,20 @@ mm_3gpp_parse_cpms_test_response (const gchar *reply, g_assert_not_reached (); } - g_strfreev (split); - g_regex_unref (r); - - g_warn_if_fail (tmp1 != NULL); - g_warn_if_fail (tmp2 != NULL); - g_warn_if_fail (tmp3 != NULL); - /* Only return TRUE if all sets have been parsed correctly * (even if the arrays may be empty) */ if (tmp1 && tmp2 && tmp3) { - *mem1 = tmp1; - *mem2 = tmp2; - *mem3 = tmp3; + *mem1 = g_steal_pointer (&tmp1); + *mem2 = g_steal_pointer (&tmp2); + *mem3 = g_steal_pointer (&tmp3); return TRUE; } - /* Otherwise, cleanup and return FALSE */ - if (tmp1) - g_array_unref (tmp1); - if (tmp2) - g_array_unref (tmp2); - if (tmp3) - g_array_unref (tmp3); + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Cannot parse +CPMS test response: mem1 %s, mem2 %s, mem3 %s", + tmp1 ? "yes" : "no", + tmp2 ? "yes" : "no", + tmp3 ? "yes" : "no"); return FALSE; } @@ -3279,9 +3178,9 @@ mm_3gpp_parse_clck_write_response (const gchar *reply, GStrv mm_3gpp_parse_cnum_exec_response (const gchar *reply) { - GArray *array = NULL; - GRegex *r; - GMatchInfo *match_info; + g_autoptr(GPtrArray) array = NULL; + g_autoptr(GRegex) r = NULL; + g_autoptr(GMatchInfo) match_info = NULL; /* Empty strings also return NULL list */ if (!reply || !reply[0]) @@ -3291,26 +3190,22 @@ mm_3gpp_parse_cnum_exec_response (const gchar *reply) G_REGEX_UNGREEDY, 0, NULL); g_assert (r != NULL); + array = g_ptr_array_new (); g_regex_match (r, reply, 0, &match_info); while (g_match_info_matches (match_info)) { - gchar *number; + g_autofree gchar *number = NULL; number = g_match_info_fetch_named (match_info, "num"); - - if (number && number[0]) { - if (!array) - array = g_array_new (TRUE, TRUE, sizeof (gchar *)); - g_array_append_val (array, number); - } else - g_free (number); - + if (number && number[0]) + g_ptr_array_add (array, g_steal_pointer (&number)); g_match_info_next (match_info, NULL); } - g_match_info_free (match_info); - g_regex_unref (r); + if (!array->len) + return NULL; - return (array ? (GStrv) g_array_free (array, FALSE) : NULL); + g_ptr_array_add (array, NULL); + return (GStrv) g_ptr_array_free (g_steal_pointer (&array), FALSE); } /*************************************************************************/ @@ -3337,6 +3232,7 @@ mm_3gpp_build_cmer_set_request (MM3gppCmerMode mode, gboolean mm_3gpp_parse_cmer_test_response (const gchar *response, + gpointer log_object, MM3gppCmerMode *out_supported_modes, MM3gppCmerInd *out_supported_inds, GError **error) @@ -3391,7 +3287,7 @@ mm_3gpp_parse_cmer_test_response (const gchar *response, if (mode_val <= 3) supported_modes |= (MM3gppCmerMode) (1 << mode_val); else - mm_dbg ("Unknown +CMER mode reported: %u", mode_val); + mm_obj_dbg (log_object, "unknown +CMER mode reported: %u", mode_val); } for (i = 0; i < array_supported_inds->len; i++) { @@ -3401,7 +3297,7 @@ mm_3gpp_parse_cmer_test_response (const gchar *response, if (ind_val <= 2) supported_inds |= (MM3gppCmerInd) (1 << ind_val); else - mm_dbg ("Unknown +CMER ind reported: %u", ind_val); + mm_obj_dbg (log_object, "unknown +CMER ind reported: %u", ind_val); } if (out_supported_modes) @@ -4122,8 +4018,11 @@ mm_string_to_access_tech (const gchar *string) void mm_3gpp_normalize_operator (gchar **operator, - MMModemCharset cur_charset) + MMModemCharset cur_charset, + gpointer log_object) { + g_autofree gchar *normalized = NULL; + g_assert (operator); if (*operator == NULL) @@ -4131,31 +4030,38 @@ mm_3gpp_normalize_operator (gchar **operator, /* Despite +CSCS? may claim supporting UCS2, Some modems (e.g. Huawei) * always report the operator name in ASCII in a +COPS response. */ - if (cur_charset == MM_MODEM_CHARSET_UCS2) { - gchar *tmp; + if (cur_charset != MM_MODEM_CHARSET_UNKNOWN) { + g_autoptr(GError) error = NULL; - tmp = g_strdup (*operator); - /* In this case we're already checking UTF-8 validity */ - tmp = mm_charset_take_and_convert_to_utf8 (tmp, cur_charset); - if (tmp) { - g_clear_pointer (operator, g_free); - *operator = tmp; + normalized = mm_modem_charset_str_to_utf8 (*operator, -1, cur_charset, TRUE, &error); + if (normalized) goto out; - } + + mm_obj_dbg (log_object, "couldn't convert operator string '%s' from charset '%s': %s", + *operator, + mm_modem_charset_to_string (cur_charset), + error->message); } /* Charset is unknown or there was an error in conversion; try to see * if the contents we got are valid UTF-8 already. */ - if (!g_utf8_validate (*operator, -1, NULL)) - g_clear_pointer (operator, g_free); + if (g_utf8_validate (*operator, -1, NULL)) + normalized = g_strdup (*operator); out: /* Some modems (Novatel LTE) return the operator name as "Unknown" when * it fails to obtain the operator name. Return NULL in such case. */ - if (*operator && g_ascii_strcasecmp (*operator, "unknown") == 0) + if (!normalized || g_ascii_strcasecmp (normalized, "unknown") == 0) { + /* If normalization failed, just cleanup the string */ g_clear_pointer (operator, g_free); + return; + } + + mm_obj_dbg (log_object, "operator normalized '%s'->'%s'", *operator, normalized); + g_clear_pointer (operator, g_free); + *operator = g_steal_pointer (&normalized); } /*************************************************************************/ @@ -4395,10 +4301,9 @@ mm_3gpp_parse_emergency_numbers (const char *raw, GError **error) return NULL; } - bin = (guint8 *) mm_utils_hexstr2bin (raw, &binlen); + bin = mm_utils_hexstr2bin (raw, -1, &binlen, error); if (!bin) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, - "invalid raw emergency numbers list contents: %s", raw); + g_prefix_error (error, "invalid raw emergency numbers list contents: "); return NULL; } @@ -4408,7 +4313,7 @@ mm_3gpp_parse_emergency_numbers (const char *raw, GError **error) for (i = 0; i < max_items; i++) { gchar *number; - number = mm_bcd_to_string (&bin[i*3], 3); + number = mm_bcd_to_string (&bin[i*3], 3, TRUE /* low_nybble_first */); if (number && number[0]) g_ptr_array_add (out, number); else diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 9c1be81f..0f314959 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -39,13 +39,10 @@ /* Common utilities */ /*****************************************************************************/ -#define MM_MODEM_CAPABILITY_3GPP_LTE \ - (MM_MODEM_CAPABILITY_LTE | \ - MM_MODEM_CAPABILITY_LTE_ADVANCED) - #define MM_MODEM_CAPABILITY_3GPP \ (MM_MODEM_CAPABILITY_GSM_UMTS | \ - MM_MODEM_CAPABILITY_3GPP_LTE) + MM_MODEM_CAPABILITY_LTE | \ + MM_MODEM_CAPABILITY_5GNR) gchar *mm_strip_quotes (gchar *str); const gchar *mm_strip_tag (const gchar *str, @@ -59,8 +56,9 @@ GArray *mm_parse_uint_list (const gchar *str, guint mm_count_bits_set (gulong number); guint mm_find_bit_set (gulong number); -gchar *mm_create_device_identifier (guint vid, - guint pid, +gchar *mm_create_device_identifier (guint vid, + guint pid, + gpointer log_object, const gchar *ati, const gchar *ati1, const gchar *gsn, @@ -83,12 +81,12 @@ gchar *mm_new_iso8601_time (guint year, gint offset_minutes); GArray *mm_filter_supported_modes (const GArray *all, - const GArray *supported_combinations); - -GArray *mm_filter_supported_capabilities (MMModemCapability all, - const GArray *supported_combinations); + const GArray *supported_combinations, + gpointer log_object); -gchar *mm_bcd_to_string (const guint8 *bcd, gsize bcd_len); +gchar *mm_bcd_to_string (const guint8 *bcd, + gsize bcd_len, + gboolean low_nybble_first); /*****************************************************************************/ /* VOICE specific helpers and utilities */ @@ -107,6 +105,7 @@ typedef struct { gchar *number; /* optional */ } MMCallInfo; gboolean mm_3gpp_parse_clcc_response (const gchar *str, + gpointer log_object, GList **out_list, GError **error); void mm_3gpp_call_info_list_free (GList *call_info_list); @@ -126,6 +125,7 @@ typedef enum { /*< underscore_name=mm_flow_control >*/ } MMFlowControl; MMFlowControl mm_parse_ifc_test_response (const gchar *response, + gpointer log_object, GError **error); MMFlowControl mm_flow_control_from_string (const gchar *str, @@ -159,6 +159,7 @@ typedef struct { void mm_3gpp_network_info_list_free (GList *info_list); GList *mm_3gpp_parse_cops_test_response (const gchar *reply, MMModemCharset cur_charset, + gpointer log_object, GError **error); /* AT+COPS? (current operator) response parser */ @@ -180,8 +181,9 @@ typedef struct { MMBearerIpFamily pdp_type; } MM3gppPdpContextFormat; void mm_3gpp_pdp_context_format_list_free (GList *pdp_format_list); -GList *mm_3gpp_parse_cgdcont_test_response (const gchar *reply, - GError **error); +GList *mm_3gpp_parse_cgdcont_test_response (const gchar *reply, + gpointer log_object, + GError **error); /* AT+CGDCONT? (PDP context query) response parser */ typedef struct { @@ -198,8 +200,9 @@ guint mm_3gpp_select_best_cid (const gchar *apn, MMBearerIpFamily ip_family, GList *context_list, GList *context_format_list, - gboolean *cid_reused, - gboolean *cid_overwritten); + gpointer log_object, + gboolean *out_cid_reused, + gboolean *out_cid_overwritten); /* AT+CGACT? (active PDP context query) response parser */ typedef struct { @@ -213,14 +216,16 @@ GList *mm_3gpp_parse_cgact_read_response (const gchar *reply, GError **error); /* CREG/CGREG response/unsolicited message parser */ -gboolean mm_3gpp_parse_creg_response (GMatchInfo *info, - MMModem3gppRegistrationState *out_reg_state, - gulong *out_lac, - gulong *out_ci, - MMModemAccessTechnology *out_act, - gboolean *out_cgreg, - gboolean *out_cereg, - GError **error); +gboolean mm_3gpp_parse_creg_response (GMatchInfo *info, + gpointer log_object, + MMModem3gppRegistrationState *out_reg_state, + gulong *out_lac, + gulong *out_ci, + MMModemAccessTechnology *out_act, + gboolean *out_cgreg, + gboolean *out_cereg, + gboolean *out_c5greg, + GError **error); /* AT+CMGF=? (SMS message format) response parser */ gboolean mm_3gpp_parse_cmgf_test_response (const gchar *reply, @@ -229,10 +234,11 @@ gboolean mm_3gpp_parse_cmgf_test_response (const gchar *reply, GError **error); /* AT+CPMS=? (Preferred SMS storage) response parser */ -gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply, - GArray **mem1, - GArray **mem2, - GArray **mem3); +gboolean mm_3gpp_parse_cpms_test_response (const gchar *reply, + GArray **mem1, + GArray **mem2, + GArray **mem3, + GError **error); /* AT+CPMS? (Current SMS storage) response parser */ gboolean mm_3gpp_parse_cpms_query_response (const gchar *reply, @@ -279,6 +285,7 @@ typedef enum { /*< underscore_name=mm_3gpp_cmer_ind >*/ gchar *mm_3gpp_build_cmer_set_request (MM3gppCmerMode mode, MM3gppCmerInd ind); gboolean mm_3gpp_parse_cmer_test_response (const gchar *reply, + gpointer log_object, MM3gppCmerMode *supported_modes, MM3gppCmerInd *supported_inds, GError **error); @@ -395,6 +402,7 @@ gboolean mm_3gpp_parse_cesq_response (const gchar *response, GError **error); gboolean mm_3gpp_cesq_response_to_signal_info (const gchar *response, + gpointer log_object, MMSignal **out_gsm, MMSignal **out_umts, MMSignal **out_lte, @@ -408,6 +416,7 @@ gboolean mm_3gpp_parse_cemode_query_response (const gchar *r /* CCWA service query response parser */ gboolean mm_3gpp_parse_ccwa_service_query_response (const gchar *response, + gpointer log_object, gboolean *status, GError **error); @@ -420,7 +429,8 @@ const gchar *mm_3gpp_facility_to_acronym (MMModem3gppFacility facility) MMModemAccessTechnology mm_string_to_access_tech (const gchar *string); void mm_3gpp_normalize_operator (gchar **operator, - MMModemCharset cur_charset); + MMModemCharset cur_charset, + gpointer log_object); gboolean mm_3gpp_parse_operator_id (const gchar *operator_id, guint16 *mcc, @@ -433,18 +443,24 @@ MMBearerIpFamily mm_3gpp_get_ip_family_from_pdp_type (const gchar *pdp_type); char *mm_3gpp_parse_iccid (const char *raw_iccid, GError **error); -gboolean mm_3gpp_rscp_level_to_rscp (guint rscp_level, - gdouble *out_rscp); -gboolean mm_3gpp_rxlev_to_rssi (guint rxlev, - gdouble *out_rssi); -gboolean mm_3gpp_ecn0_level_to_ecio (guint ecn0_level, - gdouble *out_ecio); -gboolean mm_3gpp_rsrq_level_to_rsrq (guint rsrq_level, - gdouble *out_rsrq); -gboolean mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level, - gdouble *out_rsrp); -gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level, - gdouble *out_rssnr); +gboolean mm_3gpp_rscp_level_to_rscp (guint rscp_level, + gpointer log_object, + gdouble *out_rscp); +gboolean mm_3gpp_rxlev_to_rssi (guint rxlev, + gpointer log_object, + gdouble *out_rssi); +gboolean mm_3gpp_ecn0_level_to_ecio (guint ecn0_level, + gpointer log_object, + gdouble *out_ecio); +gboolean mm_3gpp_rsrq_level_to_rsrq (guint rsrq_level, + gpointer log_object, + gdouble *out_rsrq); +gboolean mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level, + gpointer log_object, + gdouble *out_rsrp); +gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level, + gpointer log_object, + gdouble *out_rssnr); GStrv mm_3gpp_parse_emergency_numbers (const char *raw, GError **error); diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c index 950af441..4e9f3008 100644 --- a/src/mm-plugin-manager.c +++ b/src/mm-plugin-manager.c @@ -28,16 +28,18 @@ #include "mm-plugin-manager.h" #include "mm-plugin.h" #include "mm-shared.h" -#include "mm-log.h" +#include "mm-utils.h" +#include "mm-log-object.h" #define SHARED_PREFIX "libmm-shared" #define PLUGIN_PREFIX "libmm-plugin" -static void initable_iface_init (GInitableIface *iface); +static void initable_iface_init (GInitableIface *iface); +static void log_object_iface_init (MMLogObjectInterface *iface); G_DEFINE_TYPE_EXTENDED (MMPluginManager, mm_plugin_manager, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_iface_init)) + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -61,6 +63,9 @@ struct _MMPluginManagerPrivate { /* List of ongoing device support checks */ GList *device_contexts; + + /* Full list of subsystems requested by the registered plugins */ + gchar **subsystems; }; /*****************************************************************************/ @@ -177,7 +182,7 @@ common_async_context_new (MMPluginManager *self, /* * Port context * - * This structure hold all the probing information related to a single port. + * This structure holds all the probing information related to a single port. */ struct _PortContext { /* Reference counting */ @@ -260,7 +265,8 @@ port_context_run_finish (MMPluginManager *self, static void port_context_complete (PortContext *port_context) { - GTask *task; + MMPluginManager *self; + GTask *task; /* If already completed, do nothing */ if (!port_context->task) @@ -271,8 +277,9 @@ port_context_complete (PortContext *port_context) port_context->task = NULL; /* Log about the time required to complete the checks */ - mm_dbg ("[plugin manager] task %s: finished in '%lf' seconds", - port_context->name, g_timer_elapsed (port_context->timer, NULL)); + self = g_task_get_source_object (task); + mm_obj_dbg (self, "task %s: finished in '%lf' seconds", + port_context->name, g_timer_elapsed (port_context->timer, NULL)); if (!port_context->best_plugin) g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Unsupported"); @@ -287,10 +294,13 @@ static void port_context_supported (PortContext *port_context, MMPlugin *plugin) { + MMPluginManager *self; + g_assert (plugin); + self = g_task_get_source_object (port_context->task); - mm_dbg ("[plugin manager] task %s: found best plugin for port (%s)", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: found best plugin for port (%s)", + port_context->name, mm_plugin_get_name (plugin)); /* Found a best plugin, store it to return it */ port_context->best_plugin = g_object_ref (plugin); @@ -309,7 +319,8 @@ static void port_context_set_suggestion (PortContext *port_context, MMPlugin *suggested_plugin) { - gboolean forbidden_icera; + MMPluginManager *self; + gboolean forbidden_icera; /* Plugin suggestions serve two different purposes here: * 1) Finish all the probes which were deferred until suggested. @@ -325,6 +336,9 @@ port_context_set_suggestion (PortContext *port_context, if (port_context->best_plugin || port_context->suggested_plugin) return; + /* There may not be a task at this point, so be gentle */ + self = port_context->task ? g_task_get_source_object (port_context->task) : NULL; + /* Complete tasks which were deferred until suggested */ if (port_context->defer_until_suggested) { /* Reset the defer until suggested flag; we consider this @@ -332,8 +346,8 @@ port_context_set_suggestion (PortContext *port_context, port_context->defer_until_suggested = FALSE; if (suggested_plugin) { - mm_dbg ("[plugin manager] task %s: deferred task completed, got suggested plugin (%s)", - port_context->name, mm_plugin_get_name (suggested_plugin)); + mm_obj_dbg (self, "task %s: deferred task completed, got suggested plugin (%s)", + port_context->name, mm_plugin_get_name (suggested_plugin)); /* Advance to the suggested plugin and re-check support there */ port_context->suggested_plugin = g_object_ref (suggested_plugin); port_context->current = g_list_find (port_context->current, port_context->suggested_plugin); @@ -343,8 +357,7 @@ port_context_set_suggestion (PortContext *port_context, return; } - mm_dbg ("[plugin manager] task %s: deferred task completed, no suggested plugin", - port_context->name); + mm_obj_dbg (self, "task %s: deferred task completed, no suggested plugin", port_context->name); port_context_complete (port_context); return; } @@ -354,7 +367,7 @@ port_context_set_suggestion (PortContext *port_context, return; /* The GENERIC plugin is NEVER suggested to others */ - if (g_str_equal (mm_plugin_get_name (suggested_plugin), MM_PLUGIN_GENERIC_NAME)) + if (mm_plugin_is_generic (suggested_plugin)) return; /* If the plugin has MM_PLUGIN_FORBIDDEN_ICERA set, we do *not* suggest @@ -372,8 +385,8 @@ port_context_set_suggestion (PortContext *port_context, * should run its probing independently, and we'll later decide * which result applies to the whole device. */ - mm_dbg ("[plugin manager] task %s: got suggested plugin (%s)", - port_context->name, mm_plugin_get_name (suggested_plugin)); + mm_obj_dbg (self, "task %s: got suggested plugin (%s)", + port_context->name, mm_plugin_get_name (suggested_plugin)); port_context->suggested_plugin = g_object_ref (suggested_plugin); } @@ -381,7 +394,10 @@ static void port_context_unsupported (PortContext *port_context, MMPlugin *plugin) { + MMPluginManager *self; + g_assert (plugin); + self = g_task_get_source_object (port_context->task); /* If there is no suggested plugin, go on to the next one */ if (!port_context->suggested_plugin) { @@ -396,8 +412,8 @@ port_context_unsupported (PortContext *port_context, * just cancel the port probing and avoid more tests. */ if (port_context->suggested_plugin == plugin) { - mm_dbg ("[plugin manager] task %s: ignoring port unsupported by physical modem's plugin", - port_context->name); + mm_obj_dbg (self, "task %s: ignoring port unsupported by physical modem's plugin", + port_context->name); port_context_complete (port_context); return; } @@ -412,14 +428,17 @@ port_context_unsupported (PortContext *port_context, static void port_context_defer (PortContext *port_context) { + MMPluginManager *self; + + self = g_task_get_source_object (port_context->task); + /* Try with the suggested one after being deferred */ if (port_context->suggested_plugin) { - mm_dbg ("[plugin manager] task %s: deferring support check (%s suggested)", - port_context->name, mm_plugin_get_name (MM_PLUGIN (port_context->suggested_plugin))); + mm_obj_dbg (self, "task %s: deferring support check (%s suggested)", + port_context->name, mm_plugin_get_name (MM_PLUGIN (port_context->suggested_plugin))); port_context->current = g_list_find (port_context->current, port_context->suggested_plugin); } else - mm_dbg ("[plugin manager] task %s: deferring support check", - port_context->name); + mm_obj_dbg (self, "task %s: deferring support check", port_context->name); /* Schedule checking support. * @@ -434,14 +453,17 @@ static void port_context_defer_until_suggested (PortContext *port_context, MMPlugin *plugin) { + MMPluginManager *self; + g_assert (plugin); + self = g_task_get_source_object (port_context->task); /* If we arrived here and we already have a plugin suggested, use it */ if (port_context->suggested_plugin) { /* We can finish this context */ if (port_context->suggested_plugin == plugin) { - mm_dbg ("[plugin manager] task %s: completed, got suggested plugin (%s)", - port_context->name, mm_plugin_get_name (port_context->suggested_plugin)); + mm_obj_dbg (self, "task %s: completed, got suggested plugin (%s)", + port_context->name, mm_plugin_get_name (port_context->suggested_plugin)); /* Store best plugin and end operation */ port_context->best_plugin = g_object_ref (port_context->suggested_plugin); port_context_complete (port_context); @@ -449,8 +471,8 @@ port_context_defer_until_suggested (PortContext *port_context, } /* Recheck support in deferred task */ - mm_dbg ("[plugin manager] task %s: re-checking support on deferred task, got suggested plugin (%s)", - port_context->name, mm_plugin_get_name (port_context->suggested_plugin)); + mm_obj_dbg (self, "task %s: re-checking support on deferred task, got suggested plugin (%s)", + port_context->name, mm_plugin_get_name (port_context->suggested_plugin)); port_context->current = g_list_find (port_context->current, port_context->suggested_plugin); port_context_next (port_context); return; @@ -459,8 +481,7 @@ port_context_defer_until_suggested (PortContext *port_context, /* We are deferred until a suggested plugin is given. If last supports task * of a given device is finished without finding a best plugin, this task * will get finished reporting unsupported. */ - mm_dbg ("[plugin manager] task %s: deferring support check until result suggested", - port_context->name); + mm_obj_dbg (self, "task %s: deferring support check until result suggested", port_context->name); port_context->defer_until_suggested = TRUE; } @@ -469,15 +490,18 @@ plugin_supports_port_ready (MMPlugin *plugin, GAsyncResult *res, PortContext *port_context) { + MMPluginManager *self; MMPluginSupportsResult support_result; GError *error = NULL; + self = g_task_get_source_object (port_context->task); + /* Get supports check results */ support_result = mm_plugin_supports_port_finish (plugin, res, &error); if (error) { g_assert_cmpuint (support_result, ==, MM_PLUGIN_SUPPORTS_PORT_UNKNOWN); - mm_warn ("[plugin manager] task %s: error when checking support with plugin '%s': '%s'", - port_context->name, mm_plugin_get_name (plugin), error->message); + mm_obj_warn (self, "task %s: error when checking support with plugin '%s': %s", + port_context->name, mm_plugin_get_name (plugin), error->message); g_error_free (error); } @@ -507,7 +531,10 @@ plugin_supports_port_ready (MMPlugin *plugin, static void port_context_next (PortContext *port_context) { - MMPlugin *plugin; + MMPluginManager *self; + MMPlugin *plugin; + + self = g_task_get_source_object (port_context->task); /* If we're cancelled, done */ if (g_cancellable_is_cancelled (port_context->cancellable)) { @@ -527,8 +554,8 @@ port_context_next (PortContext *port_context) * async method because we want to make sure the context is still valid * once the method finishes. */ plugin = MM_PLUGIN (port_context->current->data); - mm_dbg ("[plugin manager] task %s: checking with plugin '%s'", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: checking with plugin '%s'", + port_context->name, mm_plugin_get_name (plugin)); mm_plugin_supports_port (plugin, port_context->device, port_context->port, @@ -540,6 +567,8 @@ port_context_next (PortContext *port_context) static gboolean port_context_cancel (PortContext *port_context) { + MMPluginManager *self; + /* Port context cancellation, which only makes sense if the context is * actually being run, so just exit if it isn't. */ if (!port_context->task) @@ -549,8 +578,8 @@ port_context_cancel (PortContext *port_context) if (g_cancellable_is_cancelled (port_context->cancellable)) return FALSE; - mm_dbg ("[plugin manager) task %s: cancellation requested", - port_context->name); + self = g_task_get_source_object (port_context->task); + mm_obj_dbg (self, "task %s: cancellation requested", port_context->name); /* Make sure we hold a port context reference while cancelling, as the * cancellable signal handlers may end up unref-ing our last reference @@ -600,8 +629,8 @@ port_context_run (MMPluginManager *self, port_context->suggested_plugin = g_object_ref (suggested); port_context->current = g_list_find (port_context->current, port_context->suggested_plugin); if (!port_context->current) - mm_warn ("[plugin manager] task %s: suggested plugin (%s) not among the ones to test", - port_context->name, mm_plugin_get_name (suggested)); + mm_obj_warn (self, "task %s: suggested plugin (%s) not among the ones to test", + port_context->name, mm_plugin_get_name (suggested)); } /* Log the list of plugins found and specify which are the ones that are going @@ -610,31 +639,31 @@ port_context_run (MMPluginManager *self, gboolean suggested_found = FALSE; GList *l; - mm_dbg ("[plugin manager] task %s: found '%u' plugins to try", - port_context->name, g_list_length (port_context->plugins)); + mm_obj_dbg (self, "task %s: found '%u' plugins to try", + port_context->name, g_list_length (port_context->plugins)); for (l = port_context->plugins; l; l = g_list_next (l)) { MMPlugin *plugin; plugin = MM_PLUGIN (l->data); if (suggested_found) { - mm_dbg ("[plugin manager] task %s: may try with plugin '%s'", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: may try with plugin '%s'", + port_context->name, mm_plugin_get_name (plugin)); continue; } if (suggested && l == port_context->current) { suggested_found = TRUE; - mm_dbg ("[plugin manager] task %s: will try with plugin '%s' (suggested)", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: will try with plugin '%s' (suggested)", + port_context->name, mm_plugin_get_name (plugin)); continue; } if (suggested && !suggested_found) { - mm_dbg ("[plugin manager] task %s: won't try with plugin '%s' (skipped)", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: won't try with plugin '%s' (skipped)", + port_context->name, mm_plugin_get_name (plugin)); continue; } - mm_dbg ("[plugin manager] task %s: will try with plugin '%s'", - port_context->name, mm_plugin_get_name (plugin)); + mm_obj_dbg (self, "task %s: will try with plugin '%s'", + port_context->name, mm_plugin_get_name (plugin)); } } @@ -647,7 +676,7 @@ port_context_run (MMPluginManager *self, * best plugin found for the port. */ port_context->task = g_task_new (self, port_context->cancellable, callback, user_data); - mm_dbg ("[plugin manager) task %s: started", port_context->name); + mm_obj_dbg (self, "task %s: started", port_context->name); /* Go probe with the first plugin */ port_context_next (port_context); @@ -710,7 +739,7 @@ struct _DeviceContext { /* The operation task */ GTask *task; - /* Internal ancellable */ + /* Internal cancellable */ GCancellable *cancellable; /* Timer tracking how much time is required for the device support check */ @@ -828,22 +857,25 @@ device_context_run_finish (MMPluginManager *self, static void device_context_complete (DeviceContext *device_context) { - GTask *task; + MMPluginManager *self; + GTask *task; + + self = g_task_get_source_object (device_context->task); /* If the context is completed before the 2500ms minimum probing time, we need to wait * until that happens, so that we give enough time to udev/hotplug to report the * new port additions. */ if (device_context->min_probing_time_id) { - mm_dbg ("[plugin manager] task %s: all port probings completed, but not reached min probing time yet", - device_context->name); + mm_obj_dbg (self, "task %s: all port probings completed, but not reached min probing time yet", + device_context->name); return; } /* If the context is completed less than 1500ms before the last port was exposed, * wait some more. */ if (device_context->extra_probing_time_id) { - mm_dbg ("[plugin manager] task %s: all port probings completed, but not reached extra probing time yet", - device_context->name); + mm_obj_dbg (self, "task %s: all port probings completed, but not reached extra probing time yet", + device_context->name); return; } @@ -853,8 +885,8 @@ device_context_complete (DeviceContext *device_context) device_context->task = NULL; /* Log about the time required to complete the checks */ - mm_dbg ("[plugin manager] task %s: finished in '%lf' seconds", - device_context->name, g_timer_elapsed (device_context->timer, NULL)); + mm_obj_dbg (self, "task %s: finished in '%lf' seconds", + device_context->name, g_timer_elapsed (device_context->timer, NULL)); /* Remove signal handlers */ if (device_context->grabbed_id) { @@ -913,20 +945,24 @@ device_context_set_best_plugin (DeviceContext *device_context, PortContext *port_context, MMPlugin *best_plugin) { + MMPluginManager *self; + + self = g_task_get_source_object (device_context->task); + if (!best_plugin) { /* If the port appeared after an already probed port, which decided that * the Generic plugin was the best one (which is by default not initially * suggested), we'll end up arriving here. Don't ignore it, it may well * be a wwan port that we do need to grab. */ if (device_context->best_plugin) { - mm_dbg ("[plugin manager] task %s: assuming port can be handled by the '%s' plugin", - port_context->name, mm_plugin_get_name (device_context->best_plugin)); + mm_obj_dbg (self, "task %s: assuming port can be handled by the '%s' plugin", + port_context->name, mm_plugin_get_name (device_context->best_plugin)); return; } /* Unsupported error, this is generic when we cannot find a plugin */ - mm_dbg ("[plugin manager] task %s: not supported by any plugin" , - port_context->name); + mm_obj_dbg (self, "task %s: not supported by any plugin" , + port_context->name); /* Tell the device to ignore this port */ mm_device_ignore_port (device_context->device, port_context->port); @@ -942,12 +978,12 @@ device_context_set_best_plugin (DeviceContext *device_context, * one and now we're reporting a more specific one, use the new one. */ if (!device_context->best_plugin || - (g_str_equal (mm_plugin_get_name (device_context->best_plugin), MM_PLUGIN_GENERIC_NAME) && + (mm_plugin_is_generic (device_context->best_plugin) && device_context->best_plugin != best_plugin)) { /* Only log best plugin if it's not the generic one */ - if (!g_str_equal (mm_plugin_get_name (best_plugin), MM_PLUGIN_GENERIC_NAME)) - mm_dbg ("[plugin manager] task %s: found best plugin: %s", - port_context->name, mm_plugin_get_name (best_plugin)); + if (!mm_plugin_is_generic (best_plugin)) + mm_obj_dbg (self, "task %s: found best plugin: %s", + port_context->name, mm_plugin_get_name (best_plugin)); /* Store and suggest this plugin also to other port probes */ device_context->best_plugin = g_object_ref (best_plugin); device_context_suggest_plugin (device_context, port_context, best_plugin); @@ -979,19 +1015,19 @@ device_context_set_best_plugin (DeviceContext *device_context, g_assert (new_allowed_icera == FALSE || new_forbidden_icera == FALSE); if (previous_allowed_icera && new_forbidden_icera) - mm_warn ("[plugin manager] task %s: will use plugin '%s' instead of '%s', modem is icera-capable", + mm_obj_warn (self, "task %s: will use plugin '%s' instead of '%s', modem is icera-capable", port_context->name, mm_plugin_get_name (device_context->best_plugin), mm_plugin_get_name (best_plugin)); else if (new_allowed_icera && previous_forbidden_icera) { - mm_warn ("[plugin manager] task %s: overriding previously selected device plugin '%s' with '%s', modem is icera-capable", + mm_obj_warn (self, "task %s: overriding previously selected device plugin '%s' with '%s', modem is icera-capable", port_context->name, mm_plugin_get_name (device_context->best_plugin), mm_plugin_get_name (best_plugin)); g_object_unref (device_context->best_plugin); device_context->best_plugin = g_object_ref (best_plugin); } else - mm_warn ("[plugin manager] task %s: plugin mismatch error (device reports '%s', port reports '%s')", + mm_obj_warn (self, "task %s: plugin mismatch error (device reports '%s', port reports '%s')", port_context->name, mm_plugin_get_name (device_context->best_plugin), mm_plugin_get_name (best_plugin)); @@ -999,21 +1035,24 @@ device_context_set_best_plugin (DeviceContext *device_context, } /* Device plugin equal to best plugin */ - mm_dbg ("[plugin manager] task %s: best plugin matches device reported one: %s", - port_context->name, mm_plugin_get_name (best_plugin)); + mm_obj_dbg (self, "task %s: best plugin matches device reported one: %s", + port_context->name, mm_plugin_get_name (best_plugin)); } static void device_context_continue (DeviceContext *device_context) { - GList *l; - GString *s = NULL; - guint n = 0; - guint n_active = 0; + MMPluginManager *self; + GList *l; + GString *s = NULL; + guint n = 0; + guint n_active = 0; + + self = g_task_get_source_object (device_context->task); /* If there are no running port contexts around, we're free to finish */ if (!device_context->port_contexts) { - mm_dbg ("[plugin manager] task %s: no more ports to probe", device_context->name); + mm_obj_dbg (self, "task %s: no more ports to probe", device_context->name); device_context_complete (device_context); return; } @@ -1038,12 +1077,12 @@ device_context_continue (DeviceContext *device_context) } g_assert (n > 0 && s); - mm_dbg ("[plugin Manager] task %s: still %u running probes (%u active): %s", - device_context->name, n, n_active, s->str); + mm_obj_dbg (self, "task %s: still %u running probes (%u active): %s", + device_context->name, n, n_active, s->str); g_string_free (s, TRUE); if (n_active == 0) { - mm_dbg ("[plugin manager] task %s: no active tasks to probe", device_context->name); + mm_obj_dbg (self, "task %s: no active tasks to probe", device_context->name); device_context_suggest_plugin (device_context, NULL, NULL); } } @@ -1064,7 +1103,7 @@ port_context_run_ready (MMPluginManager *self, /* This error is not critical */ device_context_set_best_plugin (common->device_context, common->port_context, NULL); } else - mm_warn ("[plugin manager] task %s: failed: %s", common->port_context->name, error->message); + mm_obj_warn (self, "task %s: failed: %s", common->port_context->name, error->message); g_error_free (error); } else { /* Set the plugin as the best one in the device context */ @@ -1090,9 +1129,12 @@ port_context_run_ready (MMPluginManager *self, static gboolean device_context_min_probing_time_elapsed (DeviceContext *device_context) { + MMPluginManager *self; + device_context->min_probing_time_id = 0; - mm_dbg ("[plugin manager] task %s: min probing time elapsed", device_context->name); + self = g_task_get_source_object (device_context->task); + mm_obj_dbg (self, "task %s: min probing time elapsed", device_context->name); /* Wakeup the device context logic */ device_context_continue (device_context); @@ -1102,9 +1144,12 @@ device_context_min_probing_time_elapsed (DeviceContext *device_context) static gboolean device_context_extra_probing_time_elapsed (DeviceContext *device_context) { + MMPluginManager *self; + device_context->extra_probing_time_id = 0; - mm_dbg ("[plugin manager] task %s: extra probing time elapsed", device_context->name); + self = g_task_get_source_object (device_context->task); + mm_obj_dbg (self, "task %s: extra probing time elapsed", device_context->name); /* Wakeup the device context logic */ device_context_continue (device_context); @@ -1129,10 +1174,8 @@ device_context_run_port_context (DeviceContext *device_context, /* If we got one already set in the device context, it will be the first one, * unless it is the generic plugin */ - if (device_context->best_plugin && - !g_str_equal (mm_plugin_get_name (device_context->best_plugin), MM_PLUGIN_GENERIC_NAME)) { + if (device_context->best_plugin && !mm_plugin_is_generic (device_context->best_plugin)) suggested = device_context->best_plugin; - } port_context_run (self, port_context, @@ -1156,7 +1199,7 @@ device_context_min_wait_time_elapsed (DeviceContext *device_context) self = device_context->self; device_context->min_wait_time_id = 0; - mm_dbg ("[plugin manager] task %s: min wait time elapsed", device_context->name); + mm_obj_dbg (self, "task %s: min wait time elapsed", device_context->name); /* Move list of port contexts out of the wait list */ g_assert (!device_context->port_contexts); @@ -1185,10 +1228,12 @@ static void device_context_port_released (DeviceContext *device_context, MMKernelDevice *port) { - PortContext *port_context; + MMPluginManager *self; + PortContext *port_context; - mm_dbg ("[plugin manager] task %s: port released: %s", - device_context->name, mm_kernel_device_get_name (port)); + self = g_task_get_source_object (device_context->task); + mm_obj_dbg (self, "task %s: port released: %s", + device_context->name, mm_kernel_device_get_name (port)); /* Check if there's a waiting port context */ port_context = device_context_peek_waiting_port_context (device_context, port); @@ -1209,8 +1254,8 @@ device_context_port_released (DeviceContext *device_context, /* This is not something worth warning. If the probing task has already * been finished, it will already be removed from the list */ - mm_dbg ("[plugin manager] task %s: port wasn't found: %s", - device_context->name, mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "task %s: port wasn't found: %s", + device_context->name, mm_kernel_device_get_name (port)); } static void @@ -1223,13 +1268,13 @@ device_context_port_grabbed (DeviceContext *device_context, /* Recover plugin manager */ self = MM_PLUGIN_MANAGER (device_context->self); - mm_dbg ("[plugin manager] task %s: port grabbed: %s", - device_context->name, mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "task %s: port grabbed: %s", + device_context->name, mm_kernel_device_get_name (port)); /* Ignore if for any reason we still have it in the running list */ port_context = device_context_peek_running_port_context (device_context, port); if (port_context) { - mm_warn ("[plugin manager] task %s: port context already being processed", + mm_obj_warn (self, "task %s: port context already being processed", device_context->name); return; } @@ -1237,7 +1282,7 @@ device_context_port_grabbed (DeviceContext *device_context, /* Ignore if for any reason we still have it in the waiting list */ port_context = device_context_peek_waiting_port_context (device_context, port); if (port_context) { - mm_warn ("[plugin manager] task %s: port context already scheduled", + mm_obj_warn (self, "task %s: port context already scheduled", device_context->name); return; } @@ -1255,13 +1300,13 @@ device_context_port_grabbed (DeviceContext *device_context, device_context->device, port); - mm_dbg ("[plugin manager] task %s: new support task for port", - port_context->name); + mm_obj_dbg (self, "task %s: new support task for port", + port_context->name); /* Îf still waiting the min wait time, store it in the waiting list */ if (device_context->min_wait_time_id) { - mm_dbg ("[plugin manager) task %s: deferred until min wait time elapsed", - port_context->name); + mm_obj_dbg (self, "task %s: deferred until min wait time elapsed", + port_context->name); /* Store the port reference in the list within the device */ device_context->wait_port_contexts = g_list_prepend (device_context->wait_port_contexts, port_context); return; @@ -1278,12 +1323,14 @@ device_context_port_grabbed (DeviceContext *device_context, static gboolean device_context_cancel (DeviceContext *device_context) { + MMPluginManager *self; + /* If cancelled already, do nothing */ if (g_cancellable_is_cancelled (device_context->cancellable)) return FALSE; - mm_dbg ("[plugin manager) task %s: cancellation requested", - device_context->name); + self = g_task_get_source_object (device_context->task); + mm_obj_dbg (self, "task %s: cancellation requested", device_context->name); /* The device context is cancelled now */ g_cancellable_cancel (device_context->cancellable); @@ -1502,7 +1549,7 @@ mm_plugin_manager_device_support_check (MMPluginManager *self, * Note that we handle cancellations ourselves, as we don't want the caller * to be required to keep track of a GCancellable for each of these tasks. */ - task = g_task_new (G_OBJECT (self), NULL, callback, user_data); + task = g_task_new (self, NULL, callback, user_data); /* Fail if there is already a task for the same device */ device_context = plugin_manager_peek_device_context (self, device); @@ -1520,8 +1567,8 @@ mm_plugin_manager_device_support_check (MMPluginManager *self, /* Track the device context in the list within the plugin manager. */ self->priv->device_contexts = g_list_prepend (self->priv->device_contexts, device_context); - mm_dbg ("[plugin manager] task %s: new support task for device: %s", - device_context->name, mm_device_get_uid (device_context->device)); + mm_obj_dbg (self, "task %s: new support task for device: %s", + device_context->name, mm_device_get_uid (device_context->device)); /* Run device context */ device_context_run (self, @@ -1558,6 +1605,14 @@ mm_plugin_manager_peek_plugin (MMPluginManager *self, /*****************************************************************************/ +const gchar ** +mm_plugin_manager_get_subsystems (MMPluginManager *self) +{ + return (const gchar **) self->priv->subsystems; +} + +/*****************************************************************************/ + static void register_plugin_whitelist_tags (MMPluginManager *self, MMPlugin *plugin) @@ -1573,6 +1628,21 @@ register_plugin_whitelist_tags (MMPluginManager *self, mm_filter_register_plugin_whitelist_tag (self->priv->filter, tags[i]); } +static void +register_plugin_whitelist_vendor_ids (MMPluginManager *self, + MMPlugin *plugin) +{ + const guint16 *vendor_ids; + guint i; + + if (!mm_filter_check_rule_enabled (self->priv->filter, MM_FILTER_RULE_PLUGIN_WHITELIST)) + return; + + vendor_ids = mm_plugin_get_allowed_vendor_ids (plugin); + for (i = 0; vendor_ids && vendor_ids[i]; i++) + mm_filter_register_plugin_whitelist_vendor_id (self->priv->filter, vendor_ids[i]); +} + static void register_plugin_whitelist_product_ids (MMPluginManager *self, MMPlugin *plugin) @@ -1589,57 +1659,58 @@ register_plugin_whitelist_product_ids (MMPluginManager *self, } static MMPlugin * -load_plugin (const gchar *path) +load_plugin (MMPluginManager *self, + const gchar *path) { - MMPlugin *plugin = NULL; - GModule *module; - MMPluginCreateFunc plugin_create_func; - gint *major_plugin_version; - gint *minor_plugin_version; - gchar *path_display; + MMPlugin *plugin = NULL; + GModule *module; + MMPluginCreateFunc plugin_create_func; + gint *major_plugin_version; + gint *minor_plugin_version; + gchar *path_display; /* Get printable UTF-8 string of the path */ path_display = g_filename_display_name (path); module = g_module_open (path, 0); if (!module) { - mm_warn ("[plugin manager] could not load plugin '%s': %s", path_display, g_module_error ()); + mm_obj_warn (self, "could not load plugin '%s': %s", path_display, g_module_error ()); goto out; } if (!g_module_symbol (module, "mm_plugin_major_version", (gpointer *) &major_plugin_version)) { - mm_warn ("[plugin manager] could not load plugin '%s': Missing major version info", path_display); + mm_obj_warn (self, "could not load plugin '%s': Missing major version info", path_display); goto out; } if (*major_plugin_version != MM_PLUGIN_MAJOR_VERSION) { - mm_warn ("[plugin manager] could not load plugin '%s': Plugin major version %d, %d is required", + mm_obj_warn (self, "could not load plugin '%s': Plugin major version %d, %d is required", path_display, *major_plugin_version, MM_PLUGIN_MAJOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_plugin_minor_version", (gpointer *) &minor_plugin_version)) { - mm_warn ("[plugin manager] could not load plugin '%s': Missing minor version info", path_display); + mm_obj_warn (self, "could not load plugin '%s': Missing minor version info", path_display); goto out; } if (*minor_plugin_version != MM_PLUGIN_MINOR_VERSION) { - mm_warn ("[plugin manager] could not load plugin '%s': Plugin minor version %d, %d is required", + mm_obj_warn (self, "could not load plugin '%s': Plugin minor version %d, %d is required", path_display, *minor_plugin_version, MM_PLUGIN_MINOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_plugin_create", (gpointer *) &plugin_create_func)) { - mm_warn ("[plugin manager] could not load plugin '%s': %s", path_display, g_module_error ()); + mm_obj_warn (self, "could not load plugin '%s': %s", path_display, g_module_error ()); goto out; } plugin = (*plugin_create_func) (); if (plugin) { - mm_dbg ("[plugin manager] loaded plugin '%s' from '%s'", mm_plugin_get_name (plugin), path_display); + mm_obj_dbg (self, "loaded plugin '%s' from '%s'", mm_plugin_get_name (plugin), path_display); g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module); } else - mm_warn ("[plugin manager] could not load plugin '%s': initialization failed", path_display); + mm_obj_warn (self, "could not load plugin '%s': initialization failed", path_display); out: if (module && !plugin) @@ -1651,7 +1722,8 @@ load_plugin (const gchar *path) } static void -load_shared (const gchar *path) +load_shared (MMPluginManager *self, + const gchar *path) { GModule *module; gchar *path_display; @@ -1664,38 +1736,38 @@ load_shared (const gchar *path) module = g_module_open (path, 0); if (!module) { - mm_warn ("[plugin manager] could not load shared '%s': %s", path_display, g_module_error ()); + mm_obj_warn (self, "could not load shared '%s': %s", path_display, g_module_error ()); goto out; } if (!g_module_symbol (module, "mm_shared_major_version", (gpointer *) &major_shared_version)) { - mm_warn ("[plugin manager] could not load shared '%s': Missing major version info", path_display); + mm_obj_warn (self, "could not load shared '%s': Missing major version info", path_display); goto out; } if (*major_shared_version != MM_SHARED_MAJOR_VERSION) { - mm_warn ("[plugin manager] could not load shared '%s': Shared major version %d, %d is required", - path_display, *major_shared_version, MM_SHARED_MAJOR_VERSION); + mm_obj_warn (self, "could not load shared '%s': Shared major version %d, %d is required", + path_display, *major_shared_version, MM_SHARED_MAJOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_shared_minor_version", (gpointer *) &minor_shared_version)) { - mm_warn ("[plugin manager] could not load shared '%s': Missing minor version info", path_display); + mm_obj_warn (self, "could not load shared '%s': Missing minor version info", path_display); goto out; } if (*minor_shared_version != MM_SHARED_MINOR_VERSION) { - mm_warn ("[plugin manager] could not load shared '%s': Shared minor version %d, %d is required", - path_display, *minor_shared_version, MM_SHARED_MINOR_VERSION); + mm_obj_warn (self, "could not load shared '%s': Shared minor version %d, %d is required", + path_display, *minor_shared_version, MM_SHARED_MINOR_VERSION); goto out; } if (!g_module_symbol (module, "mm_shared_name", (gpointer *) &shared_name)) { - mm_warn ("[plugin manager] could not load shared '%s': Missing name", path_display); + mm_obj_warn (self, "could not load shared '%s': Missing name", path_display); goto out; } - mm_dbg ("[plugin manager] loaded shared '%s' utils from '%s'", *shared_name, path_display); + mm_obj_dbg (self, "loaded shared '%s' utils from '%s'", *shared_name, path_display); out: if (module && !(*shared_name)) @@ -1705,15 +1777,17 @@ load_shared (const gchar *path) } static gboolean -load_plugins (MMPluginManager *self, - GError **error) +load_plugins (MMPluginManager *self, + GError **error) { - GDir *dir = NULL; - const gchar *fname; - gchar *plugindir_display = NULL; - GList *shared_paths = NULL; - GList *plugin_paths = NULL; - GList *l; + GDir *dir = NULL; + const gchar *fname; + GList *shared_paths = NULL; + GList *plugin_paths = NULL; + GList *l; + GPtrArray *subsystems = NULL; + g_autofree gchar *subsystems_str = NULL; + g_autofree gchar *plugindir_display = NULL; if (!g_module_supported ()) { g_set_error (error, @@ -1726,7 +1800,7 @@ load_plugins (MMPluginManager *self, /* Get printable UTF-8 string of the path */ plugindir_display = g_filename_display_name (self->priv->plugin_dir); - mm_dbg ("[plugin manager] looking for plugins in '%s'", plugindir_display); + mm_obj_dbg (self, "looking for plugins in '%s'", plugindir_display); dir = g_dir_open (self->priv->plugin_dir, 0, NULL); if (!dir) { g_set_error (error, @@ -1748,31 +1822,53 @@ load_plugins (MMPluginManager *self, /* Load all shared utils */ for (l = shared_paths; l; l = g_list_next (l)) - load_shared ((const gchar *)(l->data)); + load_shared (self, (const gchar *)(l->data)); /* Load all plugins */ + subsystems = g_ptr_array_new (); for (l = plugin_paths; l; l = g_list_next (l)) { - MMPlugin *plugin; + MMPlugin *plugin; + const gchar **plugin_subsystems; + guint i; - plugin = load_plugin ((const gchar *)(l->data)); + plugin = load_plugin (self, (const gchar *)(l->data)); if (!plugin) continue; - if (g_str_equal (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME)) - /* Generic plugin */ + /* Ignore plugins that don't specify subsystems */ + plugin_subsystems = mm_plugin_get_allowed_subsystems (plugin); + if (!plugin_subsystems) { + mm_obj_warn (self, "plugin '%s' doesn't specify allowed subsystems: ignored", + mm_plugin_get_name (plugin)); + continue; + } + + /* Process generic plugin */ + if (mm_plugin_is_generic (plugin)) { + if (self->priv->generic) { + mm_obj_warn (self, "plugin '%s' is generic and another one is already registered: ignored", + mm_plugin_get_name (plugin)); + continue; + } self->priv->generic = plugin; - else - /* Vendor specific plugin */ + } else self->priv->plugins = g_list_append (self->priv->plugins, plugin); + /* Track required subsystems, avoiding duplicates in the list */ + for (i = 0; plugin_subsystems[i]; i++) { + if (!g_ptr_array_find_with_equal_func (subsystems, plugin_subsystems[i], g_str_equal, NULL)) + g_ptr_array_add (subsystems, g_strdup (plugin_subsystems[i])); + } + /* Register plugin whitelist rules in filter, if any */ - register_plugin_whitelist_tags (self, plugin); + register_plugin_whitelist_tags (self, plugin); + register_plugin_whitelist_vendor_ids (self, plugin); register_plugin_whitelist_product_ids (self, plugin); } /* Check the generic plugin once all looped */ if (!self->priv->generic) - mm_warn ("[plugin manager] generic plugin not loaded"); + mm_obj_dbg (self, "generic plugin not loaded"); /* Treat as error if we don't find any plugin */ if (!self->priv->plugins && !self->priv->generic) { @@ -1784,20 +1880,43 @@ load_plugins (MMPluginManager *self, goto out; } - mm_dbg ("[plugin manager] successfully loaded %u plugins", - g_list_length (self->priv->plugins) + !!self->priv->generic); + /* Validate required subsystems */ + if (!subsystems->len) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_NO_PLUGINS, + "empty list of subsystems required by plugins"); + goto out; + } + /* Add trailing NULL and store as GStrv */ + g_ptr_array_add (subsystems, NULL); + self->priv->subsystems = (gchar **) g_ptr_array_free (subsystems, FALSE); + subsystems_str = g_strjoinv (", ", self->priv->subsystems); + + mm_obj_dbg (self, "successfully loaded %u plugins registering %u subsystems: %s", + g_list_length (self->priv->plugins) + !!self->priv->generic, + g_strv_length (self->priv->subsystems), subsystems_str); out: g_list_free_full (shared_paths, g_free); g_list_free_full (plugin_paths, g_free); if (dir) g_dir_close (dir); - g_free (plugindir_display); /* Return TRUE if at least one plugin found */ return (self->priv->plugins || self->priv->generic); } +/*****************************************************************************/ + +static gchar * +log_object_build_id (MMLogObject *_self) +{ + return g_strdup ("plugin-manager"); +} + +/*****************************************************************************/ + MMPluginManager * mm_plugin_manager_new (const gchar *plugin_dir, MMFilter *filter, @@ -1812,12 +1931,12 @@ mm_plugin_manager_new (const gchar *plugin_dir, } static void -mm_plugin_manager_init (MMPluginManager *manager) +mm_plugin_manager_init (MMPluginManager *self) { /* Initialize opaque pointer to private data */ - manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - MM_TYPE_PLUGIN_MANAGER, - MMPluginManagerPrivate); + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + MM_TYPE_PLUGIN_MANAGER, + MMPluginManagerPrivate); } static void @@ -1877,17 +1996,11 @@ dispose (GObject *object) { MMPluginManager *self = MM_PLUGIN_MANAGER (object); - /* Cleanup list of plugins */ - if (self->priv->plugins) { - g_list_free_full (self->priv->plugins, g_object_unref); - self->priv->plugins = NULL; - } + g_list_free_full (g_steal_pointer (&self->priv->plugins), g_object_unref); g_clear_object (&self->priv->generic); - - g_free (self->priv->plugin_dir); - self->priv->plugin_dir = NULL; - + g_clear_pointer (&self->priv->plugin_dir, g_free); g_clear_object (&self->priv->filter); + g_clear_pointer (&self->priv->subsystems, g_strfreev); G_OBJECT_CLASS (mm_plugin_manager_parent_class)->dispose (object); } @@ -1898,6 +2011,12 @@ initable_iface_init (GInitableIface *iface) iface->init = initable_init; } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_plugin_manager_class_init (MMPluginManagerClass *manager_class) { diff --git a/src/mm-plugin-manager.h b/src/mm-plugin-manager.h index 6a0f47eb..79e7c1a1 100644 --- a/src/mm-plugin-manager.h +++ b/src/mm-plugin-manager.h @@ -48,7 +48,9 @@ struct _MMPluginManagerClass { GObjectClass parent; }; -GType mm_plugin_manager_get_type (void); +GType mm_plugin_manager_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPluginManager, g_object_unref) + MMPluginManager *mm_plugin_manager_new (const gchar *plugindir, MMFilter *filter, GError **error); @@ -63,5 +65,6 @@ MMPlugin * mm_plugin_manager_device_support_check_finish (MMPluginManager GError **error); MMPlugin *mm_plugin_manager_peek_plugin (MMPluginManager *self, const gchar *plugin_name); +const gchar **mm_plugin_manager_get_subsystems (MMPluginManager *self); #endif /* MM_PLUGIN_MANAGER_H */ diff --git a/src/mm-plugin.c b/src/mm-plugin.c index 4407ecec..820f570e 100644 --- a/src/mm-plugin.c +++ b/src/mm-plugin.c @@ -34,7 +34,7 @@ #include "mm-port-serial-qcdm.h" #include "mm-serial-parsers.h" #include "mm-private-boxed-types.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-daemon-enums-types.h" #if defined WITH_QMI @@ -44,7 +44,10 @@ # include "mm-broadband-modem-mbim.h" #endif -G_DEFINE_TYPE (MMPlugin, mm_plugin, G_TYPE_OBJECT) +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMPlugin, mm_plugin, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) /* Virtual port corresponding to the embedded modem */ static const gchar *virtual_port[] = {"smd0", NULL}; @@ -61,8 +64,9 @@ static const gchar *virtual_port[] = {"smd0", NULL}; struct _MMPluginPrivate { - gchar *name; + gchar *name; GHashTable *tasks; + gboolean is_generic; /* Pre-probing filters */ gchar **subsystems; @@ -104,6 +108,7 @@ struct _MMPluginPrivate { enum { PROP_0, PROP_NAME, + PROP_IS_GENERIC, PROP_ALLOWED_SUBSYSTEMS, PROP_ALLOWED_DRIVERS, PROP_FORBIDDEN_DRIVERS, @@ -141,18 +146,36 @@ mm_plugin_get_name (MMPlugin *self) return self->priv->name; } +const gchar ** +mm_plugin_get_allowed_subsystems (MMPlugin *self) +{ + return (const gchar **) self->priv->subsystems; +} + const gchar ** mm_plugin_get_allowed_udev_tags (MMPlugin *self) { return (const gchar **) self->priv->udev_tags; } +const guint16 * +mm_plugin_get_allowed_vendor_ids (MMPlugin *self) +{ + return self->priv->vendor_ids; +} + const mm_uint16_pair * mm_plugin_get_allowed_product_ids (MMPlugin *self) { return self->priv->product_ids; } +gboolean +mm_plugin_is_generic (MMPlugin *self) +{ + return self->priv->is_generic; +} + /*****************************************************************************/ static gboolean @@ -200,10 +223,6 @@ apply_subsystem_filter (MMPlugin *self, for (i = 0; self->priv->subsystems[i]; i++) { if (g_str_equal (subsys, self->priv->subsystems[i])) break; - /* New kernels may report as 'usbmisc' the subsystem */ - else if (g_str_equal (self->priv->subsystems[i], "usb") && - g_str_equal (subsys, "usbmisc")) - break; } /* If we didn't match any subsystem: unsupported */ @@ -234,9 +253,7 @@ apply_pre_probing_filters (MMPlugin *self, /* The plugin may specify that only some subsystems are supported. If that * is the case, filter by subsystem */ if (apply_subsystem_filter (self, port)) { - mm_dbg ("(%s) [%s] filtered by subsystem", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by subsystem", mm_kernel_device_get_name (port)); return TRUE; } @@ -265,9 +282,7 @@ apply_pre_probing_filters (MMPlugin *self, /* If error retrieving driver: unsupported */ if (!drivers) { - mm_dbg ("(%s) [%s] filtered as couldn't retrieve drivers", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered as couldn't retrieve drivers", mm_kernel_device_get_name (port)); return TRUE; } @@ -286,9 +301,7 @@ apply_pre_probing_filters (MMPlugin *self, /* If we didn't match any driver: unsupported */ if (!found) { - mm_dbg ("(%s) [%s] filtered by drivers", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by drivers", mm_kernel_device_get_name (port)); return TRUE; } } @@ -301,9 +314,7 @@ apply_pre_probing_filters (MMPlugin *self, for (j = 0; drivers[j]; j++) { /* If we match a forbidden driver: unsupported */ if (g_str_equal (drivers[j], self->priv->forbidden_drivers[i])) { - mm_dbg ("(%s) [%s] filtered by forbidden drivers", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by forbidden drivers", mm_kernel_device_get_name (port)); return TRUE; } } @@ -317,9 +328,7 @@ apply_pre_probing_filters (MMPlugin *self, for (j = 0; drivers[j]; j++) { /* If we match the QMI driver: unsupported */ if (g_str_equal (drivers[j], "qmi_wwan")) { - mm_dbg ("(%s) [%s] filtered by implicit QMI driver", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by implicit QMI driver", mm_kernel_device_get_name (port)); return TRUE; } } @@ -332,9 +341,7 @@ apply_pre_probing_filters (MMPlugin *self, for (j = 0; drivers[j]; j++) { /* If we match the MBIM driver: unsupported */ if (g_str_equal (drivers[j], "cdc_mbim")) { - mm_dbg ("(%s) [%s] filtered by implicit MBIM driver", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by implicit MBIM driver", mm_kernel_device_get_name (port)); return TRUE; } } @@ -398,9 +405,7 @@ apply_pre_probing_filters (MMPlugin *self, !self->priv->forbidden_product_strings) || g_str_equal (mm_kernel_device_get_subsystem (port), "net") || g_str_has_prefix (mm_kernel_device_get_name (port), "cdc-wdm"))) { - mm_dbg ("(%s) [%s] filtered by vendor/product IDs", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by vendor/product IDs", mm_kernel_device_get_name (port)); return TRUE; } @@ -410,9 +415,7 @@ apply_pre_probing_filters (MMPlugin *self, for (i = 0; self->priv->forbidden_product_ids[i].l; i++) { if (vendor == self->priv->forbidden_product_ids[i].l && product == self->priv->forbidden_product_ids[i].r) { - mm_dbg ("(%s) [%s] filtered by forbidden vendor/product IDs", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by forbidden vendor/product IDs", mm_kernel_device_get_name (port)); return TRUE; } } @@ -451,9 +454,7 @@ apply_pre_probing_filters (MMPlugin *self, /* If we didn't match any udev tag: unsupported */ if (!self->priv->udev_tags[i]) { - mm_dbg ("(%s) [%s] filtered by udev tags", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "port %s filtered by udev tags", mm_kernel_device_get_name (port)); return TRUE; } } @@ -500,9 +501,7 @@ apply_post_probing_filters (MMPlugin *self, if (vendor_filtered) { if (!self->priv->product_strings) { - mm_dbg ("(%s) [%s] filtered by vendor strings", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered by vendor strings", mm_port_probe_get_port_name (probe)); return TRUE; } } else @@ -525,9 +524,7 @@ apply_post_probing_filters (MMPlugin *self, if (self->priv->product_strings) { /* If we didn't get any vendor or product: filtered */ if (!vendor || !product) { - mm_dbg ("(%s) [%s] filtered as no vendor/product strings given", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered as no vendor/product strings given", mm_port_probe_get_port_name (probe)); return TRUE; } else { @@ -548,9 +545,7 @@ apply_post_probing_filters (MMPlugin *self, /* If we didn't match any product: unsupported */ if (!self->priv->product_strings[i].l) { - mm_dbg ("(%s) [%s] filtered by vendor/product strings", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered by vendor/product strings", mm_port_probe_get_port_name (probe)); return TRUE; } } @@ -570,9 +565,7 @@ apply_post_probing_filters (MMPlugin *self, g_free (casefolded_product); if (found) { /* If we match a forbidden product: unsupported */ - mm_dbg ("(%s) [%s] filtered by forbidden vendor/product strings", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered by forbidden vendor/product strings", mm_port_probe_get_port_name (probe)); return TRUE; } } @@ -586,9 +579,7 @@ apply_post_probing_filters (MMPlugin *self, if (self->priv->allowed_icera && !mm_port_probe_is_icera (probe)) { /* Unsupported! */ - mm_dbg ("(%s) [%s] filtered as modem is not icera", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered as modem is not icera", mm_port_probe_get_port_name (probe)); return TRUE; } @@ -597,9 +588,7 @@ apply_post_probing_filters (MMPlugin *self, if (self->priv->forbidden_icera && mm_port_probe_is_icera (probe)) { /* Unsupported! */ - mm_dbg ("(%s) [%s] filtered as modem is icera", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered as modem is icera", mm_port_probe_get_port_name (probe)); return TRUE; } @@ -608,9 +597,7 @@ apply_post_probing_filters (MMPlugin *self, if (self->priv->allowed_xmm && !mm_port_probe_is_xmm (probe)) { /* Unsupported! */ - mm_dbg ("(%s) [%s] filtered as modem is not XMM", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered as modem is not XMM", mm_port_probe_get_port_name (probe)); return TRUE; } @@ -619,9 +606,7 @@ apply_post_probing_filters (MMPlugin *self, if (self->priv->forbidden_xmm && mm_port_probe_is_xmm (probe)) { /* Unsupported! */ - mm_dbg ("(%s) [%s] filtered as modem is XMM", - self->priv->name, - mm_port_probe_get_port_name (probe)); + mm_obj_dbg (self, "port %s filtered as modem is XMM", mm_port_probe_get_port_name (probe)); return TRUE; } @@ -780,33 +765,36 @@ mm_plugin_supports_port (MMPlugin *self, return; } - /* Before launching any probing, check if the port is a net device. */ - if (g_str_equal (mm_kernel_device_get_subsystem (port), "net")) { - mm_dbg ("(%s) [%s] probing deferred until result suggested", - self->priv->name, mm_kernel_device_get_name (port)); - g_task_return_int (task, MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED); - g_object_unref (task); - return; - } - /* Build flags depending on what probing needed */ probe_run_flags = MM_PORT_PROBE_NONE; - if (!g_str_has_prefix (mm_kernel_device_get_name (port), "cdc-wdm")) { - /* Serial ports... */ + if (g_str_equal (mm_kernel_device_get_subsystem (port), "tty")) { if (self->priv->at) probe_run_flags |= MM_PORT_PROBE_AT; else if (self->priv->single_at) probe_run_flags |= MM_PORT_PROBE_AT; if (self->priv->qcdm) probe_run_flags |= MM_PORT_PROBE_QCDM; - } else { - /* cdc-wdm ports... */ + } else if (g_str_equal (mm_kernel_device_get_subsystem (port), "usbmisc")) { if (self->priv->qmi && !g_strcmp0 (mm_kernel_device_get_driver (port), "qmi_wwan")) probe_run_flags |= MM_PORT_PROBE_QMI; else if (self->priv->mbim && !g_strcmp0 (mm_kernel_device_get_driver (port), "cdc_mbim")) probe_run_flags |= MM_PORT_PROBE_MBIM; else probe_run_flags |= MM_PORT_PROBE_AT; + } else if (g_str_equal (mm_kernel_device_get_subsystem (port), "rpmsg")) { + if (self->priv->at) + probe_run_flags |= MM_PORT_PROBE_AT; + if (self->priv->qmi) + probe_run_flags |= MM_PORT_PROBE_QMI; + } else if (g_str_equal (mm_kernel_device_get_subsystem (port), "wwan")) { + if (self->priv->mbim) + probe_run_flags |= MM_PORT_PROBE_MBIM; + if (self->priv->qmi) + probe_run_flags |= MM_PORT_PROBE_QMI; + if (self->priv->qcdm) + probe_run_flags |= MM_PORT_PROBE_QCDM; + if (self->priv->at) + probe_run_flags |= MM_PORT_PROBE_AT; } /* For potential AT ports, check for more things */ @@ -821,9 +809,11 @@ mm_plugin_supports_port (MMPlugin *self, probe_run_flags |= MM_PORT_PROBE_AT_XMM; } - /* If no explicit probing was required, just request to grab it without probing anything. - * This may happen, e.g. with cdc-wdm ports which do not need QMI/MBIM probing. */ + /* If no explicit probing was required, just request to grab it without + * probing anything. This happens for all net ports and e.g. for cdc-wdm + * ports which do not need QMI/MBIM probing. */ if (probe_run_flags == MM_PORT_PROBE_NONE) { + mm_obj_dbg (self, "probing of port %s deferred until result suggested", mm_kernel_device_get_name (port)); g_task_return_int (task, MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED); g_object_unref (task); return; @@ -835,10 +825,9 @@ mm_plugin_supports_port (MMPlugin *self, if (self->priv->single_at && mm_port_probe_list_has_at_port (mm_device_peek_port_probe_list (device)) && !mm_port_probe_is_at (probe)) { - mm_dbg ("(%s) [%s] not setting up AT probing tasks: " - "modem already has the expected single AT port", - self->priv->name, - mm_kernel_device_get_name (port)); + mm_obj_dbg (self, "not setting up AT probing tasks in port %s: " + "modem already has the expected single AT port", + mm_kernel_device_get_name (port)); /* Assuming it won't be an AT port. We still run the probe anyway, in * case we need to check for other port types (e.g. QCDM) */ @@ -856,10 +845,9 @@ mm_plugin_supports_port (MMPlugin *self, /* Launch the probe */ probe_list_str = mm_port_probe_flag_build_string_from_mask (ctx->flags); - mm_dbg ("(%s) [%s] probe required: '%s'", - self->priv->name, - mm_kernel_device_get_name (port), - probe_list_str); + mm_obj_dbg (self, "probes required for port %s: '%s'", + mm_kernel_device_get_name (port), + probe_list_str); g_free (probe_list_str); mm_port_probe_run (probe, @@ -909,22 +897,25 @@ mm_plugin_discard_port_early (MMPlugin *self, MMBaseModem * mm_plugin_create_modem (MMPlugin *self, - MMDevice *device, + MMDevice *device, GError **error) { - MMBaseModem *modem; - GList *port_probes = NULL; + MMBaseModem *modem; + GList *port_probes = NULL; const gchar **virtual_ports = NULL; + const gchar **drivers; if (!mm_device_is_virtual (device)) port_probes = mm_device_peek_port_probe_list (device); else virtual_ports = mm_device_virtual_peek_ports (device); + drivers = mm_device_get_drivers (device); + /* Let the plugin create the modem from the port probe results */ modem = MM_PLUGIN_GET_CLASS (self)->create_modem (MM_PLUGIN (self), mm_device_get_uid (device), - mm_device_get_drivers (device), + drivers, mm_device_get_vendor (device), mm_device_get_product (device), port_probes, @@ -972,65 +963,71 @@ mm_plugin_create_modem (MMPlugin *self, /* Ports that are explicitly blacklisted will be grabbed as ignored */ if (mm_port_probe_is_ignored (probe)) { - mm_dbg ("(%s/%s): port is blacklisted", subsys, name); + mm_obj_dbg (self, "port %s is blacklisted", name); force_ignored = TRUE; goto grab_port; } + /* Force network ignore rules for devices that use qmi_wwan */ + if (drivers && g_strv_contains (drivers, "qmi_wwan")) { #if defined WITH_QMI - if (MM_IS_BROADBAND_MODEM_QMI (modem) && - port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "qmi_wwan") != 0) { - /* Non-QMI net ports are ignored in QMI modems */ - mm_dbg ("(%s/%s): ignoring non-QMI net port in QMI modem", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (MM_IS_BROADBAND_MODEM_QMI (modem) && + port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "qmi_wwan") != 0) { + /* Non-QMI net ports are ignored in QMI modems */ + mm_obj_dbg (self, "ignoring non-QMI net port %s in QMI modem", name); + force_ignored = TRUE; + goto grab_port; + } - if (!MM_IS_BROADBAND_MODEM_QMI (modem) && - port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "qmi_wwan") == 0) { - /* QMI net ports are ignored in non-QMI modems */ - mm_dbg ("(%s/%s): ignoring QMI net port in non-QMI modem", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (!MM_IS_BROADBAND_MODEM_QMI (modem) && + port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "qmi_wwan") == 0) { + /* QMI net ports are ignored in non-QMI modems */ + mm_obj_dbg (self, "ignoring QMI net port %s in non-QMI modem", name); + force_ignored = TRUE; + goto grab_port; + } #else - if (port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "qmi_wwan") == 0) { - /* QMI net ports are ignored if QMI support not built */ - mm_dbg ("(%s/%s): ignoring QMI net port as QMI support isn't available", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "qmi_wwan") == 0) { + /* QMI net ports are ignored if QMI support not built */ + mm_obj_dbg (self, "ignoring QMI net port %s as QMI support isn't available", name); + force_ignored = TRUE; + goto grab_port; + } #endif + } + /* Force network ignore rules for devices that use cdc_mbim */ + if (drivers && g_strv_contains (drivers, "cdc_mbim")) { #if defined WITH_MBIM - if (MM_IS_BROADBAND_MODEM_MBIM (modem) && - port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "cdc_mbim") != 0) { - /* Non-MBIM net ports are ignored in MBIM modems */ - mm_dbg ("(%s/%s): ignoring non-MBIM net port in MBIM modem", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (MM_IS_BROADBAND_MODEM_MBIM (modem) && + port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "cdc_mbim") != 0) { + /* Non-MBIM net ports are ignored in MBIM modems */ + mm_obj_dbg (self, "ignoring non-MBIM net port %s in MBIM modem", name); + force_ignored = TRUE; + goto grab_port; + } - if (!MM_IS_BROADBAND_MODEM_MBIM (modem) && - port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "cdc_mbim") == 0) { - /* MBIM net ports are ignored in non-MBIM modems */ - mm_dbg ("(%s/%s): ignoring MBIM net port in non-MBIM modem", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (!MM_IS_BROADBAND_MODEM_MBIM (modem) && + port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "cdc_mbim") == 0) { + /* MBIM net ports are ignored in non-MBIM modems */ + mm_obj_dbg (self, "ignoring MBIM net port %s in non-MBIM modem", name); + force_ignored = TRUE; + goto grab_port; + } #else - if (port_type == MM_PORT_TYPE_NET && - g_strcmp0 (driver, "cdc_mbim") == 0) { - mm_dbg ("(%s/%s): ignoring MBIM net port as MBIM support isn't available", subsys, name); - force_ignored = TRUE; - goto grab_port; - } + if (port_type == MM_PORT_TYPE_NET && + g_strcmp0 (driver, "cdc_mbim") == 0) { + mm_obj_dbg (self, "ignoring MBIM net port %s as MBIM support isn't available", name); + force_ignored = TRUE; + goto grab_port; + } #endif + } grab_port: if (force_ignored) @@ -1053,9 +1050,7 @@ mm_plugin_create_modem (MMPlugin *self, next: if (!grabbed) { - mm_warn ("Could not grab port (%s/%s): '%s'", - subsys, name, - inner_error ? inner_error->message : "unknown error"); + mm_obj_warn (self, "could not grab port %s: %s", name, inner_error ? inner_error->message : "unknown error"); g_clear_error (&inner_error); } } @@ -1077,18 +1072,18 @@ mm_plugin_create_modem (MMPlugin *self, * installed yet). */ kernel_device = mm_kernel_device_generic_new_with_rules (properties, NULL, &inner_error); if (!kernel_device) { - mm_warn ("Could not grab port (virtual/%s): '%s'", - virtual_ports[i], - inner_error ? inner_error->message : "unknown error"); + mm_obj_warn (self, "could not create generic device for virtual port %s: %s", + virtual_ports[i], + inner_error ? inner_error->message : "unknown error"); g_clear_error (&inner_error); } else if (!mm_base_modem_grab_port (modem, kernel_device, MM_PORT_TYPE_AT, MM_PORT_SERIAL_AT_FLAG_NONE, &inner_error)) { - mm_warn ("Could not grab port (virtual/%s): '%s'", - virtual_ports[i], - inner_error ? inner_error->message : "unknown error"); + mm_obj_warn (self, "could not grab virtual port %s: %s", + virtual_ports[i], + inner_error ? inner_error->message : "unknown error"); g_clear_error (&inner_error); } @@ -1107,6 +1102,19 @@ mm_plugin_create_modem (MMPlugin *self, /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + MMPlugin *self; + g_autofree gchar *plugin_name_lowercase = NULL; + + self = MM_PLUGIN (_self); + plugin_name_lowercase = g_ascii_strdown (self->priv->name, -1); + return g_strdup_printf ("plugin/%s", plugin_name_lowercase); +} + +/*****************************************************************************/ + static void mm_plugin_init (MMPlugin *self) { @@ -1133,6 +1141,10 @@ set_property (GObject *object, /* Construct only */ self->priv->name = g_value_dup_string (value); break; + case PROP_IS_GENERIC: + /* Construct only */ + self->priv->is_generic = g_value_get_boolean (value); + break; case PROP_ALLOWED_SUBSYSTEMS: /* Construct only */ self->priv->subsystems = g_value_dup_boxed (value); @@ -1255,6 +1267,9 @@ get_property (GObject *object, case PROP_NAME: g_value_set_string (value, self->priv->name); break; + case PROP_IS_GENERIC: + g_value_set_boolean (value, self->priv->is_generic); + break; case PROP_ALLOWED_SUBSYSTEMS: g_value_set_boxed (value, self->priv->subsystems); break; @@ -1366,6 +1381,12 @@ finalize (GObject *object) G_OBJECT_CLASS (mm_plugin_parent_class)->finalize (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_plugin_class_init (MMPluginClass *klass) { @@ -1386,6 +1407,14 @@ mm_plugin_class_init (MMPluginClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, PROP_IS_GENERIC, + g_param_spec_boolean (MM_PLUGIN_IS_GENERIC, + "Generic", + "Whether the plugin is the generic one", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_ALLOWED_SUBSYSTEMS, g_param_spec_boxed (MM_PLUGIN_ALLOWED_SUBSYSTEMS, diff --git a/src/mm-plugin.h b/src/mm-plugin.h index 926840bf..b27e7a2f 100644 --- a/src/mm-plugin.h +++ b/src/mm-plugin.h @@ -27,7 +27,6 @@ #include "mm-device.h" #include "mm-kernel-device.h" -#define MM_PLUGIN_GENERIC_NAME "Generic" #define MM_PLUGIN_MAJOR_VERSION 4 #define MM_PLUGIN_MINOR_VERSION 0 @@ -48,6 +47,7 @@ #define MM_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN, MMPluginClass)) #define MM_PLUGIN_NAME "name" +#define MM_PLUGIN_IS_GENERIC "is-generic" #define MM_PLUGIN_ALLOWED_SUBSYSTEMS "allowed-subsystems" #define MM_PLUGIN_ALLOWED_DRIVERS "allowed-drivers" #define MM_PLUGIN_FORBIDDEN_DRIVERS "forbidden-drivers" @@ -123,10 +123,14 @@ struct _MMPluginClass { }; GType mm_plugin_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPlugin, g_object_unref) const gchar *mm_plugin_get_name (MMPlugin *self); +const gchar **mm_plugin_get_allowed_subsystems (MMPlugin *self); const gchar **mm_plugin_get_allowed_udev_tags (MMPlugin *self); +const guint16 *mm_plugin_get_allowed_vendor_ids (MMPlugin *self); const mm_uint16_pair *mm_plugin_get_allowed_product_ids (MMPlugin *self); +gboolean mm_plugin_is_generic (MMPlugin *self); /* This method will run all pre-probing filters, to see if we can discard this * plugin from the probing logic as soon as possible. */ diff --git a/src/mm-port-mbim.c b/src/mm-port-mbim.c index 1778e783..57b7cf02 100644 --- a/src/mm-port-mbim.c +++ b/src/mm-port-mbim.c @@ -26,7 +26,7 @@ #include #include "mm-port-mbim.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMPortMbim, mm_port_mbim, MM_TYPE_PORT) @@ -176,18 +176,14 @@ qmi_device_open_ready (QmiDevice *dev, self = g_task_get_source_object (task); if (!qmi_device_open_finish (dev, res, &error)) { - mm_dbg ("[%s] error: couldn't open QmiDevice: %s", - mm_port_get_device (MM_PORT (self)), - error->message); + mm_obj_dbg (self, "error: couldn't open QmiDevice: %s", error->message); g_error_free (error); g_clear_object (&self->priv->qmi_device); /* Ignore error and complete */ - mm_info ("[%s] MBIM device is not QMI capable", - mm_port_get_device (MM_PORT (self))); + mm_obj_info (self, "MBIM device is not QMI capable"); self->priv->qmi_supported = FALSE; } else { - mm_info ("[%s] MBIM device is QMI capable", - mm_port_get_device (MM_PORT (self))); + mm_obj_info (self, "MBIM device is QMI capable"); } self->priv->in_progress = FALSE; @@ -207,13 +203,10 @@ qmi_device_new_ready (GObject *unused, self->priv->qmi_device = qmi_device_new_finish (res, &error); if (!self->priv->qmi_device) { - mm_dbg ("[%s] error: couldn't create QmiDevice: %s", - mm_port_get_device (MM_PORT (self)), - error->message); + mm_obj_dbg (self, "error: couldn't create QmiDevice: %s", error->message); g_error_free (error); /* Ignore error and complete */ - mm_info ("[%s] MBIM device is not QMI capable", - mm_port_get_device (MM_PORT (self))); + mm_obj_info (self, "MBIM device is not QMI capable"); self->priv->qmi_supported = FALSE; self->priv->in_progress = FALSE; g_task_return_boolean (task, TRUE); @@ -222,8 +215,7 @@ qmi_device_new_ready (GObject *unused, } /* Try to open using QMI over MBIM */ - mm_dbg ("[%s] trying to open QMI over MBIM device...", - mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "trying to open QMI over MBIM device..."); qmi_device_open (self->priv->qmi_device, (QMI_DEVICE_OPEN_FLAGS_PROXY | QMI_DEVICE_OPEN_FLAGS_MBIM | @@ -272,7 +264,7 @@ mbim_query_device_services_ready (MbimDevice *device, mbim_device_service_element_array_free (device_services); } else { /* Ignore error */ - mm_dbg ("Couldn't query device services, will attempt QMI open anyway: %s", error->message); + mm_obj_dbg (self, "Couldn't query device services, will attempt QMI open anyway: %s", error->message); g_error_free (error); } @@ -283,8 +275,7 @@ mbim_query_device_services_ready (MbimDevice *device, file = G_FILE (g_task_get_task_data (task)); if (!file || !self->priv->qmi_supported) { - mm_info ("[%s] MBIM device is not QMI capable", - mm_port_get_device (MM_PORT (self))); + mm_obj_info (self, "MBIM device is not QMI capable"); self->priv->in_progress = FALSE; g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -292,8 +283,7 @@ mbim_query_device_services_ready (MbimDevice *device, } /* Attempt to create and open the QMI device */ - mm_dbg ("[%s] checking if QMI over MBIM is supported", - mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "checking if QMI over MBIM is supported..."); qmi_device_new (file, g_task_get_cancellable (task), (GAsyncReadyCallback) qmi_device_new_ready, @@ -338,8 +328,7 @@ mbim_device_open_ready (MbimDevice *mbim_device, return; } - mm_dbg ("[%s] MBIM device is now open", - mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "MBIM device is now open"); #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED if (self->priv->qmi_supported) { @@ -507,10 +496,13 @@ qmi_device_close_ready (QmiDevice *qmi_device, GAsyncResult *res, GTask *task) { - GError *error = NULL; + GError *error = NULL; + MMPortMbim *self; + + self = g_task_get_source_object (task); if (!qmi_device_close_finish (qmi_device, res, &error)) { - mm_warn ("Couldn't properly close QMI device: %s", error->message); + mm_obj_warn (self, "Couldn't properly close QMI device: %s", error->message); g_error_free (error); } @@ -561,7 +553,8 @@ mm_port_mbim_close (MMPortMbim *self, for (l = self->priv->qmi_clients; l; l = g_list_next (l)) { QmiClient *qmi_client = QMI_CLIENT (l->data); - mm_dbg ("Releasing client for service '%s'...", qmi_service_get_string (qmi_client_get_service (qmi_client))); + mm_obj_dbg (self, "Releasing client for service '%s'...", + qmi_service_get_string (qmi_client_get_service (qmi_client))); qmi_device_release_client (self->priv->qmi_device, qmi_client, QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID, @@ -596,11 +589,12 @@ mm_port_mbim_peek_device (MMPortMbim *self) /*****************************************************************************/ MMPortMbim * -mm_port_mbim_new (const gchar *name) +mm_port_mbim_new (const gchar *name, + MMPortSubsys subsys) { return MM_PORT_MBIM (g_object_new (MM_TYPE_PORT_MBIM, MM_PORT_DEVICE, name, - MM_PORT_SUBSYS, MM_PORT_SUBSYS_USB, + MM_PORT_SUBSYS, subsys, MM_PORT_TYPE, MM_PORT_TYPE_MBIM, NULL)); } diff --git a/src/mm-port-mbim.h b/src/mm-port-mbim.h index 3bd20e48..8b37e99b 100644 --- a/src/mm-port-mbim.h +++ b/src/mm-port-mbim.h @@ -51,8 +51,10 @@ struct _MMPortMbimClass { }; GType mm_port_mbim_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortMbim, g_object_unref) -MMPortMbim *mm_port_mbim_new (const gchar *name); +MMPortMbim *mm_port_mbim_new (const gchar *name, + MMPortSubsys subsys); void mm_port_mbim_open (MMPortMbim *self, #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED diff --git a/src/mm-port-probe-at.c b/src/mm-port-probe-at.c index 10cce9e5..37a5ab27 100644 --- a/src/mm-port-probe-at.c +++ b/src/mm-port-probe-at.c @@ -40,8 +40,6 @@ mm_port_probe_response_processor_is_at (const gchar *command, GError **result_error) { if (error) { - mm_dbg ("Parsing AT got: '%s'", error->message); - /* Timeout errors are the only ones not fatal; * they will just go on to the next command. */ if (g_error_matches (error, diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c index 1700111f..ef5b4c94 100644 --- a/src/mm-port-probe.c +++ b/src/mm-port-probe.c @@ -27,7 +27,7 @@ #include #include "mm-port-probe.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-port-serial-at.h" #include "mm-port-serial.h" #include "mm-serial-parsers.h" @@ -63,7 +63,10 @@ * |----> MBIM capabilities check */ -G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT) +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMPortProbe, mm_port_probe, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -98,6 +101,8 @@ struct _MMPortProbePrivate { gboolean maybe_at_secondary; gboolean maybe_at_ppp; gboolean maybe_qcdm; + gboolean maybe_qmi; + gboolean maybe_mbim; /* Current probing task. Only one can be available at a time */ GTask *task; @@ -159,9 +164,7 @@ mm_port_probe_set_result_at (MMPortProbe *self, self->priv->flags |= MM_PORT_PROBE_AT; if (self->priv->is_at) { - mm_dbg ("(%s/%s) port is AT-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is AT-capable"); /* Also set as not a QCDM/QMI/MBIM port */ self->priv->is_qcdm = FALSE; @@ -169,9 +172,7 @@ mm_port_probe_set_result_at (MMPortProbe *self, self->priv->is_mbim = FALSE; self->priv->flags |= (MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI | MM_PORT_PROBE_MBIM); } else { - mm_dbg ("(%s/%s) port is not AT-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is not AT-capable"); self->priv->vendor = NULL; self->priv->product = NULL; self->priv->is_icera = FALSE; @@ -188,15 +189,11 @@ mm_port_probe_set_result_at_vendor (MMPortProbe *self, const gchar *at_vendor) { if (at_vendor) { - mm_dbg ("(%s/%s) vendor probing finished", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "vendor probing finished"); self->priv->vendor = g_utf8_casefold (at_vendor, -1); self->priv->flags |= MM_PORT_PROBE_AT_VENDOR; } else { - mm_dbg ("(%s/%s) couldn't probe for vendor string", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "couldn't probe for vendor string"); self->priv->vendor = NULL; self->priv->product = NULL; self->priv->flags |= (MM_PORT_PROBE_AT_VENDOR | MM_PORT_PROBE_AT_PRODUCT); @@ -208,15 +205,11 @@ mm_port_probe_set_result_at_product (MMPortProbe *self, const gchar *at_product) { if (at_product) { - mm_dbg ("(%s/%s) product probing finished", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "product probing finished"); self->priv->product = g_utf8_casefold (at_product, -1); self->priv->flags |= MM_PORT_PROBE_AT_PRODUCT; } else { - mm_dbg ("(%s/%s) couldn't probe for product string", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "couldn't probe for product string"); self->priv->product = NULL; self->priv->flags |= MM_PORT_PROBE_AT_PRODUCT; } @@ -227,15 +220,11 @@ mm_port_probe_set_result_at_icera (MMPortProbe *self, gboolean is_icera) { if (is_icera) { - mm_dbg ("(%s/%s) Modem is Icera-based", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "modem is Icera-based"); self->priv->is_icera = TRUE; self->priv->flags |= MM_PORT_PROBE_AT_ICERA; } else { - mm_dbg ("(%s/%s) Modem is probably not Icera-based", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "modem is probably not Icera-based"); self->priv->is_icera = FALSE; self->priv->flags |= MM_PORT_PROBE_AT_ICERA; } @@ -246,15 +235,11 @@ mm_port_probe_set_result_at_xmm (MMPortProbe *self, gboolean is_xmm) { if (is_xmm) { - mm_dbg ("(%s/%s) Modem is XMM-based", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "modem is XMM-based"); self->priv->is_xmm = TRUE; self->priv->flags |= MM_PORT_PROBE_AT_XMM; } else { - mm_dbg ("(%s/%s) Modem is probably not XMM-based", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "modem is probably not XMM-based"); self->priv->is_xmm = FALSE; self->priv->flags |= MM_PORT_PROBE_AT_XMM; } @@ -268,9 +253,7 @@ mm_port_probe_set_result_qcdm (MMPortProbe *self, self->priv->flags |= MM_PORT_PROBE_QCDM; if (self->priv->is_qcdm) { - mm_dbg ("(%s/%s) port is QCDM-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is QCDM-capable"); /* Also set as not an AT/QMI/MBIM port */ self->priv->is_at = FALSE; @@ -288,9 +271,7 @@ mm_port_probe_set_result_qcdm (MMPortProbe *self, MM_PORT_PROBE_QMI | MM_PORT_PROBE_MBIM); } else - mm_dbg ("(%s/%s) port is not QCDM-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is not QCDM-capable"); } void @@ -301,9 +282,7 @@ mm_port_probe_set_result_qmi (MMPortProbe *self, self->priv->flags |= MM_PORT_PROBE_QMI; if (self->priv->is_qmi) { - mm_dbg ("(%s/%s) port is QMI-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is QMI-capable"); /* Also set as not an AT/QCDM/MBIM port */ self->priv->is_at = FALSE; @@ -319,9 +298,7 @@ mm_port_probe_set_result_qmi (MMPortProbe *self, MM_PORT_PROBE_QCDM | MM_PORT_PROBE_MBIM); } else - mm_dbg ("(%s/%s) port is not QMI-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is not QMI-capable"); } void @@ -332,9 +309,7 @@ mm_port_probe_set_result_mbim (MMPortProbe *self, self->priv->flags |= MM_PORT_PROBE_MBIM; if (self->priv->is_mbim) { - mm_dbg ("(%s/%s) port is MBIM-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is MBIM-capable"); /* Also set as not an AT/QCDM/QMI port */ self->priv->is_at = FALSE; @@ -350,9 +325,7 @@ mm_port_probe_set_result_mbim (MMPortProbe *self, MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI); } else - mm_dbg ("(%s/%s) port is not MBIM-capable", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port is not MBIM-capable"); } /*****************************************************************************/ @@ -494,10 +467,8 @@ port_qmi_open_ready (MMPortQmi *port_qmi, is_qmi = mm_port_qmi_open_finish (port_qmi, res, &error); if (!is_qmi) { - mm_dbg ("(%s/%s) error checking QMI support: '%s'", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - error ? error->message : "unknown error"); + mm_obj_dbg (self, "error checking QMI support: %s", + error ? error->message : "unknown error"); g_clear_error (&error); } @@ -520,17 +491,22 @@ wdm_probe_qmi (MMPortProbe *self) ctx = g_task_get_task_data (self->priv->task); #if defined WITH_QMI - mm_dbg ("(%s/%s) probing QMI...", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + { + MMPortSubsys subsys = MM_PORT_SUBSYS_USBMISC; - /* Create a port and try to open it */ - ctx->port_qmi = mm_port_qmi_new (mm_kernel_device_get_name (self->priv->port)); - mm_port_qmi_open (ctx->port_qmi, - FALSE, - NULL, - (GAsyncReadyCallback) port_qmi_open_ready, - self); + mm_obj_dbg (self, "probing QMI..."); + + if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "rpmsg")) + subsys = MM_PORT_SUBSYS_RPMSG; + + /* Create a port and try to open it */ + ctx->port_qmi = mm_port_qmi_new (mm_kernel_device_get_name (self->priv->port), subsys); + mm_port_qmi_open (ctx->port_qmi, + FALSE, + NULL, + (GAsyncReadyCallback) port_qmi_open_ready, + self); + } #else /* If not compiled with QMI support, just assume we won't have any QMI port */ mm_port_probe_set_result_qmi (self, FALSE); @@ -570,10 +546,8 @@ mbim_port_open_ready (MMPortMbim *mbim_port, is_mbim = mm_port_mbim_open_finish (mbim_port, res, &error); if (!is_mbim) { - mm_dbg ("(%s/%s) error checking MBIM support: '%s'", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - error ? error->message : "unknown error"); + mm_obj_dbg (self, "error checking MBIM support: %s", + error ? error->message : "unknown error"); g_clear_error (&error); } @@ -596,12 +570,11 @@ wdm_probe_mbim (MMPortProbe *self) ctx = g_task_get_task_data (self->priv->task); #if defined WITH_MBIM - mm_dbg ("(%s/%s) probing MBIM...", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "probing MBIM..."); /* Create a port and try to open it */ - ctx->mbim_port = mm_port_mbim_new (mm_kernel_device_get_name (self->priv->port)); + ctx->mbim_port = mm_port_mbim_new (mm_kernel_device_get_name (self->priv->port), + MM_PORT_SUBSYS_USBMISC); mm_port_mbim_open (ctx->mbim_port, #if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED FALSE, /* Don't check QMI over MBIM support at this stage */ @@ -668,10 +641,7 @@ common_serial_port_setup (MMPortProbe *self, flow_control = mm_flow_control_from_string (flow_control_tag, &error); if (flow_control == MM_FLOW_CONTROL_UNKNOWN) { - mm_warn ("(%s/%s) Unsupported flow control settings in port: %s", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - error->message); + mm_obj_warn (self, "unsupported flow control settings in port: %s", error->message); g_error_free (error); } else { g_object_set (serial, @@ -708,10 +678,7 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port, /* Parse the response */ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err); if (!result) { - mm_warn ("(%s/%s) failed to parse QCDM version info command result: %d", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - err); + mm_obj_warn (self, "failed to parse QCDM version info command result: %d", err); retry = TRUE; } else { /* yay, probably a QCDM port */ @@ -721,11 +688,11 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port, g_byte_array_unref (response); } else if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_PARSE_FAILED)) { /* Failed to unescape QCDM packet: don't retry */ - mm_dbg ("QCDM parsing error: %s", error->message); + mm_obj_dbg (self, "QCDM parsing error: %s", error->message); g_error_free (error); } else { if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) - mm_dbg ("QCDM probe error: (%d) %s", error->code, error->message); + mm_obj_dbg (self, "QCDM probe error: (%d) %s", error->code, error->message); g_error_free (error); retry = TRUE; } @@ -763,6 +730,8 @@ serial_probe_qcdm (MMPortProbe *self) gint len; guint8 marker = 0x7E; PortProbeRunContext *ctx; + MMPortSubsys subsys = MM_PORT_SUBSYS_TTY; + g_assert (self->priv->task); ctx = g_task_get_task_data (self->priv->task); @@ -772,9 +741,7 @@ serial_probe_qcdm (MMPortProbe *self) if (port_probe_task_return_error_if_cancelled (self)) return G_SOURCE_REMOVE; - mm_dbg ("(%s/%s) probing QCDM...", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "probing QCDM..."); /* If open, close the AT port */ if (ctx->serial) { @@ -787,8 +754,11 @@ serial_probe_qcdm (MMPortProbe *self) g_object_unref (ctx->serial); } + if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "wwan")) + subsys = MM_PORT_SUBSYS_WWAN; + /* Open the QCDM port */ - ctx->serial = MM_PORT_SERIAL (mm_port_serial_qcdm_new (mm_kernel_device_get_name (self->priv->port))); + ctx->serial = MM_PORT_SERIAL (mm_port_serial_qcdm_new (mm_kernel_device_get_name (self->priv->port), subsys)); if (!ctx->serial) { port_probe_task_return_error (self, g_error_new (MM_CORE_ERROR, @@ -1003,9 +973,7 @@ serial_probe_at_parse_response (MMPortSerialAt *port, /* If AT probing cancelled, end this partial probing */ if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) { - mm_dbg ("(%s/%s) no need to keep on probing the port for AT support", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "no need to keep on probing the port for AT support"); ctx->at_result_processor (self, NULL); serial_probe_schedule (self); return; @@ -1046,10 +1014,8 @@ serial_probe_at_parse_response (MMPortSerialAt *port, if (ctx->at_commands_wait_secs == 0) ctx->source_id = g_idle_add ((GSourceFunc) serial_probe_at, self); else { - mm_dbg ("(%s/%s) re-scheduling next command in probing group in %u seconds...", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - ctx->at_commands_wait_secs); + mm_obj_dbg (self, "re-scheduling next command in probing group in %u seconds...", + ctx->at_commands_wait_secs); ctx->source_id = g_timeout_add_seconds (ctx->at_commands_wait_secs, (GSourceFunc) serial_probe_at, self); } goto out; @@ -1083,9 +1049,7 @@ serial_probe_at (MMPortProbe *self) /* If AT probing cancelled, end this partial probing */ if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) { - mm_dbg ("(%s/%s) no need to launch probing for AT support", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "no need to launch probing for AT support"); ctx->at_result_processor (self, NULL); serial_probe_schedule (self); return G_SOURCE_REMOVE; @@ -1275,9 +1239,7 @@ serial_buffer_full (MMPortSerial *serial, g_assert (self->priv->task); ctx = g_task_get_task_data (self->priv->task); - mm_dbg ("(%s/%s) serial buffer full", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "serial buffer full"); /* Don't explicitly close the AT port, just end the AT probing * (or custom init probing) */ mm_port_probe_set_result_at (self, FALSE); @@ -1320,8 +1282,12 @@ serial_open_at (MMPortProbe *self) gpointer parser; MMPortSubsys subsys = MM_PORT_SUBSYS_TTY; - if (g_str_has_prefix (mm_kernel_device_get_subsystem (self->priv->port), "usb")) - subsys = MM_PORT_SUBSYS_USB; + if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "usbmisc")) + subsys = MM_PORT_SUBSYS_USBMISC; + else if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "rpmsg")) + subsys = MM_PORT_SUBSYS_RPMSG; + else if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "wwan")) + subsys = MM_PORT_SUBSYS_WWAN; ctx->serial = MM_PORT_SERIAL (mm_port_serial_at_new (mm_kernel_device_get_name (self->priv->port), subsys)); if (!ctx->serial) { @@ -1420,9 +1386,7 @@ mm_port_probe_run_cancel_at_probing (MMPortProbe *self) if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) return FALSE; - mm_dbg ("(%s/%s) requested to cancel all AT probing", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "requested to cancel all AT probing"); g_cancellable_cancel (ctx->at_probing_cancellable); return TRUE; } @@ -1478,45 +1442,59 @@ mm_port_probe_run (MMPortProbe *self, /* If we're told to completely ignore the port, don't do any probing */ if (self->priv->is_ignored) { - mm_dbg ("(%s/%s) port probing finished: skipping for blacklisted port", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port probing finished: skipping for blacklisted port"); port_probe_task_return_boolean (self, TRUE); return; } - /* If this is a port flagged as a GPS port, don't do any AT or QCDM probing */ + /* If this is a port flagged as a GPS port, don't do any other probing */ if (self->priv->is_gps) { - mm_dbg ("(%s/%s) GPS port detected", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); - mm_port_probe_set_result_at (self, FALSE); + mm_obj_dbg (self, "GPS port detected"); + mm_port_probe_set_result_at (self, FALSE); mm_port_probe_set_result_qcdm (self, FALSE); + mm_port_probe_set_result_qmi (self, FALSE); + mm_port_probe_set_result_mbim (self, FALSE); } - /* If this is a port flagged as an audio port, don't do any AT or QCDM probing */ + /* If this is a port flagged as an audio port, don't do any other probing */ if (self->priv->is_audio) { - mm_dbg ("(%s/%s) audio port detected", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); - mm_port_probe_set_result_at (self, FALSE); + mm_obj_dbg (self, "audio port detected"); + mm_port_probe_set_result_at (self, FALSE); mm_port_probe_set_result_qcdm (self, FALSE); + mm_port_probe_set_result_qmi (self, FALSE); + mm_port_probe_set_result_mbim (self, FALSE); } - /* If this is a port flagged as being an AT port, don't do any QCDM probing */ + /* If this is a port flagged as being an AT port, don't do any other probing */ if (self->priv->maybe_at_primary || self->priv->maybe_at_secondary || self->priv->maybe_at_ppp) { - mm_dbg ("(%s/%s) no QCDM probing in possible AT port", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "no QCDM/QMI/MBIM probing in possible AT port"); mm_port_probe_set_result_qcdm (self, FALSE); + mm_port_probe_set_result_qmi (self, FALSE); + mm_port_probe_set_result_mbim (self, FALSE); } - /* If this is a port flagged as being a QCDM port, don't do any AT probing */ + /* If this is a port flagged as being a QCDM port, don't do any other probing */ if (self->priv->maybe_qcdm) { - mm_dbg ("(%s/%s) no AT probing in possible QCDM port", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); - mm_port_probe_set_result_at (self, FALSE); + mm_obj_dbg (self, "no AT/QMI/MBIM probing in possible QCDM port"); + mm_port_probe_set_result_at (self, FALSE); + mm_port_probe_set_result_qmi (self, FALSE); + mm_port_probe_set_result_mbim (self, FALSE); + } + + /* If this is a port flagged as being a QMI port, don't do any other probing */ + if (self->priv->maybe_qmi) { + mm_obj_dbg (self, "no AT/QCDM/MBIM probing in possible QMI port"); + mm_port_probe_set_result_at (self, FALSE); + mm_port_probe_set_result_qcdm (self, FALSE); + mm_port_probe_set_result_mbim (self, FALSE); + } + + /* If this is a port flagged as being a MBIM port, don't do any other probing */ + if (self->priv->maybe_mbim) { + mm_obj_dbg (self, "no AT/QCDM/QMI probing in possible MBIM port"); + mm_port_probe_set_result_at (self, FALSE); + mm_port_probe_set_result_qcdm (self, FALSE); + mm_port_probe_set_result_qmi (self, FALSE); } /* Check if we already have the requested probing results. @@ -1529,19 +1507,14 @@ mm_port_probe_run (MMPortProbe *self, /* All requested probings already available? If so, we're done */ if (!ctx->flags) { - mm_dbg ("(%s/%s) port probing finished: no more probings needed", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port)); + mm_obj_dbg (self, "port probing finished: no more probings needed"); port_probe_task_return_boolean (self, TRUE); return; } /* Log the probes scheduled to be run */ probe_list_str = mm_port_probe_flag_build_string_from_mask (ctx->flags); - mm_dbg ("(%s/%s) launching port probing: '%s'", - mm_kernel_device_get_subsystem (self->priv->port), - mm_kernel_device_get_name (self->priv->port), - probe_list_str); + mm_obj_dbg (self, "launching port probing: '%s'", probe_list_str); g_free (probe_list_str); /* If any AT probing is needed, start by opening as AT port */ @@ -1613,18 +1586,8 @@ mm_port_probe_list_has_at_port (GList *list) gboolean mm_port_probe_is_qcdm (MMPortProbe *self) { - const gchar *subsys; - const gchar *name; - g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - subsys = mm_kernel_device_get_subsystem (self->priv->port); - name = mm_kernel_device_get_name (self->priv->port); - if (g_str_equal (subsys, "net") || - (g_str_has_prefix (subsys, "usb") && - g_str_has_prefix (name, "cdc-wdm"))) - return FALSE; - return (self->priv->flags & MM_PORT_PROBE_QCDM ? self->priv->is_qcdm : FALSE); @@ -1633,19 +1596,11 @@ mm_port_probe_is_qcdm (MMPortProbe *self) gboolean mm_port_probe_is_qmi (MMPortProbe *self) { - const gchar *subsys; - const gchar *name; - g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - subsys = mm_kernel_device_get_subsystem (self->priv->port); - name = mm_kernel_device_get_name (self->priv->port); - if (!g_str_has_prefix (subsys, "usb") || - !name || - !g_str_has_prefix (name, "cdc-wdm")) - return FALSE; - - return self->priv->is_qmi; + return (self->priv->flags & MM_PORT_PROBE_QMI ? + self->priv->is_qmi : + FALSE); } gboolean @@ -1667,19 +1622,11 @@ mm_port_probe_list_has_qmi_port (GList *list) gboolean mm_port_probe_is_mbim (MMPortProbe *self) { - const gchar *subsys; - const gchar *name; - g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - subsys = mm_kernel_device_get_subsystem (self->priv->port); - name = mm_kernel_device_get_name (self->priv->port); - if (!g_str_has_prefix (subsys, "usb") || - !name || - !g_str_has_prefix (name, "cdc-wdm")) - return FALSE; - - return self->priv->is_mbim; + return (self->priv->flags & MM_PORT_PROBE_MBIM ? + self->priv->is_mbim : + FALSE); } gboolean @@ -1710,21 +1657,17 @@ mm_port_probe_get_port_type (MMPortProbe *self) if (g_str_equal (subsys, "net")) return MM_PORT_TYPE_NET; - if (g_str_has_prefix (subsys, "usb")) { - const gchar *name; - - name = mm_kernel_device_get_name (self->priv->port); - if (g_str_has_prefix (name, "cdc-wdm")) { #if defined WITH_QMI - if (self->priv->is_qmi) - return MM_PORT_TYPE_QMI; + if (self->priv->flags & MM_PORT_PROBE_QMI && + self->priv->is_qmi) + return MM_PORT_TYPE_QMI; #endif + #if defined WITH_MBIM - if (self->priv->is_mbim) - return MM_PORT_TYPE_MBIM; + if (self->priv->flags & MM_PORT_PROBE_MBIM && + self->priv->is_mbim) + return MM_PORT_TYPE_MBIM; #endif - } - } if (self->priv->flags & MM_PORT_PROBE_QCDM && self->priv->is_qcdm) @@ -1778,18 +1721,8 @@ mm_port_probe_get_port (MMPortProbe *self) const gchar * mm_port_probe_get_vendor (MMPortProbe *self) { - const gchar *subsys; - const gchar *name; - g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - subsys = mm_kernel_device_get_subsystem (self->priv->port); - name = mm_kernel_device_get_name (self->priv->port); - if (g_str_equal (subsys, "net") || - (g_str_has_prefix (subsys, "usb") && - g_str_has_prefix (name, "cdc-wdm"))) - return NULL; - return (self->priv->flags & MM_PORT_PROBE_AT_VENDOR ? self->priv->vendor : NULL); @@ -1798,18 +1731,8 @@ mm_port_probe_get_vendor (MMPortProbe *self) const gchar * mm_port_probe_get_product (MMPortProbe *self) { - const gchar *subsys; - const gchar *name; - g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - subsys = mm_kernel_device_get_subsystem (self->priv->port); - name = mm_kernel_device_get_name (self->priv->port); - if (g_str_equal (subsys, "net") || - (g_str_has_prefix (subsys, "usb") && - g_str_has_prefix (name, "cdc-wdm"))) - return NULL; - return (self->priv->flags & MM_PORT_PROBE_AT_PRODUCT ? self->priv->product : NULL); @@ -1820,9 +1743,6 @@ mm_port_probe_is_icera (MMPortProbe *self) { g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "net")) - return FALSE; - return (self->priv->flags & MM_PORT_PROBE_AT_ICERA ? self->priv->is_icera : FALSE); @@ -1846,9 +1766,6 @@ mm_port_probe_is_xmm (MMPortProbe *self) { g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); - if (g_str_equal (mm_kernel_device_get_subsystem (self->priv->port), "net")) - return FALSE; - return (self->priv->flags & MM_PORT_PROBE_AT_XMM ? self->priv->is_xmm : FALSE); @@ -1893,6 +1810,17 @@ mm_port_probe_get_port_subsys (MMPortProbe *self) /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + MMPortProbe *self; + + self = MM_PORT_PROBE (_self); + return g_strdup_printf ("%s/probe", mm_kernel_device_get_name (self->priv->port)); +} + +/*****************************************************************************/ + MMPortProbe * mm_port_probe_new (MMDevice *device, MMKernelDevice *port) @@ -1934,6 +1862,8 @@ set_property (GObject *object, self->priv->maybe_at_secondary = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AT_SECONDARY); self->priv->maybe_at_ppp = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AT_PPP); self->priv->maybe_qcdm = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_QCDM); + self->priv->maybe_qmi = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_QMI); + self->priv->maybe_mbim = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_MBIM); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1989,6 +1919,12 @@ dispose (GObject *object) G_OBJECT_CLASS (mm_port_probe_parent_class)->dispose (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_port_probe_class_init (MMPortProbeClass *klass) { diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h index 8c2ead9a..9c2fd893 100644 --- a/src/mm-port-probe.h +++ b/src/mm-port-probe.h @@ -79,6 +79,7 @@ typedef gboolean (* MMPortProbeAtCustomInitFinish) (MMPortProbe *probe, GError **error); GType mm_port_probe_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortProbe, g_object_unref) MMPortProbe *mm_port_probe_new (MMDevice *device, MMKernelDevice *port); diff --git a/src/mm-port-qmi.c b/src/mm-port-qmi.c index 75d3ee48..af407bd4 100644 --- a/src/mm-port-qmi.c +++ b/src/mm-port-qmi.c @@ -22,7 +22,7 @@ #include #include "mm-port-qmi.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMPortQmi, mm_port_qmi, MM_TYPE_PORT) @@ -41,24 +41,40 @@ struct _MMPortQmiPrivate { /*****************************************************************************/ -QmiClient * -mm_port_qmi_peek_client (MMPortQmi *self, - QmiService service, - MMPortQmiFlag flag) +static QmiClient * +lookup_client (MMPortQmi *self, + QmiService service, + MMPortQmiFlag flag, + gboolean steal) { GList *l; for (l = self->priv->services; l; l = g_list_next (l)) { ServiceInfo *info = l->data; - if (info->service == service && - info->flag == flag) - return info->client; + if (info->service == service && info->flag == flag) { + QmiClient *found; + + found = info->client; + if (steal) { + self->priv->services = g_list_delete_link (self->priv->services, l); + g_free (info); + } + return found; + } } return NULL; } +QmiClient * +mm_port_qmi_peek_client (MMPortQmi *self, + QmiService service, + MMPortQmiFlag flag) +{ + return lookup_client (self, service, flag, FALSE); +} + QmiClient * mm_port_qmi_get_client (MMPortQmi *self, QmiService service, @@ -82,6 +98,30 @@ mm_port_qmi_peek_device (MMPortQmi *self) /*****************************************************************************/ +void +mm_port_qmi_release_client (MMPortQmi *self, + QmiService service, + MMPortQmiFlag flag) +{ + QmiClient *client; + + if (!self->priv->qmi_device) + return; + + client = lookup_client (self, service, flag, TRUE); + if (!client) + return; + + mm_obj_dbg (self, "explicitly releasing client for service '%s'...", qmi_service_get_string (service)); + qmi_device_release_client (self->priv->qmi_device, + client, + QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID, + 3, NULL, NULL, NULL); + g_object_unref (client); +} + +/*****************************************************************************/ + typedef struct { ServiceInfo *info; } AllocateClientContext; @@ -194,7 +234,7 @@ typedef enum { PORT_OPEN_STEP_ALLOCATE_WDA_CLIENT, PORT_OPEN_STEP_GET_WDA_DATA_FORMAT, PORT_OPEN_STEP_CHECK_DATA_FORMAT, - PORT_OPEN_STEP_SET_KERNEL_DATA_FORMAT, + PORT_OPEN_STEP_SYNC_DATA_FORMAT, PORT_OPEN_STEP_CLOSE_BEFORE_OPEN_WITH_DATA_FORMAT, PORT_OPEN_STEP_OPEN_WITH_DATA_FORMAT, PORT_OPEN_STEP_LAST @@ -254,26 +294,35 @@ qmi_device_close_on_error_ready (QmiDevice *qmi_device, GAsyncResult *res, GTask *task) { - GError *error = NULL; + MMPortQmi *self; + g_autoptr(GError) error = NULL; - if (!qmi_device_close_finish (qmi_device, res, &error)) { - mm_warn ("Couldn't close QMI device after failed open sequence: %s", error->message); - g_error_free (error); - } + self = g_task_get_source_object (task); + + if (!qmi_device_close_finish (qmi_device, res, &error)) + mm_obj_warn (self, "Couldn't close QMI device after failed open sequence: %s", error->message); port_open_complete_with_error (task); } static void -qmi_device_open_second_ready (QmiDevice *qmi_device, +qmi_device_open_second_ready (QmiDevice *qmi_device, GAsyncResult *res, - GTask *task) + GTask *task) { + MMPortQmi *self; PortOpenContext *ctx; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - qmi_device_open_finish (qmi_device, res, &ctx->error); + if (qmi_device_open_finish (qmi_device, res, &ctx->error)) { + /* If the open with CTL data format is sucessful, update */ + if (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP) + self->priv->llp_is_raw_ip = TRUE; + else + self->priv->llp_is_raw_ip = FALSE; + } /* In both error and success, we go to last step */ ctx->step = PORT_OPEN_STEP_LAST; @@ -285,28 +334,59 @@ qmi_device_close_to_reopen_ready (QmiDevice *qmi_device, GAsyncResult *res, GTask *task) { + MMPortQmi *self; PortOpenContext *ctx; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!qmi_device_close_finish (qmi_device, res, &ctx->error)) { - mm_warn ("Couldn't close QMI device to reopen it"); + mm_obj_warn (self, "Couldn't close QMI device to reopen it"); ctx->step = PORT_OPEN_STEP_LAST; } else ctx->step++; port_open_step (task); } +static void +set_data_format_ready (QmiClientWda *client, + GAsyncResult *res, + GTask *task) +{ + MMPortQmi *self; + PortOpenContext *ctx; + g_autoptr(QmiMessageWdaSetDataFormatOutput) output = NULL; + g_autoptr(GError) error = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_wda_set_data_format_finish (client, res, &error); + if (!output || !qmi_message_wda_set_data_format_output_get_result (output, &error)) { + mm_obj_warn (self, "Couldn't set data format: %s", error->message); + /* If setting WDA data format fails, fallback to LLP requested via CTL */ + ctx->step = PORT_OPEN_STEP_CLOSE_BEFORE_OPEN_WITH_DATA_FORMAT; + } else { + self->priv->llp_is_raw_ip = TRUE; + ctx->step = PORT_OPEN_STEP_LAST; + } + + port_open_step (task); +} + static void get_data_format_ready (QmiClientWda *client, GAsyncResult *res, - GTask *task) + GTask *task) { - PortOpenContext *ctx; - QmiMessageWdaGetDataFormatOutput *output; - g_autoptr(GError) error = NULL; + MMPortQmi *self; + PortOpenContext *ctx; + g_autoptr(QmiMessageWdaGetDataFormatOutput) output = NULL; + g_autoptr(GError) error = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); - ctx = g_task_get_task_data (task); output = qmi_client_wda_get_data_format_finish (client, res, NULL); if (!output || !qmi_message_wda_get_data_format_output_get_result (output, &error) || @@ -316,7 +396,7 @@ get_data_format_ready (QmiClientWda *client, * When this happens, assume the device supports only raw-ip and be done * with it. */ if (error && g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_MISSING_ARGUMENT)) { - mm_dbg ("Querying data format failed: '%s', assuming raw-ip is only supported", error->message); + mm_obj_dbg (self, "Querying data format failed: '%s', assuming raw-ip is only supported", error->message); ctx->llp = QMI_WDA_LINK_LAYER_PROTOCOL_RAW_IP; ctx->step++; } else { @@ -327,20 +407,18 @@ get_data_format_ready (QmiClientWda *client, /* Go on to next step */ ctx->step++; - if (output) - qmi_message_wda_get_data_format_output_unref (output); - port_open_step (task); } static void -allocate_client_wda_ready (QmiDevice *device, +allocate_client_wda_ready (QmiDevice *device, GAsyncResult *res, - GTask *task) + GTask *task) { PortOpenContext *ctx; ctx = g_task_get_task_data (task); + ctx->wda = qmi_device_allocate_client_finish (device, res, NULL); if (!ctx->wda) { /* If no WDA supported, then we just fallback to reopening explicitly @@ -356,13 +434,14 @@ allocate_client_wda_ready (QmiDevice *device, } static void -qmi_device_open_first_ready (QmiDevice *qmi_device, +qmi_device_open_first_ready (QmiDevice *qmi_device, GAsyncResult *res, - GTask *task) + GTask *task) { PortOpenContext *ctx; ctx = g_task_get_task_data (task); + if (!qmi_device_open_finish (qmi_device, res, &ctx->error)) /* Error opening the device */ ctx->step = PORT_OPEN_STEP_LAST; @@ -399,19 +478,19 @@ qmi_device_new_ready (GObject *unused, static void port_open_step (GTask *task) { - MMPortQmi *self; + MMPortQmi *self; PortOpenContext *ctx; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); switch (ctx->step) { case PORT_OPEN_STEP_FIRST: - mm_dbg ("Opening QMI device..."); + mm_obj_dbg (self, "Opening QMI device..."); ctx->step++; /* Fall through */ case PORT_OPEN_STEP_CHECK_OPENING: - mm_dbg ("Checking if QMI device already opening..."); + mm_obj_dbg (self, "Checking if QMI device already opening..."); if (self->priv->in_progress) { g_task_return_new_error (task, MM_CORE_ERROR, @@ -424,7 +503,7 @@ port_open_step (GTask *task) /* Fall through */ case PORT_OPEN_STEP_CHECK_ALREADY_OPEN: - mm_dbg ("Checking if QMI device already open..."); + mm_obj_dbg (self, "Checking if QMI device already open..."); if (self->priv->qmi_device) { g_task_return_boolean (task, TRUE); g_object_unref (task); @@ -445,7 +524,7 @@ port_open_step (GTask *task) * that all callbacks go through the LAST step for completing. */ self->priv->in_progress = TRUE; - mm_dbg ("Creating QMI device..."); + mm_obj_dbg (self, "Creating QMI device..."); qmi_device_new (file, g_task_get_cancellable (task), (GAsyncReadyCallback) qmi_device_new_ready, @@ -458,32 +537,42 @@ port_open_step (GTask *task) case PORT_OPEN_STEP_OPEN_WITHOUT_DATA_FORMAT: /* Now open the QMI device without any data format CTL flag */ - mm_dbg ("Opening device without data format update..."); + mm_obj_dbg (self, "Opening device without data format update..."); qmi_device_open (ctx->device, (QMI_DEVICE_OPEN_FLAGS_VERSION_INFO | QMI_DEVICE_OPEN_FLAGS_PROXY), - 20, + 45, g_task_get_cancellable (task), (GAsyncReadyCallback) qmi_device_open_first_ready, task); return; case PORT_OPEN_STEP_GET_KERNEL_DATA_FORMAT: - mm_dbg ("Querying kernel data format..."); - /* Try to gather expected data format from the sysfs file */ - ctx->kernel_data_format = qmi_device_get_expected_data_format (ctx->device, NULL); - /* If data format cannot be retrieved, we fallback to 802.3 via CTL */ - if (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN) { - ctx->step = PORT_OPEN_STEP_CLOSE_BEFORE_OPEN_WITH_DATA_FORMAT; - port_open_step (task); - return; + /* Querying kernel data format is only expected when using qmi_wwan */ + if (mm_port_get_subsys (MM_PORT (self)) == MM_PORT_SUBSYS_USBMISC) { + mm_obj_dbg (self, "Querying kernel data format..."); + /* Try to gather expected data format from the sysfs file */ + ctx->kernel_data_format = qmi_device_get_expected_data_format (ctx->device, NULL); + /* If data format cannot be retrieved, we fallback to 802.3 via CTL */ + if (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN) { + ctx->step = PORT_OPEN_STEP_CLOSE_BEFORE_OPEN_WITH_DATA_FORMAT; + port_open_step (task); + return; + } } + /* For any driver other than qmi_wwan, assume raw-ip */ + else { + ctx->kernel_data_format = QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP; + mm_obj_dbg (self, "Assuming default kernel data format: %s", + qmi_device_expected_data_format_get_string (ctx->kernel_data_format)); + } + ctx->step++; /* Fall through */ case PORT_OPEN_STEP_ALLOCATE_WDA_CLIENT: /* Allocate WDA client */ - mm_dbg ("Allocating WDA client..."); + mm_obj_dbg (self, "Allocating WDA client..."); qmi_device_allocate_client (ctx->device, QMI_SERVICE_WDA, QMI_CID_NONE, @@ -495,8 +584,7 @@ port_open_step (GTask *task) case PORT_OPEN_STEP_GET_WDA_DATA_FORMAT: /* If we have WDA client, query current data format */ - g_assert (ctx->wda); - mm_dbg ("Querying device data format..."); + mm_obj_dbg (self, "Querying device data format..."); qmi_client_wda_get_data_format (QMI_CLIENT_WDA (ctx->wda), NULL, 10, @@ -508,9 +596,9 @@ port_open_step (GTask *task) case PORT_OPEN_STEP_CHECK_DATA_FORMAT: /* We now have the WDA data format and the kernel data format, if they're * equal, we're done */ - mm_dbg ("Checking data format: kernel %s, device %s", - qmi_device_expected_data_format_get_string (ctx->kernel_data_format), - qmi_wda_link_layer_protocol_get_string (ctx->llp)); + mm_obj_dbg (self, "Checking data format: kernel %s, device %s", + qmi_device_expected_data_format_get_string (ctx->kernel_data_format), + qmi_wda_link_layer_protocol_get_string (ctx->llp)); if (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3 && ctx->llp == QMI_WDA_LINK_LAYER_PROTOCOL_802_3) { @@ -531,9 +619,27 @@ port_open_step (GTask *task) ctx->step++; /* Fall through */ - case PORT_OPEN_STEP_SET_KERNEL_DATA_FORMAT: - /* Update the data format to be expected by the kernel */ - mm_dbg ("Updating kernel data format: %s", qmi_wda_link_layer_protocol_get_string (ctx->llp)); + case PORT_OPEN_STEP_SYNC_DATA_FORMAT: + /* For drivers other than qmi_wwan, the kernel data format was raw-ip + * by default, we need to ask the module to switch to it */ + if (mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_USBMISC) { + g_autoptr(QmiMessageWdaSetDataFormatInput) input = NULL; + + g_assert (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP); + input = qmi_message_wda_set_data_format_input_new (); + qmi_message_wda_set_data_format_input_set_link_layer_protocol (input, QMI_WDA_LINK_LAYER_PROTOCOL_RAW_IP, NULL); + qmi_client_wda_set_data_format (QMI_CLIENT_WDA (ctx->wda), + input, + 10, + g_task_get_cancellable (task), + (GAsyncReadyCallback) set_data_format_ready, + task); + return; + } + + /* If using the qmi_wwan driver, we ask the kernel to sync with the + * data format requested by the module */ + mm_obj_dbg (self, "Updating kernel data format: %s", qmi_wda_link_layer_protocol_get_string (ctx->llp)); if (ctx->llp == QMI_WDA_LINK_LAYER_PROTOCOL_802_3) { ctx->kernel_data_format = QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3; self->priv->llp_is_raw_ip = FALSE; @@ -552,7 +658,8 @@ port_open_step (GTask *task) return; case PORT_OPEN_STEP_CLOSE_BEFORE_OPEN_WITH_DATA_FORMAT: - mm_dbg ("Closing device to reopen it right away..."); + /* This fallback only applies when WDA unsupported */ + mm_obj_dbg (self, "Closing device to reopen it right away..."); qmi_device_close_async (ctx->device, 5, g_task_get_cancellable (task), @@ -560,23 +667,34 @@ port_open_step (GTask *task) task); return; - case PORT_OPEN_STEP_OPEN_WITH_DATA_FORMAT: - /* Need to reopen setting 802.3 using CTL */ - mm_dbg ("Reopening device with data format..."); + case PORT_OPEN_STEP_OPEN_WITH_DATA_FORMAT: { + QmiDeviceOpenFlags open_flags; + + /* Common open flags */ + open_flags = (QMI_DEVICE_OPEN_FLAGS_VERSION_INFO | + QMI_DEVICE_OPEN_FLAGS_PROXY | + QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER); + + /* Need to reopen setting 802.3/raw-ip using CTL */ + if (ctx->kernel_data_format == QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP) + open_flags |= QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP; + else + open_flags |= QMI_DEVICE_OPEN_FLAGS_NET_802_3; + + mm_obj_dbg (self, "Reopening device with data format: %s...", + qmi_device_expected_data_format_get_string (ctx->kernel_data_format)); qmi_device_open (ctx->device, - (QMI_DEVICE_OPEN_FLAGS_VERSION_INFO | - QMI_DEVICE_OPEN_FLAGS_PROXY | - QMI_DEVICE_OPEN_FLAGS_NET_802_3 | - QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER), + open_flags, 10, g_task_get_cancellable (task), (GAsyncReadyCallback) qmi_device_open_second_ready, task); return; + } case PORT_OPEN_STEP_LAST: if (ctx->error) { - mm_dbg ("QMI port open operation failed: %s", ctx->error->message); + mm_obj_dbg (self, "QMI port open operation failed: %s", ctx->error->message); if (ctx->device) { qmi_device_close_async (ctx->device, @@ -591,7 +709,7 @@ port_open_step (GTask *task) return; } - mm_dbg ("QMI port open operation finished successfully"); + mm_obj_dbg (self, "QMI port open operation finished successfully"); /* Store device in private info */ g_assert (ctx->device); @@ -608,26 +726,23 @@ port_open_step (GTask *task) } void -mm_port_qmi_open (MMPortQmi *self, - gboolean set_data_format, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +mm_port_qmi_open (MMPortQmi *self, + gboolean set_data_format, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { PortOpenContext *ctx; - GTask *task; - - g_return_if_fail (MM_IS_PORT_QMI (self)); + GTask *task; ctx = g_slice_new0 (PortOpenContext); ctx->step = PORT_OPEN_STEP_FIRST; ctx->set_data_format = set_data_format; - ctx->kernel_data_format = QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN; ctx->llp = QMI_WDA_LINK_LAYER_PROTOCOL_UNKNOWN; + ctx->kernel_data_format = QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN; task = g_task_new (self, cancellable, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)port_open_context_free); - port_open_step (task); } @@ -721,7 +836,7 @@ mm_port_qmi_close (MMPortQmi *self, for (l = self->priv->services; l; l = g_list_next (l)) { ServiceInfo *info = l->data; - mm_dbg ("Releasing client for service '%s'...", qmi_service_get_string (info->service)); + mm_obj_dbg (self, "Releasing client for service '%s'...", qmi_service_get_string (info->service)); qmi_device_release_client (ctx->qmi_device, info->client, QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID, @@ -741,11 +856,12 @@ mm_port_qmi_close (MMPortQmi *self, /*****************************************************************************/ MMPortQmi * -mm_port_qmi_new (const gchar *name) +mm_port_qmi_new (const gchar *name, + MMPortSubsys subsys) { return MM_PORT_QMI (g_object_new (MM_TYPE_PORT_QMI, MM_PORT_DEVICE, name, - MM_PORT_SUBSYS, MM_PORT_SUBSYS_USB, + MM_PORT_SUBSYS, subsys, MM_PORT_TYPE, MM_PORT_TYPE_QMI, NULL)); } diff --git a/src/mm-port-qmi.h b/src/mm-port-qmi.h index f8ea9eec..986b3b7d 100644 --- a/src/mm-port-qmi.h +++ b/src/mm-port-qmi.h @@ -45,24 +45,25 @@ struct _MMPortQmiClass { }; GType mm_port_qmi_get_type (void); - -MMPortQmi *mm_port_qmi_new (const gchar *name); - -void mm_port_qmi_open (MMPortQmi *self, - gboolean set_data_format, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_port_qmi_open_finish (MMPortQmi *self, - GAsyncResult *res, - GError **error); -gboolean mm_port_qmi_is_open (MMPortQmi *self); -void mm_port_qmi_close (MMPortQmi *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_port_qmi_close_finish (MMPortQmi *self, - GAsyncResult *res, - GError **error); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortQmi, g_object_unref) + +MMPortQmi *mm_port_qmi_new (const gchar *name, + MMPortSubsys subsys); +void mm_port_qmi_open (MMPortQmi *self, + gboolean set_data_format, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_port_qmi_open_finish (MMPortQmi *self, + GAsyncResult *res, + GError **error); +gboolean mm_port_qmi_is_open (MMPortQmi *self); +void mm_port_qmi_close (MMPortQmi *self, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_port_qmi_close_finish (MMPortQmi *self, + GAsyncResult *res, + GError **error); typedef enum { MM_PORT_QMI_FLAG_DEFAULT = 0, @@ -80,6 +81,10 @@ gboolean mm_port_qmi_allocate_client_finish (MMPortQmi *self, GAsyncResult *res, GError **error); +void mm_port_qmi_release_client (MMPortQmi *self, + QmiService service, + MMPortQmiFlag flag); + QmiClient *mm_port_qmi_peek_client (MMPortQmi *self, QmiService service, MMPortQmiFlag flag); diff --git a/src/mm-port-serial-at.c b/src/mm-port-serial-at.c index 67525af0..44c0fc92 100644 --- a/src/mm-port-serial-at.c +++ b/src/mm-port-serial-at.c @@ -22,7 +22,7 @@ #include #include "mm-port-serial-at.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMPortSerialAt, mm_port_serial_at, MM_TYPE_PORT_SERIAL) @@ -148,7 +148,7 @@ parse_response (MMPortSerial *port, /* Parse it; returns FALSE if there is nothing we can do with this * response yet. */ - if (!self->priv->response_parser_fn (self->priv->response_parser_user_data, string, &inner_error)) { + if (!self->priv->response_parser_fn (self->priv->response_parser_user_data, string, self, &inner_error)) { /* Copy what we got back in the response buffer. */ g_byte_array_append (response, (const guint8 *) string->str, string->len); g_string_free (string, TRUE); @@ -435,10 +435,13 @@ mm_port_serial_at_command (MMPortSerialAt *self, } static void -debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) +debug_log (MMPortSerial *self, + const gchar *prefix, + const gchar *buf, + gsize len) { static GString *debug = NULL; - const char *s; + const char *s; if (!debug) debug = g_string_sized_new (256); @@ -461,7 +464,7 @@ debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) } g_string_append_c (debug, '\''); - mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str); + mm_obj_dbg (self, "%s", debug->str); g_string_truncate (debug, 0); } @@ -470,6 +473,8 @@ mm_port_serial_at_set_flags (MMPortSerialAt *self, MMPortSerialAtFlag flags) { g_return_if_fail (self != NULL); g_return_if_fail (MM_IS_PORT_SERIAL_AT (self)); + + /* MM_PORT_SERIAL_AT_FLAG_NONE_NO_GENERIC is not expected */ g_return_if_fail (flags <= (MM_PORT_SERIAL_AT_FLAG_PRIMARY | MM_PORT_SERIAL_AT_FLAG_SECONDARY | MM_PORT_SERIAL_AT_FLAG_PPP | @@ -497,7 +502,7 @@ mm_port_serial_at_run_init_sequence (MMPortSerialAt *self) if (!self->priv->init_sequence) return; - mm_dbg ("(%s): running init sequence...", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "running init sequence..."); /* Just queue the init commands, don't wait for reply */ for (i = 0; self->priv->init_sequence[i]; i++) { @@ -524,17 +529,13 @@ config (MMPortSerial *_self) /*****************************************************************************/ MMPortSerialAt * -mm_port_serial_at_new (const char *name, - MMPortSubsys subsys) +mm_port_serial_at_new (const char *name, + MMPortSubsys subsys) { - g_return_val_if_fail (subsys == MM_PORT_SUBSYS_TTY || - subsys == MM_PORT_SUBSYS_USB || - subsys == MM_PORT_SUBSYS_UNIX, NULL); - return MM_PORT_SERIAL_AT (g_object_new (MM_TYPE_PORT_SERIAL_AT, MM_PORT_DEVICE, name, MM_PORT_SUBSYS, subsys, - MM_PORT_TYPE, MM_PORT_TYPE_AT, + MM_PORT_TYPE, MM_PORT_TYPE_AT, NULL)); } diff --git a/src/mm-port-serial-at.h b/src/mm-port-serial-at.h index 8e19409e..901afcba 100644 --- a/src/mm-port-serial-at.h +++ b/src/mm-port-serial-at.h @@ -42,20 +42,24 @@ typedef struct _MMPortSerialAtPrivate MMPortSerialAtPrivate; * only when connecting is port 0 opened for dialing (ATD) and PPP */ typedef enum { /*< underscore_name=mm_port_serial_at_flag >*/ - MM_PORT_SERIAL_AT_FLAG_NONE = 0, + MM_PORT_SERIAL_AT_FLAG_NONE = 0, /* This port is preferred for command and status */ - MM_PORT_SERIAL_AT_FLAG_PRIMARY = 1 << 0, + MM_PORT_SERIAL_AT_FLAG_PRIMARY = 1 << 0, /* Use port for command and status if the primary port is connected */ - MM_PORT_SERIAL_AT_FLAG_SECONDARY = 1 << 1, + MM_PORT_SERIAL_AT_FLAG_SECONDARY = 1 << 1, /* This port should be used for PPP */ - MM_PORT_SERIAL_AT_FLAG_PPP = 1 << 2, + MM_PORT_SERIAL_AT_FLAG_PPP = 1 << 2, /* This port should be used for GPS control */ - MM_PORT_SERIAL_AT_FLAG_GPS_CONTROL = 1 << 3, + MM_PORT_SERIAL_AT_FLAG_GPS_CONTROL = 1 << 3, + /* Helper flag to allow plugins specify that generic tags shouldn't be + * applied */ + MM_PORT_SERIAL_AT_FLAG_NONE_NO_GENERIC = 1 << 4, } MMPortSerialAtFlag; -typedef gboolean (*MMPortSerialAtResponseParserFn) (gpointer user_data, - GString *response, - GError **error); +typedef gboolean (*MMPortSerialAtResponseParserFn) (gpointer user_data, + GString *response, + gpointer log_object, + GError **error); typedef void (*MMPortSerialAtUnsolicitedMsgFn) (MMPortSerialAt *port, GMatchInfo *match_info, @@ -76,6 +80,7 @@ struct _MMPortSerialAtClass { }; GType mm_port_serial_at_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortSerialAt, g_object_unref) MMPortSerialAt *mm_port_serial_at_new (const char *name, MMPortSubsys subsys); diff --git a/src/mm-port-serial-gps.c b/src/mm-port-serial-gps.c index b316d05e..ea404994 100644 --- a/src/mm-port-serial-gps.c +++ b/src/mm-port-serial-gps.c @@ -19,7 +19,7 @@ #include #include "mm-port-serial-gps.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMPortSerialGps, mm_port_serial_gps, MM_TYPE_PORT_SERIAL) @@ -135,10 +135,13 @@ parse_response (MMPortSerial *port, /*****************************************************************************/ static void -debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) +debug_log (MMPortSerial *self, + const gchar *prefix, + const gchar *buf, + gsize len) { static GString *debug = NULL; - const char *s; + const gchar *s; if (!debug) debug = g_string_sized_new (256); @@ -161,7 +164,7 @@ debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) } g_string_append_c (debug, '\''); - mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str); + mm_obj_dbg (self, "%s", debug->str); g_string_truncate (debug, 0); } diff --git a/src/mm-port-serial-gps.h b/src/mm-port-serial-gps.h index 5655b5e3..ad5a97fc 100644 --- a/src/mm-port-serial-gps.h +++ b/src/mm-port-serial-gps.h @@ -46,6 +46,7 @@ struct _MMPortSerialGpsClass { }; GType mm_port_serial_gps_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortSerialGps, g_object_unref) MMPortSerialGps *mm_port_serial_gps_new (const char *name); diff --git a/src/mm-port-serial-qcdm.c b/src/mm-port-serial-qcdm.c index e723204b..08f24303 100644 --- a/src/mm-port-serial-qcdm.c +++ b/src/mm-port-serial-qcdm.c @@ -27,7 +27,7 @@ #include "libqcdm/src/utils.h" #include "libqcdm/src/errors.h" #include "libqcdm/src/dm-commands.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMPortSerialQcdm, mm_port_serial_qcdm, MM_TYPE_PORT_SERIAL) @@ -206,10 +206,13 @@ mm_port_serial_qcdm_command (MMPortSerialQcdm *self, } static void -debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) +debug_log (MMPortSerial *self, + const gchar *prefix, + const gchar *buf, + gsize len) { static GString *debug = NULL; - const char *s = buf; + const gchar *s = buf; if (!debug) debug = g_string_sized_new (512); @@ -219,7 +222,7 @@ debug_log (MMPortSerial *port, const char *prefix, const char *buf, gsize len) while (len--) g_string_append_printf (debug, " %02x", (guint8) (*s++ & 0xFF)); - mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str); + mm_obj_dbg (self, "%s", debug->str); g_string_truncate (debug, 0); } @@ -347,11 +350,12 @@ config_fd (MMPortSerial *port, int fd, GError **error) /*****************************************************************************/ MMPortSerialQcdm * -mm_port_serial_qcdm_new (const char *name) +mm_port_serial_qcdm_new (const char *name, + MMPortSubsys subsys) { return MM_PORT_SERIAL_QCDM (g_object_new (MM_TYPE_PORT_SERIAL_QCDM, MM_PORT_DEVICE, name, - MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY, + MM_PORT_SUBSYS, subsys, MM_PORT_TYPE, MM_PORT_TYPE_QCDM, MM_PORT_SERIAL_SEND_DELAY, (guint64) 0, NULL)); diff --git a/src/mm-port-serial-qcdm.h b/src/mm-port-serial-qcdm.h index e7ba01fe..85668a49 100644 --- a/src/mm-port-serial-qcdm.h +++ b/src/mm-port-serial-qcdm.h @@ -43,8 +43,10 @@ struct _MMPortSerialQcdmClass { }; GType mm_port_serial_qcdm_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortSerialQcdm, g_object_unref) -MMPortSerialQcdm *mm_port_serial_qcdm_new (const char *name); +MMPortSerialQcdm *mm_port_serial_qcdm_new (const char *name, + MMPortSubsys subsys); MMPortSerialQcdm *mm_port_serial_qcdm_new_fd (int fd); void mm_port_serial_qcdm_command (MMPortSerialQcdm *self, diff --git a/src/mm-port-serial.c b/src/mm-port-serial.c index 5e8db484..b4ba6533 100644 --- a/src/mm-port-serial.c +++ b/src/mm-port-serial.c @@ -34,7 +34,7 @@ #include #include "mm-port-serial.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-helper-enums-types.h" static gboolean port_serial_queue_process (gpointer data); @@ -290,7 +290,7 @@ parse_baudrate (guint baudrate_num, static int parse_bits (guint i) { - int bits; + int bits = -1; switch (i) { case 5: @@ -306,8 +306,7 @@ parse_bits (guint i) bits = CS8; break; default: - mm_warn ("Invalid bits (%d). Valid values are 5, 6, 7, 8.", i); - bits = CS8; + g_assert_not_reached (); } return bits; @@ -316,7 +315,7 @@ parse_bits (guint i) static int parse_parity (char c) { - int parity; + int parity = -1; switch (c) { case 'n': @@ -332,8 +331,7 @@ parse_parity (char c) parity = PARENB | PARODD; break; default: - mm_warn ("Invalid parity (%c). Valid values are n, e, o", c); - parity = 0; + g_assert_not_reached (); } return parity; @@ -342,7 +340,7 @@ parse_parity (char c) static int parse_stopbits (guint i) { - int stopbits; + int stopbits = -1; switch (i) { case 1: @@ -352,8 +350,7 @@ parse_stopbits (guint i) stopbits = CSTOPB; break; default: - mm_warn ("Invalid stop bits (%d). Valid values are 1 and 2)", i); - stopbits = 0; + g_assert_not_reached (); } return stopbits; @@ -401,11 +398,9 @@ internal_tcsetattr (MMPortSerial *self, memset (&other, 0, sizeof (struct termios)); errno = 0; if (tcgetattr (fd, &other) != 0) - mm_dbg ("(%s): couldn't get serial port attributes after setting them: %s", - mm_port_get_device (MM_PORT (self)), g_strerror (errno)); + mm_obj_dbg (self, "couldn't get serial port attributes after setting them: %s", g_strerror (errno)); else if (memcmp (options, &other, sizeof (struct termios)) != 0) - mm_dbg ("(%s): port attributes not fully set", - mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "port attributes not fully set"); #undef MAX_TCSETATTR_RETRIES @@ -433,19 +428,19 @@ set_flow_control_termios (MMPortSerial *self, /* setup the requested flags */ switch (flow_control) { case MM_FLOW_CONTROL_XON_XOFF: - mm_dbg ("(%s): enabling XON/XOFF flow control", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "enabling XON/XOFF flow control"); options->c_iflag |= (IXON | IXOFF | IXANY); break; case MM_FLOW_CONTROL_RTS_CTS: - mm_dbg ("(%s): enabling RTS/CTS flow control", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "enabling RTS/CTS flow control"); options->c_cflag |= (CRTSCTS); break; case MM_FLOW_CONTROL_NONE: case MM_FLOW_CONTROL_UNKNOWN: if (had_xon_xoff) - mm_dbg ("(%s): disabling XON/XOFF flow control", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "disabling XON/XOFF flow control"); if (had_rts_cts) - mm_dbg ("(%s): disabling RTS/CTS flow control", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "disabling RTS/CTS flow control"); break; default: g_assert_not_reached (); @@ -467,13 +462,9 @@ real_config_fd (MMPortSerial *self, int fd, GError **error) if (mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_TTY) return TRUE; - mm_dbg ("(%s): setting up baudrate: %u", - mm_port_get_device (MM_PORT (self)), - self->priv->baud); + mm_obj_dbg (self, "setting up baudrate: %u", self->priv->baud); if (!parse_baudrate (self->priv->baud, &speed) || speed == B0) { - mm_warn ("(%s): baudrate invalid: %u; defaulting to 57600", - mm_port_get_device (MM_PORT (self)), - self->priv->baud); + mm_obj_warn (self, "baudrate invalid: %u; defaulting to 57600", self->priv->baud); speed = B57600; } @@ -482,11 +473,8 @@ real_config_fd (MMPortSerial *self, int fd, GError **error) stopbits = parse_stopbits (self->priv->stopbits); memset (&stbuf, 0, sizeof (struct termios)); - if (tcgetattr (fd, &stbuf) != 0) { - mm_warn ("(%s): tcgetattr() error: %d", - mm_port_get_device (MM_PORT (self)), - errno); - } + if (tcgetattr (fd, &stbuf) != 0) + mm_obj_warn (self, "error getting serial port attributes: %s", g_strerror (errno)); stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS); stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXOFF | IXANY ); @@ -526,13 +514,10 @@ real_config_fd (MMPortSerial *self, int fd, GError **error) gchar *str; str = mm_flow_control_build_string_from_mask (self->priv->flow_control); - mm_dbg ("(%s): flow control explicitly requested for device is: %s", - mm_port_get_device (MM_PORT (self)), - str ? str : "unknown"); + mm_obj_dbg (self, "flow control explicitly requested for device is: %s", str ? str : "unknown"); g_free (str); } else - mm_dbg ("(%s): no flow control explicitly requested for device", - mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "no flow control explicitly requested for device"); set_flow_control_termios (self, self->priv->flow_control, &stbuf); @@ -540,7 +525,10 @@ real_config_fd (MMPortSerial *self, int fd, GError **error) } static void -serial_debug (MMPortSerial *self, const char *prefix, const char *buf, gsize len) +serial_debug (MMPortSerial *self, + const gchar *prefix, + const gchar *buf, + gsize len) { g_return_if_fail (len > 0); @@ -572,7 +560,7 @@ port_serial_process_command (MMPortSerial *self, /* Only print command the first time */ if (ctx->started == FALSE) { ctx->started = TRUE; - serial_debug (self, "-->", (const char *) ctx->command->data, ctx->command->len); + serial_debug (self, "-->", (const gchar *) ctx->command->data, ctx->command->len); } if (self->priv->send_delay == 0 || mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_TTY) { @@ -619,7 +607,7 @@ port_serial_process_command (MMPortSerial *self, g_signal_emit (self, signals[TIMED_OUT], 0, self->priv->n_consecutive_timeouts); g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED, - "Sending command failed: '%s'", strerror (errno)); + "Sending command failed: '%s'", g_strerror (errno)); return FALSE; } break; @@ -654,7 +642,7 @@ port_serial_process_command (MMPortSerial *self, self->priv->n_consecutive_timeouts++; g_signal_emit (self, signals[TIMED_OUT], 0, self->priv->n_consecutive_timeouts); g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_SEND_FAILED, - "Sending command failed: '%s'", strerror (errno)); + "Sending command failed: '%s'", g_strerror (errno)); return FALSE; } @@ -962,15 +950,12 @@ common_input_available (MMPortSerial *self, gsize bytes_read; GIOStatus status = G_IO_STATUS_NORMAL; CommandContext *ctx; - const char *device; GError *error = NULL; gboolean iterate = TRUE; gboolean keep_source = G_SOURCE_CONTINUE; if (condition & G_IO_HUP) { - device = mm_port_get_device (MM_PORT (self)); - mm_dbg ("(%s) unexpected port hangup!", device); - + mm_obj_dbg (self, "unexpected port hangup!"); if (self->priv->response->len) g_byte_array_remove_range (self->priv->response, 0, self->priv->response->len); port_serial_close_force (self); @@ -998,11 +983,8 @@ common_input_available (MMPortSerial *self, &bytes_read, &error); if (status == G_IO_STATUS_ERROR) { - if (error) { - mm_warn ("(%s): read error: %s", - mm_port_get_device (MM_PORT (self)), - error->message); - } + if (error) + mm_obj_warn (self, "read error: %s", error->message); g_clear_error (&error); } } else if (self->priv->socket) { @@ -1019,9 +1001,7 @@ common_input_available (MMPortSerial *self, status = G_IO_STATUS_AGAIN; else status = G_IO_STATUS_ERROR; - mm_warn ("(%s): receive error: %s", - mm_port_get_device (MM_PORT (self)), - error->message); + mm_obj_warn (self, "receive error: %s", error->message); g_clear_error (&error); } else { bytes_read = (gsize) sbytes_read; @@ -1140,11 +1120,9 @@ port_connected (MMPortSerial *self, GParamSpec *pspec, gpointer user_data) connected = mm_port_get_connected (MM_PORT (self)); if (self->priv->fd >= 0 && ioctl (self->priv->fd, (connected ? TIOCNXCL : TIOCEXCL)) < 0) { - mm_warn ("(%s): could not %s serial port lock: (%d) %s", - mm_port_get_device (MM_PORT (self)), - connected ? "drop" : "re-acquire", - errno, - strerror (errno)); + mm_obj_warn (self, "could not %s serial port lock: %s", + connected ? "drop" : "re-acquire", + g_strerror (errno)); if (!connected) { // FIXME: do something here, maybe try again in a few seconds or // close the port and error out? @@ -1200,7 +1178,7 @@ mm_port_serial_open (MMPortSerial *self, GError **error) goto success; } - mm_dbg ("(%s) opening serial port...", device); + mm_obj_dbg (self, "opening serial port..."); g_get_current_time (&tv_start); @@ -1224,7 +1202,6 @@ mm_port_serial_open (MMPortSerial *self, GError **error) MM_SERIAL_ERROR, (errno == ENODEV) ? MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE : MM_SERIAL_ERROR_OPEN_FAILED, "Could not open serial device %s: %s", device, strerror (errno_save)); - mm_warn ("(%s) could not open serial device (%d)", device, errno_save); return FALSE; } } @@ -1236,7 +1213,6 @@ mm_port_serial_open (MMPortSerial *self, GError **error) errno_save = errno; g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "Could not lock serial device %s: %s", device, strerror (errno_save)); - mm_warn ("(%s) could not lock serial device (%d)", device, errno_save); goto error; } @@ -1250,21 +1226,20 @@ mm_port_serial_open (MMPortSerial *self, GError **error) if (ioctl (self->priv->fd, TIOCGSERIAL, &sinfo) == 0) { sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE; if (ioctl (self->priv->fd, TIOCSSERIAL, &sinfo) < 0) - mm_warn ("(%s): couldn't set serial port closing_wait to none: %s", - device, g_strerror (errno)); + mm_obj_warn (self, "couldn't set serial port closing_wait to none: %s", g_strerror (errno)); } } g_warn_if_fail (MM_PORT_SERIAL_GET_CLASS (self)->config_fd); if (self->priv->fd >= 0 && !MM_PORT_SERIAL_GET_CLASS (self)->config_fd (self, self->priv->fd, error)) { - mm_dbg ("(%s) failed to configure serial device", device); + mm_obj_dbg (self, "failed to configure serial device"); goto error; } g_get_current_time (&tv_end); if (tv_end.tv_sec - tv_start.tv_sec > 7) - mm_warn ("(%s): open blocked by driver for more than 7 seconds!", device); + mm_obj_warn (self, "open blocked by driver for more than 7 seconds!"); if (mm_port_get_subsys (MM_PORT (self)) != MM_PORT_SUBSYS_UNIX) { /* Create new GIOChannel */ @@ -1330,7 +1305,7 @@ mm_port_serial_open (MMPortSerial *self, GError **error) success: self->priv->open_count++; - mm_dbg ("(%s) device open count is %d (open)", device, self->priv->open_count); + mm_obj_dbg (self, "device open count is %d (open)", self->priv->open_count); /* Run additional port config if just opened */ if (self->priv->open_count == 1 && MM_PORT_SERIAL_GET_CLASS (self)->config) @@ -1339,7 +1314,7 @@ mm_port_serial_open (MMPortSerial *self, GError **error) return TRUE; error: - mm_warn ("(%s) failed to open serial device", device); + mm_obj_warn (self, "failed to open serial device"); if (self->priv->iochannel) { g_io_channel_unref (self->priv->iochannel); @@ -1372,8 +1347,7 @@ mm_port_serial_is_open (MMPortSerial *self) static void _close_internal (MMPortSerial *self, gboolean force) { - const char *device; - guint i; + guint i; g_return_if_fail (MM_IS_PORT_SERIAL (self)); @@ -1384,9 +1358,7 @@ _close_internal (MMPortSerial *self, gboolean force) self->priv->open_count--; } - device = mm_port_get_device (MM_PORT (self)); - - mm_dbg ("(%s) device open count is %d (close)", device, self->priv->open_count); + mm_obj_dbg (self, "device open count is %d (close)", self->priv->open_count); if (self->priv->open_count > 0) return; @@ -1405,7 +1377,7 @@ _close_internal (MMPortSerial *self, gboolean force) GTimeVal tv_start, tv_end; struct serial_struct sinfo = { 0 }; - mm_dbg ("(%s) closing serial port...", device); + mm_obj_dbg (self, "closing serial port..."); mm_port_set_connected (MM_PORT (self), FALSE); @@ -1418,11 +1390,10 @@ _close_internal (MMPortSerial *self, gboolean force) */ if (ioctl (self->priv->fd, TIOCGSERIAL, &sinfo) == 0) { if (sinfo.closing_wait != ASYNC_CLOSING_WAIT_NONE) { - mm_warn ("(%s): serial port closing_wait was reset!", device); + mm_obj_warn (self, "serial port closing_wait was reset!"); sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE; if (ioctl (self->priv->fd, TIOCSSERIAL, &sinfo) < 0) - mm_warn ("(%s): couldn't set serial port closing_wait to none: %s", - device, g_strerror (errno)); + mm_obj_warn (self, "couldn't set serial port closing_wait to none: %s", g_strerror (errno)); } } @@ -1455,7 +1426,7 @@ _close_internal (MMPortSerial *self, gboolean force) g_get_current_time (&tv_end); - mm_dbg ("(%s) serial port closed", device); + mm_obj_dbg (self, "serial port closed"); /* Some ports don't respond to data and when close is called * the serial layer waits up to 30 second (closing_wait) for @@ -1463,7 +1434,7 @@ _close_internal (MMPortSerial *self, gboolean force) * Log that. See GNOME bug #630670 for more details. */ if (tv_end.tv_sec - tv_start.tv_sec > 7) - mm_warn ("(%s): close blocked by driver for more than 7 seconds!", device); + mm_obj_warn (self, "close blocked by driver for more than 7 seconds!"); } /* Clear the command queue */ @@ -1517,7 +1488,7 @@ port_serial_close_force (MMPortSerial *self) if (self->priv->forced_close) return; - mm_dbg ("(%s) forced to close port", mm_port_get_device (MM_PORT (self))); + mm_obj_dbg (self, "forced to close port"); /* Mark as having forced the close, so that we don't warn about incorrect * open counts */ @@ -1654,9 +1625,7 @@ mm_port_serial_reopen (MMPortSerial *self, return; } - mm_dbg ("(%s) reopening port (%u)", - mm_port_get_device (MM_PORT (self)), - ctx->initial_open_count); + mm_obj_dbg (self, "reopening port (%u)", ctx->initial_open_count); for (i = 0; i < ctx->initial_open_count; i++) mm_port_serial_close (self); @@ -1899,16 +1868,14 @@ mm_port_serial_set_flow_control (MMPortSerial *self, /* Return if current settings are already what we want */ if (!set_flow_control_termios (self, flow_control, &options)) { - mm_dbg ("(%s): no need to change flow control settings: already %s", - mm_port_get_device (MM_PORT (self)), flow_control_str); + mm_obj_dbg (self, "no need to change flow control settings: already %s", flow_control_str); goto out; } if (!internal_tcsetattr (self, self->priv->fd, &options, &inner_error)) goto out; - mm_dbg ("(%s): flow control settings updated to %s", - mm_port_get_device (MM_PORT (self)), flow_control_str); + mm_obj_dbg (self, "flow control settings updated to %s", flow_control_str); out: g_free (flow_control_str); diff --git a/src/mm-port-serial.h b/src/mm-port-serial.h index b30bad77..5ad17c2e 100644 --- a/src/mm-port-serial.h +++ b/src/mm-port-serial.h @@ -93,12 +93,12 @@ struct _MMPortSerialClass { /* Called to configure the serial port after it's opened. Errors, if any, * should get ignored. */ - void (*config) (MMPortSerial *self); + void (*config) (MMPortSerial *self); void (*debug_log) (MMPortSerial *self, - const char *prefix, - const char *buf, - gsize len); + const gchar *prefix, + const gchar *buf, + gsize len); /* Signals */ void (*buffer_full) (MMPortSerial *port, const GByteArray *buffer); @@ -107,6 +107,7 @@ struct _MMPortSerialClass { }; GType mm_port_serial_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortSerial, g_object_unref) MMPortSerial *mm_port_serial_new (const char *name, MMPortType ptype); diff --git a/src/mm-port.c b/src/mm-port.c index 0156f6e7..285c89a7 100644 --- a/src/mm-port.c +++ b/src/mm-port.c @@ -19,9 +19,13 @@ #include #include "mm-port.h" -#include "mm-log.h" +#include "mm-port-enums-types.h" +#include "mm-log-object.h" -G_DEFINE_TYPE (MMPort, mm_port, G_TYPE_OBJECT) +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMPort, mm_port, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -88,10 +92,7 @@ mm_port_set_connected (MMPort *self, gboolean connected) if (self->priv->connected != connected) { self->priv->connected = connected; g_object_notify (G_OBJECT (self), MM_PORT_CONNECTED); - - mm_dbg ("(%s): port now %s", - self->priv->device, - connected ? "connected" : "disconnected"); + mm_obj_dbg (self, "port now %s", connected ? "connected" : "disconnected"); } } @@ -105,6 +106,19 @@ mm_port_peek_kernel_device (MMPort *self) /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + MMPort *self; + + self = MM_PORT (_self); + return g_strdup_printf ("%s/%s", + mm_port_get_device (self), + mm_port_type_get_string (mm_port_get_port_type (self))); +} + +/*****************************************************************************/ + static void mm_port_init (MMPort *self) { @@ -194,6 +208,12 @@ dispose (GObject *object) G_OBJECT_CLASS (mm_port_parent_class)->dispose (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_port_class_init (MMPortClass *klass) { diff --git a/src/mm-port.h b/src/mm-port.h index 33b07d97..3fe920cc 100644 --- a/src/mm-port.h +++ b/src/mm-port.h @@ -26,10 +26,11 @@ typedef enum { /*< underscore_name=mm_port_subsys >*/ MM_PORT_SUBSYS_UNKNOWN = 0x0, MM_PORT_SUBSYS_TTY, MM_PORT_SUBSYS_NET, - MM_PORT_SUBSYS_USB, + MM_PORT_SUBSYS_USBMISC, MM_PORT_SUBSYS_UNIX, - - MM_PORT_SUBSYS_LAST = MM_PORT_SUBSYS_UNIX /*< skip >*/ + MM_PORT_SUBSYS_RPMSG, + MM_PORT_SUBSYS_WWAN, + MM_PORT_SUBSYS_LAST = MM_PORT_SUBSYS_WWAN /*< skip >*/ } MMPortSubsys; typedef enum { /*< underscore_name=mm_port_type >*/ @@ -72,6 +73,7 @@ struct _MMPortClass { }; GType mm_port_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPort, g_object_unref) const gchar *mm_port_get_device (MMPort *self); MMPortSubsys mm_port_get_subsys (MMPort *self); diff --git a/src/mm-private-boxed-types.c b/src/mm-private-boxed-types.c index 465649b5..1c510bb8 100644 --- a/src/mm-private-boxed-types.c +++ b/src/mm-private-boxed-types.c @@ -37,18 +37,18 @@ uint16_array_copy (guint16 *array) GType mm_uint16_array_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("MMUint16Array"), (GBoxedCopyFunc) uint16_array_copy, (GBoxedFreeFunc) g_free); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } static mm_uint16_pair * @@ -72,18 +72,18 @@ uint16_pair_array_copy (mm_uint16_pair *array) GType mm_uint16_pair_array_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("MMUint16PairArray"), (GBoxedCopyFunc) uint16_pair_array_copy, (GBoxedFreeFunc) g_free); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } static void @@ -122,18 +122,18 @@ str_pair_array_copy (mm_str_pair *array) GType mm_str_pair_array_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("MMStrPairArray"), (GBoxedCopyFunc) str_pair_array_copy, (GBoxedFreeFunc) str_pair_array_free); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } static gpointer * @@ -157,18 +157,47 @@ pointer_array_copy (gpointer *array) GType mm_pointer_array_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("MMPointerArray"), (GBoxedCopyFunc) pointer_array_copy, (GBoxedFreeFunc) g_free); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; +} + +static GPtrArray * +object_array_copy (GPtrArray *object_array) +{ + return g_ptr_array_ref (object_array); +} + +static void +object_array_free (GPtrArray *object_array) +{ + g_ptr_array_unref (object_array); +} + +GType +mm_object_array_get_type (void) +{ + static gsize g_define_type_id_initialized = 0; + + if (g_once_init_enter (&g_define_type_id_initialized)) { + GType g_define_type_id = + g_boxed_type_register_static (g_intern_static_string ("MMObjectArray"), + (GBoxedCopyFunc) object_array_copy, + (GBoxedFreeFunc) object_array_free); + + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); + } + + return g_define_type_id_initialized; } static void @@ -194,16 +223,16 @@ async_method_copy (MMAsyncMethod *original) GType mm_async_method_get_type (void) { - static volatile gsize g_define_type_id__volatile = 0; + static gsize g_define_type_id_initialized = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { + if (g_once_init_enter (&g_define_type_id_initialized)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("MMAsyncMethod"), (GBoxedCopyFunc) async_method_copy, (GBoxedFreeFunc) async_method_free); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + g_once_init_leave (&g_define_type_id_initialized, g_define_type_id); } - return g_define_type_id__volatile; + return g_define_type_id_initialized; } diff --git a/src/mm-private-boxed-types.h b/src/mm-private-boxed-types.h index fcdcbb10..8a7d5fcb 100644 --- a/src/mm-private-boxed-types.h +++ b/src/mm-private-boxed-types.h @@ -34,6 +34,9 @@ GType mm_str_pair_array_get_type (void) G_GNUC_CONST; GType mm_pointer_array_get_type (void) G_GNUC_CONST; #define MM_TYPE_POINTER_ARRAY (mm_pointer_array_get_type ()) +GType mm_object_array_get_type (void) G_GNUC_CONST; +#define MM_TYPE_OBJECT_ARRAY (mm_object_array_get_type ()) + typedef struct { GCallback async; GCallback finish; diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c index b7bb3087..0b60d607 100644 --- a/src/mm-serial-parsers.c +++ b/src/mm-serial-parsers.c @@ -19,7 +19,7 @@ #include "mm-error-helpers.h" #include "mm-serial-parsers.h" -#include "mm-log.h" +#include "mm-log-object.h" /* Clean up the response by removing control characters like etc */ static void @@ -108,16 +108,16 @@ mm_serial_parser_v1_new (void) parser = g_slice_new (MMSerialParserV1); - parser->regex_ok = g_regex_new ("\\r\\nOK(\\r\\n)+$", flags, 0, NULL); + parser->regex_ok = g_regex_new ("\\r\\nOK(\\r\\n)+", flags, 0, NULL); parser->regex_connect = g_regex_new ("\\r\\nCONNECT.*\\r\\n", flags, 0, NULL); parser->regex_sms = g_regex_new ("\\r\\n>\\s*$", flags, 0, NULL); - parser->regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); - parser->regex_cms_error = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); - parser->regex_cme_error_str = g_regex_new ("\\r\\n\\+CME ERROR:\\s*([^\\n\\r]+)\\r\\n$", flags, 0, NULL); - parser->regex_cms_error_str = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*([^\\n\\r]+)\\r\\n$", flags, 0, NULL); - parser->regex_ezx_error = g_regex_new ("\\r\\n\\MODEM ERROR:\\s*(\\d+)\\r\\n$", flags, 0, NULL); - parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n$", flags, 0, NULL); - parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n$", flags, 0, NULL); + parser->regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR:\\s*(\\d+)\\r\\n", flags, 0, NULL); + parser->regex_cms_error = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*(\\d+)\\r\\n", flags, 0, NULL); + parser->regex_cme_error_str = g_regex_new ("\\r\\n\\+CME ERROR:\\s*([^\\n\\r]+)\\r\\n", flags, 0, NULL); + parser->regex_cms_error_str = g_regex_new ("\\r\\n\\+CMS ERROR:\\s*([^\\n\\r]+)\\r\\n", flags, 0, NULL); + parser->regex_ezx_error = g_regex_new ("\\r\\n\\MODEM ERROR:\\s*(\\d+)\\r\\n", flags, 0, NULL); + parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n", flags, 0, NULL); + parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n", flags, 0, NULL); /* Samsung Z810 may reply "NA" to report a not-available error */ parser->regex_na = g_regex_new ("\\r\\nNA\\r\\n", flags, 0, NULL); @@ -161,9 +161,10 @@ mm_serial_parser_v1_add_filter (gpointer data, } gboolean -mm_serial_parser_v1_parse (gpointer data, - GString *response, - GError **error) +mm_serial_parser_v1_parse (gpointer data, + GString *response, + gpointer log_object, + GError **error) { MMSerialParserV1 *parser = (MMSerialParserV1 *) data; GMatchInfo *match_info; @@ -188,7 +189,7 @@ mm_serial_parser_v1_parse (gpointer data, response, &local_error)) { g_assert (local_error != NULL); - mm_dbg ("Got response filtered in serial port: %s", local_error->message); + mm_obj_dbg (log_object, "response filtered in serial port: %s", local_error->message); g_propagate_error (error, local_error); response_clean (response); return TRUE; @@ -238,7 +239,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_mobile_equipment_error_for_code (atoi (str)); + local_error = mm_mobile_equipment_error_for_code (atoi (str), log_object); goto done; } g_match_info_free (match_info); @@ -251,7 +252,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_mobile_equipment_error_for_code (atoi (str)); + local_error = mm_mobile_equipment_error_for_code (atoi (str), log_object); goto done; } g_match_info_free (match_info); @@ -263,7 +264,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_message_error_for_code (atoi (str)); + local_error = mm_message_error_for_code (atoi (str), log_object); goto done; } g_match_info_free (match_info); @@ -275,7 +276,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_mobile_equipment_error_for_string (str); + local_error = mm_mobile_equipment_error_for_string (str, log_object); goto done; } g_match_info_free (match_info); @@ -287,7 +288,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_message_error_for_string (str); + local_error = mm_message_error_for_string (str, log_object); goto done; } g_match_info_free (match_info); @@ -299,7 +300,7 @@ mm_serial_parser_v1_parse (gpointer data, if (found) { str = g_match_info_fetch (match_info, 1); g_assert (str); - local_error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN); + local_error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, log_object); goto done; } g_match_info_free (match_info); @@ -309,7 +310,7 @@ mm_serial_parser_v1_parse (gpointer data, response->str, response->len, 0, 0, &match_info, NULL); if (found) { - local_error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN); + local_error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN, log_object); goto done; } g_match_info_free (match_info); @@ -337,7 +338,7 @@ mm_serial_parser_v1_parse (gpointer data, code = MM_CONNECTION_ERROR_NO_CARRIER; } - local_error = mm_connection_error_for_code (code); + local_error = mm_connection_error_for_code (code, log_object); goto done; } g_match_info_free (match_info); @@ -361,7 +362,7 @@ mm_serial_parser_v1_parse (gpointer data, response_clean (response); if (local_error) { - mm_dbg ("Got failure code %d: %s", local_error->code, local_error->message); + mm_obj_dbg (log_object, "operation failure: %d (%s)", local_error->code, local_error->message); g_propagate_error (error, local_error); } diff --git a/src/mm-serial-parsers.h b/src/mm-serial-parsers.h index 641c5e0f..523597b9 100644 --- a/src/mm-serial-parsers.h +++ b/src/mm-serial-parsers.h @@ -24,6 +24,7 @@ void mm_serial_parser_v1_set_custom_regex (gpointer data, GRegex *error); gboolean mm_serial_parser_v1_parse (gpointer parser, GString *response, + gpointer log_object, GError **error); void mm_serial_parser_v1_destroy (gpointer parser); gboolean mm_serial_parser_v1_is_known_error (const GError *error); diff --git a/src/mm-shared-qmi.c b/src/mm-shared-qmi.c index 7c3575eb..a2f25095 100644 --- a/src/mm-shared-qmi.c +++ b/src/mm-shared-qmi.c @@ -25,10 +25,11 @@ #include -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-iface-modem.h" #include "mm-iface-modem-3gpp.h" #include "mm-iface-modem-location.h" +#include "mm-sim-qmi.h" #include "mm-shared-qmi.h" #include "mm-modem-helpers-qmi.h" @@ -70,9 +71,11 @@ typedef struct { /* Capabilities & modes helpers */ MMModemCapability current_capabilities; GArray *supported_radio_interfaces; - Feature feature_nas_technology_preference; - Feature feature_nas_system_selection_preference; - Feature feature_extended_lte_band_preference; + Feature feature_nas_tp; + Feature feature_nas_ssp; + Feature feature_nas_ssp_extended_lte_band_preference; + Feature feature_nas_ssp_acquisition_order_preference; + GArray *feature_nas_ssp_acquisition_order_preference_array; gboolean disable_4g_only_mode; GArray *supported_bands; @@ -91,6 +94,12 @@ typedef struct { gboolean config_active_default; GArray *config_list; gint config_active_i; + + /* Slot status monitoring */ + QmiClient *uim_client; + gulong uim_slot_status_indication_id; + gulong uim_refresh_indication_id; + guint uim_refresh_start_timeout_id; } Private; static void @@ -110,6 +119,16 @@ private_free (Private *priv) g_signal_handler_disconnect (priv->loc_client, priv->loc_location_nmea_indication_id); if (priv->loc_client) g_object_unref (priv->loc_client); + if (priv->uim_slot_status_indication_id) + g_signal_handler_disconnect (priv->uim_client, priv->uim_slot_status_indication_id); + if (priv->uim_refresh_indication_id) + g_signal_handler_disconnect (priv->uim_client, priv->uim_refresh_indication_id); + if (priv->uim_client) + g_object_unref (priv->uim_client); + if (priv->uim_refresh_start_timeout_id) + g_source_remove (priv->uim_refresh_start_timeout_id); + if (priv->feature_nas_ssp_acquisition_order_preference_array) + g_array_unref (priv->feature_nas_ssp_acquisition_order_preference_array); g_strfreev (priv->loc_assistance_data_servers); g_slice_free (Private, priv); } @@ -126,8 +145,10 @@ get_private (MMSharedQmi *self) if (!priv) { priv = g_slice_new0 (Private); - priv->feature_nas_technology_preference = FEATURE_UNKNOWN; - priv->feature_nas_system_selection_preference = FEATURE_UNKNOWN; + priv->feature_nas_tp = FEATURE_UNKNOWN; + priv->feature_nas_ssp = FEATURE_UNKNOWN; + priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_UNKNOWN; + priv->feature_nas_ssp_acquisition_order_preference = FEATURE_UNKNOWN; priv->config_active_i = -1; /* Setup parent class' MMIfaceModemLocation */ @@ -197,7 +218,7 @@ register_in_network_cancelled (GCancellable *cancellable, g_signal_handler_disconnect (ctx->client, ctx->serving_system_indication_id); ctx->serving_system_indication_id = 0; - g_assert (g_task_return_error_if_cancelled (task)); + g_task_return_error_if_cancelled (task); g_object_unref (task); } @@ -326,41 +347,14 @@ initiate_network_register_ready (QmiClientNas *client, qmi_message_nas_initiate_network_register_output_unref (output); } -void -mm_shared_qmi_3gpp_register_in_network (MMIfaceModem3gpp *self, - const gchar *operator_id, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static void +register_in_network_inr (GTask *task, + QmiClient *client, + GCancellable *cancellable, + guint16 mcc, + guint16 mnc) { - GTask *task; - RegisterInNetworkContext *ctx; QmiMessageNasInitiateNetworkRegisterInput *input; - guint16 mcc = 0; - guint16 mnc; - QmiClient *client = NULL; - GError *error = NULL; - - /* Get NAS client */ - if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_NAS, &client, - callback, user_data)) - return; - - task = g_task_new (self, cancellable, callback, user_data); - - ctx = g_slice_new0 (RegisterInNetworkContext); - ctx->client = g_object_ref (client); - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_task_set_task_data (task, ctx, (GDestroyNotify)register_in_network_context_free); - - /* Parse input MCC/MNC */ - if (operator_id && !mm_3gpp_parse_operator_id (operator_id, &mcc, &mnc, &error)) { - g_assert (error != NULL); - g_task_return_error (task, error); - g_object_unref (task); - return; - } input = qmi_message_nas_initiate_network_register_input_new (); @@ -395,6 +389,105 @@ mm_shared_qmi_3gpp_register_in_network (MMIfaceModem3gpp *self, qmi_message_nas_initiate_network_register_input_unref (input); } +static void +set_system_selection_preference_ready (QmiClientNas *client, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + QmiMessageNasSetSystemSelectionPreferenceOutput *output; + + output = qmi_client_nas_set_system_selection_preference_finish (client, res, &error); + if (!output || !qmi_message_nas_set_system_selection_preference_output_get_result (output, &error)) { + if (!g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_EFFECT)) { + g_prefix_error (&error, "Couldn't set network selection preference: "); + g_task_return_error (task, error); + goto out; + } + g_error_free (error); + } + + g_task_return_boolean (task, TRUE); + +out: + g_object_unref (task); + + if (output) + qmi_message_nas_set_system_selection_preference_output_unref (output); +} + +static void +register_in_network_sssp (GTask *task, + QmiClient *client, + GCancellable *cancellable, + guint16 mcc, + guint16 mnc) +{ + QmiMessageNasSetSystemSelectionPreferenceInput *input; + + input = qmi_message_nas_set_system_selection_preference_input_new (); + + qmi_message_nas_set_system_selection_preference_input_set_network_selection_preference ( + input, + mcc ? QMI_NAS_NETWORK_SELECTION_PREFERENCE_MANUAL : QMI_NAS_NETWORK_SELECTION_PREFERENCE_AUTOMATIC, + mcc, + mnc, + NULL); + + qmi_client_nas_set_system_selection_preference ( + QMI_CLIENT_NAS (client), + input, + 120, + cancellable, + (GAsyncReadyCallback)set_system_selection_preference_ready, + task); + + qmi_message_nas_set_system_selection_preference_input_unref (input); +} + +void +mm_shared_qmi_3gpp_register_in_network (MMIfaceModem3gpp *self, + const gchar *operator_id, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + RegisterInNetworkContext *ctx; + guint16 mcc = 0; + guint16 mnc; + QmiClient *client = NULL; + GError *error = NULL; + Private *priv = NULL; + + /* Get NAS client */ + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_NAS, &client, + callback, user_data)) + return; + + task = g_task_new (self, cancellable, callback, user_data); + + ctx = g_slice_new0 (RegisterInNetworkContext); + ctx->client = g_object_ref (client); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_task_set_task_data (task, ctx, (GDestroyNotify)register_in_network_context_free); + + /* Parse input MCC/MNC */ + if (operator_id && !mm_3gpp_parse_operator_id (operator_id, &mcc, &mnc, &error)) { + g_assert (error != NULL); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + priv = get_private (MM_SHARED_QMI (self)); + if (priv->feature_nas_ssp == FEATURE_SUPPORTED) + register_in_network_sssp (task, client, cancellable, mcc, mnc); + else + register_in_network_inr (task, client, cancellable, mcc, mnc); +} + /*****************************************************************************/ /* Current capabilities setting (Modem interface) */ @@ -601,8 +694,8 @@ set_current_capabilities_step (GTask *task) switch (ctx->step) { case SET_CURRENT_CAPABILITIES_STEP_FIRST: /* Error out early if both unsupported */ - if ((priv->feature_nas_system_selection_preference != FEATURE_SUPPORTED) && - (priv->feature_nas_technology_preference != FEATURE_SUPPORTED)) { + if ((priv->feature_nas_ssp != FEATURE_SUPPORTED) && + (priv->feature_nas_tp != FEATURE_SUPPORTED)) { g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Setting capabilities is not supported by this device"); g_object_unref (task); @@ -612,7 +705,7 @@ set_current_capabilities_step (GTask *task) /* fall-through */ case SET_CURRENT_CAPABILITIES_STEP_NAS_SYSTEM_SELECTION_PREFERENCE: - if (priv->feature_nas_system_selection_preference == FEATURE_SUPPORTED) { + if (priv->feature_nas_ssp == FEATURE_SUPPORTED) { set_current_capabilities_system_selection_preference (task); return; } @@ -620,7 +713,7 @@ set_current_capabilities_step (GTask *task) /* fall-through */ case SET_CURRENT_CAPABILITIES_STEP_NAS_TECHNOLOGY_PREFERENCE: - if (priv->feature_nas_technology_preference == FEATURE_SUPPORTED) { + if (priv->feature_nas_tp == FEATURE_SUPPORTED) { set_current_capabilities_technology_preference (task); return; } @@ -660,8 +753,8 @@ mm_shared_qmi_set_current_capabilities (MMIfaceModem *self, return; priv = get_private (MM_SHARED_QMI (self)); - g_assert (priv->feature_nas_technology_preference != FEATURE_UNKNOWN); - g_assert (priv->feature_nas_system_selection_preference != FEATURE_UNKNOWN); + g_assert (priv->feature_nas_tp != FEATURE_UNKNOWN); + g_assert (priv->feature_nas_ssp != FEATURE_UNKNOWN); ctx = g_slice_new0 (SetCurrentCapabilitiesContext); ctx->client = g_object_ref (client); @@ -761,7 +854,7 @@ load_current_capabilities_get_capabilities_ready (QmiClientDms *client, for (i = 0; i < radio_interface_list->len; i++) ctx->capabilities_context.dms_capabilities |= - mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list, QmiDmsRadioInterface, i)); + mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list, QmiDmsRadioInterface, i), self); out: if (output) @@ -795,20 +888,20 @@ load_current_capabilities_get_technology_preference_ready (QmiClientNas *client, output = qmi_client_nas_get_technology_preference_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: %s", error->message); + mm_obj_dbg (self, "QMI operation failed: %s", error->message); g_error_free (error); - priv->feature_nas_technology_preference = FEATURE_UNSUPPORTED; + priv->feature_nas_tp = FEATURE_UNSUPPORTED; } else if (!qmi_message_nas_get_technology_preference_output_get_result (output, &error)) { - mm_dbg ("Couldn't get technology preference: %s", error->message); + mm_obj_dbg (self, "couldn't get technology preference: %s", error->message); g_error_free (error); - priv->feature_nas_technology_preference = FEATURE_SUPPORTED; + priv->feature_nas_tp = FEATURE_UNSUPPORTED; } else { qmi_message_nas_get_technology_preference_output_get_active ( output, &ctx->capabilities_context.nas_tp_mask, NULL, /* duration */ NULL); - priv->feature_nas_technology_preference = FEATURE_SUPPORTED; + priv->feature_nas_tp = FEATURE_SUPPORTED; } if (output) @@ -833,21 +926,35 @@ load_current_capabilities_get_system_selection_preference_ready (QmiClientNas *c ctx = g_task_get_task_data (task); priv = get_private (MM_SHARED_QMI (self)); + priv->feature_nas_ssp = FEATURE_UNSUPPORTED; + priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_UNSUPPORTED; + priv->feature_nas_ssp_acquisition_order_preference = FEATURE_UNSUPPORTED; + output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error); if (!output) { - mm_dbg ("QMI operation failed: %s", error->message); + mm_obj_dbg (self, "QMI operation failed: %s", error->message); g_error_free (error); - priv->feature_nas_system_selection_preference = FEATURE_UNSUPPORTED; } else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) { - mm_dbg ("Couldn't get system selection preference: %s", error->message); + mm_obj_dbg (self, "couldn't get system selection preference: %s", error->message); g_error_free (error); - priv->feature_nas_system_selection_preference = FEATURE_SUPPORTED; } else { + GArray *acquisition_order_preference_array = NULL; + + /* SSP is supported, perform feature checks */ + priv->feature_nas_ssp = FEATURE_SUPPORTED; + if (qmi_message_nas_get_system_selection_preference_output_get_extended_lte_band_preference (output, NULL, NULL, NULL, NULL, NULL)) + priv->feature_nas_ssp_extended_lte_band_preference = FEATURE_SUPPORTED; + if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference (output, &acquisition_order_preference_array, NULL) && + acquisition_order_preference_array && + acquisition_order_preference_array->len) { + priv->feature_nas_ssp_acquisition_order_preference = FEATURE_SUPPORTED; + priv->feature_nas_ssp_acquisition_order_preference_array = g_array_ref (acquisition_order_preference_array); + } + qmi_message_nas_get_system_selection_preference_output_get_mode_preference ( output, &ctx->capabilities_context.nas_ssp_mode_preference_mask, NULL); - priv->feature_nas_system_selection_preference = FEATURE_SUPPORTED; } if (output) @@ -895,9 +1002,9 @@ load_current_capabilities_step (GTask *task) return; case LOAD_CURRENT_CAPABILITIES_STEP_LAST: - g_assert (priv->feature_nas_technology_preference != FEATURE_UNKNOWN); - g_assert (priv->feature_nas_system_selection_preference != FEATURE_UNKNOWN); - priv->current_capabilities = mm_modem_capability_from_qmi_capabilities_context (&ctx->capabilities_context); + g_assert (priv->feature_nas_tp != FEATURE_UNKNOWN); + g_assert (priv->feature_nas_ssp != FEATURE_UNKNOWN); + priv->current_capabilities = mm_modem_capability_from_qmi_capabilities_context (&ctx->capabilities_context, self); g_task_return_int (task, priv->current_capabilities); g_object_unref (task); return; @@ -946,8 +1053,8 @@ mm_shared_qmi_load_current_capabilities (MMIfaceModem *self, /* Current capabilities is the first thing run, and will only be run once per modem, * so we should here check support for the optional features. */ priv = get_private (MM_SHARED_QMI (self)); - g_assert (priv->feature_nas_technology_preference == FEATURE_UNKNOWN); - g_assert (priv->feature_nas_system_selection_preference == FEATURE_UNKNOWN); + g_assert (priv->feature_nas_tp == FEATURE_UNKNOWN); + g_assert (priv->feature_nas_ssp == FEATURE_UNKNOWN); ctx = g_slice_new0 (LoadCurrentCapabilitiesContext); ctx->nas_client = g_object_ref (nas_client); @@ -997,7 +1104,7 @@ mm_shared_qmi_load_supported_capabilities (MMIfaceModem *self, /* Build mask with all supported capabilities */ mask = MM_MODEM_CAPABILITY_NONE; for (i = 0; i < priv->supported_radio_interfaces->len; i++) - mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (priv->supported_radio_interfaces, QmiDmsRadioInterface, i)); + mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (priv->supported_radio_interfaces, QmiDmsRadioInterface, i), self); supported_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 3); @@ -1006,7 +1113,7 @@ mm_shared_qmi_load_supported_capabilities (MMIfaceModem *self, * switching only when switching GSM/UMTS+CDMA/EVDO multimode devices, and only if * we have support for the commands doing it. */ - if (priv->feature_nas_technology_preference == FEATURE_SUPPORTED || priv->feature_nas_system_selection_preference == FEATURE_SUPPORTED) { + if (priv->feature_nas_tp == FEATURE_SUPPORTED || priv->feature_nas_ssp == FEATURE_SUPPORTED) { if (mask == (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_CDMA_EVDO)) { /* Multimode GSM/UMTS+CDMA/EVDO device switched to GSM/UMTS only */ single = MM_MODEM_CAPABILITY_GSM_UMTS; @@ -1164,11 +1271,13 @@ static void set_current_modes_system_selection_preference (GTask *task) { MMIfaceModem *self; + Private *priv; SetCurrentModesContext *ctx; QmiMessageNasSetSystemSelectionPreferenceInput *input; QmiNasRatModePreference pref; self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); ctx = g_task_get_task_data (task); input = qmi_message_nas_set_system_selection_preference_input_new (); @@ -1177,22 +1286,23 @@ set_current_modes_system_selection_preference (GTask *task) /* Preferred modes */ if (ctx->preferred != MM_MODEM_MODE_NONE) { - GArray *array; - - /* Acquisition order array */ - array = mm_modem_mode_to_qmi_acquisition_order_preference (ctx->allowed, - ctx->preferred, - mm_iface_modem_is_cdma (self), - mm_iface_modem_is_3gpp (self)); - g_assert (array); - qmi_message_nas_set_system_selection_preference_input_set_acquisition_order_preference (input, array, NULL); - g_array_unref (array); + if (priv->feature_nas_ssp_acquisition_order_preference == FEATURE_SUPPORTED) { + GArray *array; + + /* Acquisition order array */ + array = mm_modem_mode_to_qmi_acquisition_order_preference (ctx->allowed, + ctx->preferred, + priv->feature_nas_ssp_acquisition_order_preference_array); + g_assert (array); + qmi_message_nas_set_system_selection_preference_input_set_acquisition_order_preference (input, array, NULL); + g_array_unref (array); + } /* Only set GSM/WCDMA acquisition order preference if both 2G and 3G given as allowed */ if (mm_iface_modem_is_3gpp (self) && ((ctx->allowed & (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G))) { QmiNasGsmWcdmaAcquisitionOrderPreference order; - order = mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (ctx->preferred); + order = mm_modem_mode_to_qmi_gsm_wcdma_acquisition_order_preference (ctx->preferred, self); qmi_message_nas_set_system_selection_preference_input_set_gsm_wcdma_acquisition_order_preference (input, order, NULL); } } @@ -1252,12 +1362,12 @@ mm_shared_qmi_set_current_modes (MMIfaceModem *self, priv = get_private (MM_SHARED_QMI (self)); - if (priv->feature_nas_system_selection_preference == FEATURE_SUPPORTED) { + if (priv->feature_nas_ssp == FEATURE_SUPPORTED) { set_current_modes_system_selection_preference (task); return; } - if (priv->feature_nas_technology_preference == FEATURE_SUPPORTED) { + if (priv->feature_nas_tp == FEATURE_SUPPORTED) { set_current_modes_technology_preference (task); return; } @@ -1371,12 +1481,17 @@ load_current_modes_system_selection_preference_ready (QmiClientNas *client, GAsyncResult *res, GTask *task) { + MMSharedQmi *self; + Private *priv; LoadCurrentModesResult *result = NULL; QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL; GError *error = NULL; QmiNasRatModePreference mode_preference_mask = 0; MMModemMode allowed; + self = g_task_get_source_object (task); + priv = get_private (self); + output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error); if (!output || !qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) { g_task_return_error (task, error); @@ -1408,24 +1523,11 @@ load_current_modes_system_selection_preference_ready (QmiClientNas *client, result->allowed = allowed; result->preferred = MM_MODEM_MODE_NONE; - /* For 2G+3G only rely on the GSM/WCDMA acquisition order preference TLV */ - if (mode_preference_mask == (QMI_NAS_RAT_MODE_PREFERENCE_GSM | QMI_NAS_RAT_MODE_PREFERENCE_UMTS)) { - QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma; - - if (qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference ( - output, - &gsm_or_wcdma, - NULL)) - result->preferred = mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma); - } - /* Otherwise, rely on the acquisition order array TLV */ - else { + /* If acquisition order preference is available, always use that first */ + if (priv->feature_nas_ssp_acquisition_order_preference == FEATURE_SUPPORTED) { GArray *array; - if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference ( - output, - &array, - NULL) && + if (qmi_message_nas_get_system_selection_preference_output_get_acquisition_order_preference (output, &array, NULL) && array->len > 0) { guint i; @@ -1446,6 +1548,16 @@ load_current_modes_system_selection_preference_ready (QmiClientNas *client, } } } + /* For 2G+3G only rely on the GSM/WCDMA acquisition order preference TLV */ + else if (mode_preference_mask == (QMI_NAS_RAT_MODE_PREFERENCE_GSM | QMI_NAS_RAT_MODE_PREFERENCE_UMTS)) { + QmiNasGsmWcdmaAcquisitionOrderPreference gsm_or_wcdma; + + if (qmi_message_nas_get_system_selection_preference_output_get_gsm_wcdma_acquisition_order_preference ( + output, + &gsm_or_wcdma, + NULL)) + result->preferred = mm_modem_mode_from_qmi_gsm_wcdma_acquisition_order_preference (gsm_or_wcdma, self); + } g_task_return_pointer (task, result, g_free); @@ -1492,12 +1604,12 @@ mm_shared_qmi_load_current_modes (MMIfaceModem *self, priv = get_private (MM_SHARED_QMI (self)); - if (priv->feature_nas_system_selection_preference != FEATURE_UNSUPPORTED) { + if (priv->feature_nas_ssp != FEATURE_UNSUPPORTED) { load_current_modes_system_selection_preference (task); return; } - if (priv->feature_nas_technology_preference != FEATURE_UNSUPPORTED) { + if (priv->feature_nas_tp != FEATURE_UNSUPPORTED) { load_current_modes_technology_preference (task); return; } @@ -1541,90 +1653,85 @@ mm_shared_qmi_load_supported_modes (MMIfaceModem *self, /* Build all, based on the supported radio interfaces */ mask_all = MM_MODEM_MODE_NONE; for (i = 0; i < priv->supported_radio_interfaces->len; i++) - mask_all |= mm_modem_mode_from_qmi_radio_interface (g_array_index (priv->supported_radio_interfaces, QmiDmsRadioInterface, i)); + mask_all |= mm_modem_mode_from_qmi_radio_interface (g_array_index (priv->supported_radio_interfaces, QmiDmsRadioInterface, i), self); mode.allowed = mask_all; mode.preferred = MM_MODEM_MODE_NONE; all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); g_array_append_val (all, mode); /* If SSP and TP are not supported, ignore supported mode management */ - if (priv->feature_nas_system_selection_preference == FEATURE_UNSUPPORTED && priv->feature_nas_technology_preference == FEATURE_UNSUPPORTED) { + if (priv->feature_nas_ssp == FEATURE_UNSUPPORTED && priv->feature_nas_tp == FEATURE_UNSUPPORTED) { g_task_return_pointer (task, all, (GDestroyNotify) g_array_unref); g_object_unref (task); return; } - combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 5); + combinations = g_array_new (FALSE, FALSE, sizeof (MMModemModeCombination)); + +#define ADD_MODE_PREFERENCE(MODE1, MODE2, MODE3, MODE4) do { \ + mode.allowed = MODE1; \ + if (MODE2 != MM_MODEM_MODE_NONE) { \ + mode.allowed |= MODE2; \ + if (MODE3 != MM_MODEM_MODE_NONE) { \ + mode.allowed |= MODE3; \ + if (MODE4 != MM_MODEM_MODE_NONE) \ + mode.allowed |= MODE4; \ + } \ + if (priv->feature_nas_ssp != FEATURE_UNSUPPORTED) { \ + if (MODE3 != MM_MODEM_MODE_NONE) { \ + if (MODE4 != MM_MODEM_MODE_NONE) { \ + mode.preferred = MODE4; \ + g_array_append_val (combinations, mode); \ + } \ + mode.preferred = MODE3; \ + g_array_append_val (combinations, mode); \ + } \ + mode.preferred = MODE2; \ + g_array_append_val (combinations, mode); \ + mode.preferred = MODE1; \ + g_array_append_val (combinations, mode); \ + } else { \ + mode.preferred = MM_MODEM_MODE_NONE; \ + g_array_append_val (combinations, mode); \ + } \ + } else { \ + mode.allowed = MODE1; \ + mode.preferred = MM_MODEM_MODE_NONE; \ + g_array_append_val (combinations, mode); \ + } \ + } while (0) /* 2G-only, 3G-only */ - mode.allowed = MM_MODEM_MODE_2G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - mode.allowed = MM_MODEM_MODE_3G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); /* 4G-only mode is not possible in multimode GSM/UMTS+CDMA/EVDO+LTE * devices. This configuration may be selected as "LTE only" capability * instead. */ - if (!priv->disable_4g_only_mode) { - mode.allowed = MM_MODEM_MODE_4G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 2G+3G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - if (priv->feature_nas_system_selection_preference != FEATURE_UNSUPPORTED) { - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } else { - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 2G+4G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_4G); - if (priv->feature_nas_system_selection_preference != FEATURE_UNSUPPORTED) { - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } else { - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 3G+4G */ - mode.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - if (priv->feature_nas_system_selection_preference != FEATURE_UNSUPPORTED) { - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - } else { - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 2G+3G+4G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - if (priv->feature_nas_system_selection_preference != FEATURE_UNSUPPORTED) { - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } else { - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); + if (!priv->disable_4g_only_mode) + ADD_MODE_PREFERENCE (MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + + /* 2G, 3G, 4G combinations */ + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE); + + /* 5G related mode combinations are only supported when NAS SSP is supported, + * as there is no 5G support in NAS TP. */ + if (priv->feature_nas_ssp != FEATURE_UNSUPPORTED) { + ADD_MODE_PREFERENCE (MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G, MM_MODEM_MODE_NONE); + ADD_MODE_PREFERENCE (MM_MODEM_MODE_2G, MM_MODEM_MODE_3G, MM_MODEM_MODE_4G, MM_MODEM_MODE_5G); } /* Filter out unsupported modes */ - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, self); g_array_unref (all); g_array_unref (combinations); @@ -1679,7 +1786,7 @@ dms_get_band_capabilities_ready (QmiClientDms *client, &extended_qmi_lte_bands, NULL); - mm_bands = mm_modem_bands_from_qmi_band_capabilities (qmi_bands, qmi_lte_bands, extended_qmi_lte_bands); + mm_bands = mm_modem_bands_from_qmi_band_capabilities (qmi_bands, qmi_lte_bands, extended_qmi_lte_bands, self); if (mm_bands->len == 0) { g_clear_pointer (&mm_bands, g_array_unref); error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, @@ -1772,7 +1879,8 @@ load_bands_get_system_selection_preference_ready (QmiClientNas *client, <e_band_preference_mask, NULL); - if (qmi_message_nas_get_system_selection_preference_output_get_extended_lte_band_preference ( + if ((priv->feature_nas_ssp_extended_lte_band_preference == FEATURE_SUPPORTED) && + qmi_message_nas_get_system_selection_preference_output_get_extended_lte_band_preference ( output, &extended_lte_band_preference[0], &extended_lte_band_preference[1], @@ -1781,13 +1889,11 @@ load_bands_get_system_selection_preference_ready (QmiClientNas *client, NULL)) extended_lte_band_preference_size = G_N_ELEMENTS (extended_lte_band_preference); - if (G_UNLIKELY (priv->feature_extended_lte_band_preference == FEATURE_UNKNOWN)) - priv->feature_extended_lte_band_preference = extended_lte_band_preference_size ? FEATURE_SUPPORTED : FEATURE_UNSUPPORTED; - mm_bands = mm_modem_bands_from_qmi_band_preference (band_preference_mask, lte_band_preference_mask, extended_lte_band_preference_size ? extended_lte_band_preference : NULL, - extended_lte_band_preference_size); + extended_lte_band_preference_size, + self); if (mm_bands->len == 0) { g_clear_pointer (&mm_bands, g_array_unref); @@ -1901,13 +2007,14 @@ mm_shared_qmi_set_current_bands (MMIfaceModem *self, mm_modem_bands_to_qmi_band_preference (bands_array, &qmi_bands, &qmi_lte_bands, - priv->feature_extended_lte_band_preference == FEATURE_SUPPORTED ? extended_qmi_lte_bands : NULL, - G_N_ELEMENTS (extended_qmi_lte_bands)); + priv->feature_nas_ssp_extended_lte_band_preference == FEATURE_SUPPORTED ? extended_qmi_lte_bands : NULL, + G_N_ELEMENTS (extended_qmi_lte_bands), + self); input = qmi_message_nas_set_system_selection_preference_input_new (); qmi_message_nas_set_system_selection_preference_input_set_band_preference (input, qmi_bands, NULL); if (mm_iface_modem_is_3gpp_lte (self)) { - if (priv->feature_extended_lte_band_preference == FEATURE_SUPPORTED) + if (priv->feature_nas_ssp_extended_lte_band_preference == FEATURE_SUPPORTED) qmi_message_nas_set_system_selection_preference_input_set_extended_lte_band_preference ( input, extended_qmi_lte_bands[0], @@ -1946,14 +2053,17 @@ reset_set_operating_mode_reset_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) { + MMSharedQmi *self; QmiMessageDmsSetOperatingModeOutput *output; - GError *error = NULL; + GError *error = NULL; + + self = g_task_get_source_object (task); output = qmi_client_dms_set_operating_mode_finish (client, res, &error); if (!output || !qmi_message_dms_set_operating_mode_output_get_result (output, &error)) { g_task_return_error (task, error); } else { - mm_info ("Modem is being rebooted now"); + mm_obj_info (self, "rebooting now"); g_task_return_boolean (task, TRUE); } @@ -2093,7 +2203,7 @@ mm_shared_qmi_factory_reset (MMIfaceModem *self, return; } - mm_dbg ("performing a factory reset..."); + mm_obj_dbg (self, "performing a factory reset..."); qmi_client_dms_restore_factory_defaults (QMI_CLIENT_DMS (client), input, 10, @@ -2381,7 +2491,7 @@ find_requested_carrier_config (GTask *task) /* Match generic configuration */ config_fallback = g_key_file_get_string (ctx->keyfile, group, GENERIC_CONFIG_FALLBACK, NULL); - mm_dbg ("Fallback carrier configuration %sfound in group '%s'", config_fallback ? "" : "not ", group); + mm_obj_dbg (self, "fallback carrier configuration %sfound in group '%s'", config_fallback ? "" : "not ", group); /* First, try to match 6 MCCMNC digits (3-digit MNCs) */ strncpy (mccmnc, ctx->imsi, 6); @@ -2392,8 +2502,8 @@ find_requested_carrier_config (GTask *task) mccmnc[5] = '\0'; ctx->config_requested = g_key_file_get_string (ctx->keyfile, group, mccmnc, NULL); } - mm_dbg ("Requested carrier configuration %sfound for '%s' in group '%s': %s", - ctx->config_requested ? "" : "not ", mccmnc, group, ctx->config_requested ? ctx->config_requested : "n/a"); + mm_obj_dbg (self, "requested carrier configuration %sfound for '%s' in group '%s': %s", + ctx->config_requested ? "" : "not ", mccmnc, group, ctx->config_requested ? ctx->config_requested : "n/a"); if (!ctx->config_requested && !config_fallback) { setup_carrier_config_abort (task, g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, @@ -2410,16 +2520,16 @@ find_requested_carrier_config (GTask *task) config = &g_array_index (priv->config_list, ConfigInfo, i); if (ctx->config_requested && !g_strcmp0 (ctx->config_requested, config->description)) { - mm_dbg ("Requested carrier configuration '%s' is available (version 0x%08x, size %u bytes)", - config->description, config->version, config->total_size); + mm_obj_dbg (self, "requested carrier configuration '%s' is available (version 0x%08x, size %u bytes)", + config->description, config->version, config->total_size); if (ctx->config_requested_i < 0) ctx->config_requested_i = i; else ctx->config_requested_i = select_newest_carrier_config (self, ctx->config_requested_i, i); } if (config_fallback && !g_strcmp0 (config_fallback, config->description)) { - mm_dbg ("Fallback carrier configuration '%s' is available (version 0x%08x, size %u bytes)", - config->description, config->version, config->total_size); + mm_obj_dbg (self, "fallback carrier configuration '%s' is available (version 0x%08x, size %u bytes)", + config->description, config->version, config->total_size); if (config_fallback_i < 0) config_fallback_i = i; else @@ -2444,8 +2554,8 @@ find_requested_carrier_config (GTask *task) g_assert (config_fallback_i >= 0); config = &g_array_index (priv->config_list, ConfigInfo, config_fallback_i); - mm_info ("Using fallback carrier configuration '%s' (version 0x%08x, size %u bytes)", - config->description, config->version, config->total_size); + mm_obj_info (self, "using fallback carrier configuration '%s' (version 0x%08x, size %u bytes)", + config->description, config->version, config->total_size); g_free (ctx->config_requested); ctx->config_requested = config_fallback; @@ -2455,8 +2565,8 @@ find_requested_carrier_config (GTask *task) ConfigInfo *config; config = &g_array_index (priv->config_list, ConfigInfo, ctx->config_requested_i); - mm_dbg ("Using requested carrier configuration '%s' (version 0x%08x, size %u bytes)", - config->description, config->version, config->total_size); + mm_obj_dbg (self, "using requested carrier configuration '%s' (version 0x%08x, size %u bytes)", + config->description, config->version, config->total_size); } ctx->step++; @@ -2470,11 +2580,13 @@ find_requested_carrier_config (GTask *task) static void setup_carrier_config_step (GTask *task) { + MMSharedQmi *self; SetupCarrierConfigContext *ctx; Private *priv; - ctx = g_task_get_task_data (task); - priv = get_private (g_task_get_source_object (task)); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + priv = get_private (self); switch (ctx->step) { case SETUP_CARRIER_CONFIG_STEP_FIRST: @@ -2489,7 +2601,7 @@ setup_carrier_config_step (GTask *task) g_assert (ctx->config_requested_i >= 0); g_assert (priv->config_active_i >= 0 || priv->config_active_default); if (ctx->config_requested_i == priv->config_active_i) { - mm_info ("Carrier config switching not needed: already using '%s'", ctx->config_requested); + mm_obj_info (self, "carrier config switching not needed: already using '%s'", ctx->config_requested); ctx->step = SETUP_CARRIER_CONFIG_STEP_LAST; setup_carrier_config_step (task); return; @@ -2506,8 +2618,8 @@ setup_carrier_config_step (GTask *task) requested_config = &g_array_index (priv->config_list, ConfigInfo, ctx->config_requested_i); active_config = (priv->config_active_default ? NULL : &g_array_index (priv->config_list, ConfigInfo, priv->config_active_i)); - mm_warn ("Carrier config switching needed: '%s' -> '%s'", - active_config ? active_config->description : DEFAULT_CONFIG_DESCRIPTION, requested_config->description); + mm_obj_warn (self, "carrier config switching needed: '%s' -> '%s'", + active_config ? active_config->description : DEFAULT_CONFIG_DESCRIPTION, requested_config->description); type_and_id.config_type = requested_config->config_type;; type_and_id.id = requested_config->id; @@ -2730,13 +2842,15 @@ get_selected_config_indication (QmiClientPdc *client, QmiIndicationPdcGetSelectedConfigOutput *output, GTask *task) { + MMSharedQmi *self; LoadCarrierConfigContext *ctx; GArray *active_id = NULL; GError *error = NULL; guint16 error_code = 0; guint i; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!qmi_indication_pdc_get_selected_config_output_get_indication_result (output, &error_code, &error)) { load_carrier_config_abort (task, error); @@ -2753,7 +2867,7 @@ get_selected_config_indication (QmiClientPdc *client, qmi_indication_pdc_get_selected_config_output_get_active_id (output, &active_id, NULL); if (!active_id) { - mm_dbg ("no carrier config currently selected (default in use)"); + mm_obj_dbg (self, "no carrier config currently selected (default in use)"); ctx->config_active_default = TRUE; goto next; } @@ -2889,13 +3003,15 @@ list_configs_indication (QmiClientPdc *client, QmiIndicationPdcListConfigsOutput *output, GTask *task) { + MMSharedQmi *self; LoadCarrierConfigContext *ctx; GError *error = NULL; GArray *configs = NULL; guint i; guint16 error_code = 0; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!qmi_indication_pdc_list_configs_output_get_indication_result (output, &error_code, &error)) { load_carrier_config_abort (task, error); @@ -2923,7 +3039,7 @@ list_configs_indication (QmiClientPdc *client, } /* Preallocate config list and request details for each */ - mm_dbg ("found %u carrier configurations...", configs->len); + mm_obj_dbg (self, "found %u carrier configurations...", configs->len); ctx->config_list = g_array_sized_new (FALSE, TRUE, sizeof (ConfigInfo), configs->len); g_array_set_size (ctx->config_list, configs->len); g_array_set_clear_func (ctx->config_list, (GDestroyNotify) config_info_clear); @@ -3082,99 +3198,1066 @@ mm_shared_qmi_load_carrier_config (MMIfaceModem *self, } /*****************************************************************************/ -/* Location: Set SUPL server */ +/* Load SIM slots (modem interface) */ typedef struct { - QmiClient *client; - gchar *supl; - glong indication_id; - guint timeout_id; -} SetSuplServerContext; + QmiClientUim *client_uim; + GPtrArray *sim_slots; + GList *sorted_sims; + MMBaseSim *current_sim; + guint current_slot_number; + guint active_slot_number; + guint active_logical_id; +} LoadSimSlotsContext; static void -set_supl_server_context_free (SetSuplServerContext *ctx) +load_sim_slots_context_free (LoadSimSlotsContext *ctx) { - if (ctx->client) { - if (ctx->timeout_id) - g_source_remove (ctx->timeout_id); - if (ctx->indication_id) - g_signal_handler_disconnect (ctx->client, ctx->indication_id); - g_object_unref (ctx->client); - } - g_slice_free (SetSuplServerContext, ctx); + g_clear_object (&ctx->current_sim); + g_list_free_full (ctx->sorted_sims, (GDestroyNotify)g_object_unref); + g_clear_pointer (&ctx->sim_slots, g_ptr_array_unref); + g_clear_object (&ctx->client_uim); + g_slice_free (LoadSimSlotsContext, ctx); } -static GArray * -parse_as_utf16_url (const gchar *supl) +static void +sim_slot_free (MMBaseSim *sim) { - GArray *url; - gchar *utf16; - gsize utf16_len; - - utf16 = g_convert (supl, -1, "UTF-16BE", "UTF-8", NULL, &utf16_len, NULL); - url = g_array_append_vals (g_array_sized_new (FALSE, FALSE, sizeof (guint8), utf16_len), - utf16, utf16_len); - g_free (utf16); - return url; + if (sim) + g_object_unref (sim); } gboolean -mm_shared_qmi_location_set_supl_server_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) +mm_shared_qmi_load_sim_slots_finish (MMIfaceModem *self, + GAsyncResult *res, + GPtrArray **sim_slots, + guint *primary_sim_slot, + GError **error) { - return g_task_propagate_boolean (G_TASK (res), error); + LoadSimSlotsContext *ctx; + + if (!g_task_propagate_boolean (G_TASK (res), error)) + return FALSE; + + ctx = g_task_get_task_data (G_TASK (res)); + if (sim_slots) + *sim_slots = g_steal_pointer (&ctx->sim_slots); + if (primary_sim_slot) + *primary_sim_slot = ctx->active_slot_number; + return TRUE; } static void -pds_set_agps_config_ready (QmiClientPds *client, - GAsyncResult *res, - GTask *task) +active_slot_switch_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) { - QmiMessagePdsSetAgpsConfigOutput *output; - GError *error = NULL; + g_autoptr(QmiMessageUimSwitchSlotOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + LoadSimSlotsContext *ctx; - output = qmi_client_pds_set_agps_config_finish (client, res, &error); - if (!output) { - g_prefix_error (&error, "QMI operation failed: "); - g_task_return_error (task, error); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_uim_switch_slot_finish (client, res, &error); + if ((!output || !qmi_message_uim_switch_slot_output_get_result (output, &error)) && + !g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_EFFECT)) { + mm_obj_err (self, "couldn't switch to original slot %u", ctx->active_slot_number); + g_task_return_error (task, g_steal_pointer (&error)); + } else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +reload_active_slot (GTask *task) +{ + g_autoptr(QmiMessageUimSwitchSlotInput) input = NULL; + LoadSimSlotsContext *ctx; + MMIfaceModem *self; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + /* If we're already in the original active SIM slot, nothing else to do */ + if (ctx->current_slot_number == ctx->active_slot_number) { + g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - if (!qmi_message_pds_set_agps_config_output_get_result (output, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); + mm_obj_dbg (self, "switching to original active SIM at slot %u", ctx->active_slot_number); - qmi_message_pds_set_agps_config_output_unref (output); + /* Switch to the original active slot */ + input = qmi_message_uim_switch_slot_input_new (); + qmi_message_uim_switch_slot_input_set_logical_slot (input, (guint8) ctx->active_logical_id, NULL); + qmi_message_uim_switch_slot_input_set_physical_slot (input, ctx->active_slot_number, NULL); + qmi_client_uim_switch_slot (ctx->client_uim, + input, + 10, + NULL, + (GAsyncReadyCallback) active_slot_switch_ready, + task); } +static void load_next_sim_info (GTask *task); + static void -pds_set_supl_server (GTask *task) +next_sim_initialize_ready (MMBaseSim *sim, + GAsyncResult *res, + GTask *task) { - MMSharedQmi *self; - SetSuplServerContext *ctx; - QmiMessagePdsSetAgpsConfigInput *input; - guint32 ip; - guint16 port; - GArray *url; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + LoadSimSlotsContext *ctx; self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); + ctx = g_task_get_task_data (task); - input = qmi_message_pds_set_agps_config_input_new (); + if (!mm_base_sim_initialize_finish (sim, res, &error)) + mm_obj_dbg (self, "couldn't initialize SIM at slot %u: won't load additional info", + ctx->current_slot_number); + else + mm_obj_dbg (self, "initialized SIM at slot %u", + ctx->current_slot_number); - /* For multimode devices, prefer UMTS by default */ - if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) - qmi_message_pds_set_agps_config_input_set_network_mode (input, QMI_PDS_NETWORK_MODE_UMTS, NULL); - else if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (self))) - qmi_message_pds_set_agps_config_input_set_network_mode (input, QMI_PDS_NETWORK_MODE_CDMA, NULL); + /* Iterate to next SIM */ + load_next_sim_info (task); +} - if (mm_parse_supl_address (ctx->supl, NULL, &ip, &port, NULL)) - qmi_message_pds_set_agps_config_input_set_location_server_address (input, ip, port, NULL); - else { +static void +next_sim_switch_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimSwitchSlotOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + LoadSimSlotsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_uim_switch_slot_finish (client, res, &error); + if (!output || !qmi_message_uim_switch_slot_output_get_result (output, &error)) { + /* ignore NoEffect errors on slot switch, because that indicates we're + * already in the desired slot */ + if (!g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_EFFECT)) { + mm_obj_dbg (self, "couldn't switch to SIM at slot %u: won't load additional info", + ctx->current_slot_number); + load_next_sim_info (task); + return; + } + } + + mm_obj_dbg (self, "switched to SIM at slot %u: initializing...", + ctx->current_slot_number); + + mm_base_sim_initialize (ctx->current_sim, + NULL, + (GAsyncReadyCallback) next_sim_initialize_ready, + task); +} + +static void +load_next_sim_info (GTask *task) +{ + g_autoptr(QmiMessageUimSwitchSlotInput) input = NULL; + LoadSimSlotsContext *ctx; + MMIfaceModem *self; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + /* All done? */ + if (!ctx->sorted_sims) { + mm_obj_dbg (self, "no more SIMs to load info from"); + reload_active_slot (task); + return; + } + + /* Steal SIM from list */ + g_clear_object (&ctx->current_sim); + ctx->current_sim = MM_BASE_SIM (ctx->sorted_sims->data); + ctx->sorted_sims = g_list_delete_link (ctx->sorted_sims, ctx->sorted_sims); + ctx->current_slot_number = mm_base_sim_get_slot_number (ctx->current_sim); + + mm_obj_dbg (self, "switching to SIM at slot %u: %s", + ctx->current_slot_number, mm_base_sim_get_path (ctx->current_sim)); + + /* Switch to the next slot */ + input = qmi_message_uim_switch_slot_input_new (); + qmi_message_uim_switch_slot_input_set_logical_slot (input, (guint8) ctx->active_logical_id, NULL); + qmi_message_uim_switch_slot_input_set_physical_slot (input, ctx->current_slot_number, NULL); + qmi_client_uim_switch_slot (ctx->client_uim, + input, + 10, + NULL, + (GAsyncReadyCallback) next_sim_switch_ready, + task); +} + +static void +uim_get_slot_status_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimGetSlotStatusOutput) output = NULL; + LoadSimSlotsContext *ctx; + MMIfaceModem *self; + GError *error = NULL; + GArray *physical_slots = NULL; + GArray *ext_information = NULL; + GArray *slot_eids = NULL; + guint i; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_uim_get_slot_status_finish (client, res, &error); + if (!output || + !qmi_message_uim_get_slot_status_output_get_result (output, &error) || + !qmi_message_uim_get_slot_status_output_get_physical_slot_status (output, &physical_slots, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* It's fine if we don't have EID information, but it should be well-formed if present. If it's malformed, + * there is probably a modem firmware bug. */ + if (qmi_message_uim_get_slot_status_output_get_physical_slot_information (output, &ext_information, NULL) && + qmi_message_uim_get_slot_status_output_get_slot_eid_information (output, &slot_eids, NULL) && + (ext_information->len != physical_slots->len || slot_eids->len != physical_slots->len)) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "UIM Get Slot Status returned malformed response"); + g_object_unref (task); + return; + } + + ctx->sim_slots = g_ptr_array_new_full (physical_slots->len, (GDestroyNotify) sim_slot_free); + + for (i = 0; i < physical_slots->len; i++) { + QmiPhysicalSlotStatusSlot *slot_status; + QmiPhysicalSlotInformationSlot *slot_info; + MMBaseSim *sim; + g_autofree gchar *raw_iccid = NULL; + g_autofree gchar *iccid = NULL; + g_autofree gchar *eid = NULL; + g_autoptr(GError) inner_error = NULL; + gboolean sim_active = FALSE; + + /* Store active slot info */ + slot_status = &g_array_index (physical_slots, QmiPhysicalSlotStatusSlot, i); + if (slot_status->physical_slot_status == QMI_UIM_SLOT_STATE_ACTIVE) { + sim_active = TRUE; + ctx->active_logical_id = slot_status->logical_slot; + ctx->active_slot_number = i + 1; + ctx->current_slot_number = ctx->active_slot_number; + } + + if (!slot_status->iccid->len) { + mm_obj_dbg (self, "not creating SIM object: no SIM in slot %u", i + 1); + g_ptr_array_add (ctx->sim_slots, NULL); + continue; + } + + raw_iccid = mm_bcd_to_string ((const guint8 *)slot_status->iccid->data, slot_status->iccid->len, + TRUE /* low_nybble_first */); + if (!raw_iccid) { + mm_obj_warn (self, "not creating SIM object: failed to convert ICCID from BCD"); + g_ptr_array_add (ctx->sim_slots, NULL); + continue; + } + + iccid = mm_3gpp_parse_iccid (raw_iccid, &inner_error); + if (!iccid) { + mm_obj_warn (self, "not creating SIM object: couldn't parse SIM iccid: %s", inner_error->message); + g_ptr_array_add (ctx->sim_slots, NULL); + continue; + } + + if (ext_information && slot_eids) { + slot_info = &g_array_index (ext_information, QmiPhysicalSlotInformationSlot, i); + if (slot_info->is_euicc) { + GArray *slot_eid; + + slot_eid = g_array_index (slot_eids, GArray *, i); + if (slot_eid->len) + eid = mm_qmi_uim_decode_eid (slot_eid->data, slot_eid->len); + if (!eid) + mm_obj_dbg (self, "SIM in slot %d is marked as eUICC, but has malformed EID", i + 1); + } + } + + sim = mm_sim_qmi_new_initialized (MM_BASE_MODEM (self), + TRUE, /* consider DMS UIM deprecated if we're creating SIM slots */ + i + 1, /* slot number is the array index starting at 1 */ + sim_active, + iccid, + NULL, /* imsi unknown */ + eid, /* may be NULL, which is fine */ + NULL, /* operator id unknown */ + NULL, /* operator name unknown */ + NULL); /* emergency numbers unknown */ + g_ptr_array_add (ctx->sim_slots, sim); + + if (sim_active) + ctx->sorted_sims = g_list_append (ctx->sorted_sims, g_object_ref (sim)); + else + ctx->sorted_sims = g_list_prepend (ctx->sorted_sims, g_object_ref (sim)); + } + g_assert_cmpuint (ctx->sim_slots->len, ==, physical_slots->len); + + /* Now, iterate over all the SIMs, we'll attempt to load info from them by + * quickly switching over to them, leaving the active SIM to the end */ + load_next_sim_info (task); +} + +void +mm_shared_qmi_load_sim_slots (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + LoadSimSlotsContext *ctx; + GTask *task; + QmiClient *client = NULL; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_UIM, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + ctx = g_slice_new0 (LoadSimSlotsContext); + ctx->client_uim = g_object_ref (client); + g_task_set_task_data (task, ctx, (GDestroyNotify) load_sim_slots_context_free); + + qmi_client_uim_get_slot_status (ctx->client_uim, + NULL, + 10, + NULL, + (GAsyncReadyCallback) uim_get_slot_status_ready, + task); +} + +/*****************************************************************************/ +/* Set Primary SIM slot (modem interface) */ + +gboolean +mm_shared_qmi_set_primary_sim_slot_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +uim_switch_slot_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimSwitchSlotOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + + self = g_task_get_source_object (task); + + output = qmi_client_uim_switch_slot_finish (client, res, &error); + if (!output || !qmi_message_uim_switch_slot_output_get_result (output, &error)) { + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NO_EFFECT)) + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_EXISTS, + "SIM slot switch operation not needed"); + else + g_task_return_error (task, g_steal_pointer (&error)); + } else { + mm_obj_info (self, "SIM slot switch operation request successful"); + g_task_return_boolean (task, TRUE); + } + g_object_unref (task); +} + +static void +uim_switch_get_slot_status_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimGetSlotStatusOutput) output = NULL; + g_autoptr(QmiMessageUimSwitchSlotInput) input = NULL; + MMIfaceModem *self; + GError *error = NULL; + GArray *physical_slots = NULL; + guint i; + guint active_logical_id = 0; + guint active_slot_number; + guint slot_number; + + self = g_task_get_source_object (task); + slot_number = GPOINTER_TO_UINT (g_task_get_task_data (task)); + + output = qmi_client_uim_get_slot_status_finish (client, res, &error); + if (!output || + !qmi_message_uim_get_slot_status_output_get_result (output, &error) || + !qmi_message_uim_get_slot_status_output_get_physical_slot_status (output, &physical_slots, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + for (i = 0; i < physical_slots->len; i++) { + QmiPhysicalSlotStatusSlot *slot_status; + + /* We look for the currently ACTIVE SIM card only! */ + slot_status = &g_array_index (physical_slots, QmiPhysicalSlotStatusSlot, i); + if (slot_status->physical_slot_status != QMI_UIM_SLOT_STATE_ACTIVE) + continue; + + active_logical_id = slot_status->logical_slot; + active_slot_number = i + 1; + } + + if (!active_logical_id) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "couldn't find active slot logical ID"); + g_object_unref (task); + return; + } + + if (active_slot_number == slot_number) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_EXISTS, + "SIM slot switch operation not needed"); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "requesting active logical id %d switch to SIM slot %u", active_logical_id, slot_number); + + input = qmi_message_uim_switch_slot_input_new (); + qmi_message_uim_switch_slot_input_set_logical_slot (input, (guint8) active_logical_id, NULL); + qmi_message_uim_switch_slot_input_set_physical_slot (input, slot_number, NULL); + qmi_client_uim_switch_slot (client, + input, + 10, + NULL, + (GAsyncReadyCallback) uim_switch_slot_ready, + task); +} + +void +mm_shared_qmi_set_primary_sim_slot (MMIfaceModem *self, + guint sim_slot, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + QmiClient *client = NULL; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_UIM, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + g_task_set_task_data (task, GUINT_TO_POINTER (sim_slot), NULL); + + qmi_client_uim_get_slot_status (QMI_CLIENT_UIM (client), + NULL, + 10, + NULL, + (GAsyncReadyCallback) uim_switch_get_slot_status_ready, + task); +} + +/*****************************************************************************/ +/* SIM hot swap detection */ + +#define REFRESH_START_TIMEOUT_SECS 3 + +gboolean +mm_shared_qmi_setup_sim_hot_swap_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +uim_refresh_complete (QmiClientUim *client, + QmiUimSessionType session_type) +{ + g_autoptr(QmiMessageUimRefreshCompleteInput) refresh_complete_input = NULL; + GArray *dummy_aid; + + dummy_aid = g_array_new (FALSE, FALSE, sizeof (guint8)); + + refresh_complete_input = qmi_message_uim_refresh_complete_input_new (); + qmi_message_uim_refresh_complete_input_set_session ( + refresh_complete_input, + session_type, + dummy_aid, /* ignored */ + NULL); + qmi_message_uim_refresh_complete_input_set_info ( + refresh_complete_input, + TRUE, + NULL); + + qmi_client_uim_refresh_complete ( + client, + refresh_complete_input, + 10, + NULL, + NULL, + NULL); + g_array_unref (dummy_aid); +} + +static gboolean +uim_start_refresh_timeout (MMSharedQmi *self) +{ + Private *priv; + + priv = get_private (self); + priv->uim_refresh_start_timeout_id = 0; + + mm_obj_dbg (self, "refresh start timed out; trigger SIM change check"); + + mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL); + + return G_SOURCE_REMOVE; +} + +static void +uim_refresh_indication_cb (QmiClientUim *client, + QmiIndicationUimRefreshOutput *output, + MMSharedQmi *self) +{ + QmiUimRefreshStage stage; + QmiUimRefreshMode mode; + QmiUimSessionType session_type; + Private *priv; + g_autoptr(GError) error = NULL; + + priv = get_private (self); + + if (!qmi_indication_uim_refresh_output_get_event (output, + &stage, + &mode, + &session_type, + NULL, + NULL, + &error)) { + mm_obj_warn (self, "couldn't process UIM refresh indication: %s", error->message); + return; + } + + mm_obj_dbg (self, "refresh indication received: session type '%s', stage '%s', mode '%s'", + qmi_uim_session_type_get_string (session_type), + qmi_uim_refresh_stage_get_string (stage), + qmi_uim_refresh_mode_get_string (mode)); + + /* Support only the first slot for now. Primary GW provisioning is used in old modems. */ + if (session_type != QMI_UIM_SESSION_TYPE_CARD_SLOT_1 && + session_type != QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING) { + mm_obj_warn (self, "refresh session type not supported: %s", qmi_uim_session_type_get_string (session_type)); + return; + } + + /* Currently we handle only UICC Reset type refresh, which can be used + * in profile switch scenarios. In other cases we just trigger 'refresh + * complete' during start phase. Signal to notify about potential SIM + * profile switch is triggered when the refresh is ending. If it were + * triggered in start phase, reading SIM files seems to fail with + * an internal error. + * + * It's possible that 'end-with-success' stage never appears. For that, + * we start a timer at 'start' stage and if it expires, the SIM change + * check is triggered anyway. */ + if (stage == QMI_UIM_REFRESH_STAGE_START) { + if (mode == QMI_UIM_REFRESH_MODE_RESET) { + if (!priv->uim_refresh_start_timeout_id) + priv->uim_refresh_start_timeout_id = g_timeout_add_seconds (REFRESH_START_TIMEOUT_SECS, + (GSourceFunc)uim_start_refresh_timeout, + self); + } else + uim_refresh_complete (client, session_type); + } else if (stage == QMI_UIM_REFRESH_STAGE_END_WITH_SUCCESS) { + if (mode == QMI_UIM_REFRESH_MODE_RESET) { + if (priv->uim_refresh_start_timeout_id) { + g_source_remove (priv->uim_refresh_start_timeout_id); + priv->uim_refresh_start_timeout_id = 0; + } + mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL); + } + } +} + +static void +uim_slot_status_indication_cb (QmiClientUim *client, + QmiIndicationUimSlotStatusOutput *output, + MMSharedQmi *self) +{ + GArray *physical_slots = NULL; + guint i; + g_autoptr(GError) error = NULL; + + mm_obj_dbg (self, "received slot status indication"); + + if (!qmi_indication_uim_slot_status_output_get_physical_slot_status (output, + &physical_slots, + &error)) { + mm_obj_warn (self, "could not process slot status indication: %s", error->message); + return; + } + + for (i = 0; i < physical_slots->len; i++) { + QmiPhysicalSlotStatusSlot *slot_status; + + slot_status = &g_array_index (physical_slots, QmiPhysicalSlotStatusSlot, i); + + /* We only care about active slot changes */ + if (slot_status->physical_slot_status == QMI_UIM_SLOT_STATE_ACTIVE) { + g_autofree gchar *iccid = NULL; + + if (slot_status->iccid && slot_status->iccid->len > 0) { + iccid = mm_bcd_to_string ((const guint8 *) slot_status->iccid->data, slot_status->iccid->len, + TRUE /* low_nybble_first */); + } + + mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), + i + 1, /* Slot index */ + iccid, + NULL, + NULL); + } + } +} + +static void +uim_refresh_register_iccid_change_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + MMSharedQmi *self; + Private *priv; + g_autoptr(QmiMessageUimRefreshRegisterOutput) output = NULL; + g_autoptr(GError) error = NULL; + + self = g_task_get_source_object (task); + priv = get_private (self); + + output = qmi_client_uim_refresh_register_finish (client, res, &error); + if (!output || !qmi_message_uim_refresh_register_output_get_result (output, &error)) { + mm_obj_dbg (self, "refresh registration using 'refresh register' failed: %s", error->message); + g_clear_object (&priv->uim_client); + g_task_return_new_error (task, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, + "SIM hot swap detection not supported by modem"); + } else { + mm_obj_dbg (self, "registered for SIM refresh events using 'refresh register'"); + priv->uim_refresh_indication_id = + g_signal_connect (client, + "refresh", + G_CALLBACK (uim_refresh_indication_cb), + self); + g_task_return_boolean (task, TRUE); + } + g_object_unref (task); +} + +/* This is the last resort if 'refresh register all' does not work. It works + * on some older modems. Those modems may not also support QMI_UIM_SESSION_TYPE_CARD_SLOT_1 + * so we'll use QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING */ +static void +uim_refresh_register_iccid_change (GTask *task) +{ + MMSharedQmi *self; + Private *priv; + QmiMessageUimRefreshRegisterInputInfoFilesElement file_element; + guint8 val; + g_autoptr(QmiMessageUimRefreshRegisterInput) refresh_register_input = NULL; + g_autoptr(GArray) dummy_aid = NULL; + g_autoptr(GArray) file = NULL; + g_autoptr(GArray) file_element_path = NULL; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + + mm_obj_dbg (self, "register for refresh file indication"); + + dummy_aid = g_array_new (FALSE, FALSE, sizeof (guint8)); + + file = g_array_sized_new (FALSE, FALSE, sizeof (QmiMessageUimRefreshRegisterInputInfoFilesElement), 1); + + file_element_path = g_array_sized_new (FALSE, FALSE, sizeof (guint8), 2); + val = 0x00; + g_array_append_val (file_element_path, val); + val = 0x3F; + g_array_append_val (file_element_path, val); + + + memset (&file_element, 0, sizeof (file_element)); + file_element.file_id = 0x2FE2; /* ICCID */ + file_element.path = file_element_path; + g_array_append_val (file, file_element); + + refresh_register_input = qmi_message_uim_refresh_register_input_new (); + qmi_message_uim_refresh_register_input_set_info (refresh_register_input, + TRUE, + FALSE, + file, + NULL); + qmi_message_uim_refresh_register_input_set_session (refresh_register_input, + QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING, + dummy_aid, + NULL); + + qmi_client_uim_refresh_register (QMI_CLIENT_UIM (priv->uim_client), + refresh_register_input, + 10, + NULL, + (GAsyncReadyCallback) uim_refresh_register_iccid_change_ready, + task); +} + +/* Refresh registration and event handling. + * This is used only as fallback in case slot status indications do not work + * in the particular modem (determined by UIM Get Slot Status failing) for + * detecting ICCID changing due to a profile switch. + * + * We assume that devices not supporting UIM Get Slot Status only have a + * single slot, for which we register refresh events. + */ + +static void +uim_refresh_register_all_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimRefreshRegisterAllOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + Private *priv; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + + output = qmi_client_uim_refresh_register_all_finish (client, res, &error); + if (!output || !qmi_message_uim_refresh_register_all_output_get_result (output, &error)) { + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NOT_SUPPORTED) || + g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) { + /* As last resort, if 'refresh register all' fails, try a plain 'refresh register'. + * Some older modems may not support 'refresh register all'. */ + uim_refresh_register_iccid_change (task); + return; + } + + mm_obj_dbg (self, "refresh register all operation failed: %s", error->message); + g_clear_object (&priv->uim_client); + g_task_return_error (task, g_steal_pointer (&error)); + } else { + mm_obj_dbg (self, "registered for all SIM refresh events"); + priv->uim_refresh_indication_id = + g_signal_connect (client, + "refresh", + G_CALLBACK (uim_refresh_indication_cb), + self); + g_task_return_boolean (task, TRUE); + } + g_object_unref (task); +} + +static void +uim_slot_status_not_supported (GTask *task) +{ + MMIfaceModem *self; + Private *priv; + g_autoptr(QmiMessageUimRefreshRegisterAllInput) refresh_register_all_input = NULL; + g_autoptr(GArray) dummy_aid = NULL; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + + g_assert (!priv->uim_refresh_indication_id); + + mm_obj_dbg (self, "slot status not supported by modem: register for refresh indications"); + + dummy_aid = g_array_new (FALSE, FALSE, sizeof (guint8)); + refresh_register_all_input = qmi_message_uim_refresh_register_all_input_new (); + + qmi_message_uim_refresh_register_all_input_set_info (refresh_register_all_input, + TRUE, + NULL); + qmi_message_uim_refresh_register_all_input_set_session (refresh_register_all_input, + QMI_UIM_SESSION_TYPE_CARD_SLOT_1, + dummy_aid, + NULL); + + qmi_client_uim_refresh_register_all (QMI_CLIENT_UIM (priv->uim_client), + refresh_register_all_input, + 10, + NULL, + (GAsyncReadyCallback) uim_refresh_register_all_ready, + task); +} + +static void +uim_check_get_slot_status_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimGetSlotStatusOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + Private *priv; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + + output = qmi_client_uim_get_slot_status_finish (client, res, &error); + if (!output || !qmi_message_uim_get_slot_status_output_get_result (output, &error)) { + if (priv->uim_slot_status_indication_id) { + g_signal_handler_disconnect (client, priv->uim_slot_status_indication_id); + priv->uim_slot_status_indication_id = 0; + } + + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NOT_SUPPORTED) || + g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) { + uim_slot_status_not_supported (task); + return; + } + + mm_obj_dbg (self, "slot status retrieval failed: %s", error->message); + g_clear_object (&priv->uim_client); + g_task_return_error (task, g_steal_pointer (&error)); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "slot status retrieval succeeded: monitoring slot status indications"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +uim_register_events_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimRegisterEventsOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMIfaceModem *self; + Private *priv; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + + /* If event registration fails, go on with initialization. In that case + * we cannot use slot status indications to detect eUICC profile switches. */ + output = qmi_client_uim_register_events_finish (client, res, &error); + if (output && qmi_message_uim_register_events_output_get_result (output, &error)) { + g_assert (!priv->uim_slot_status_indication_id); + priv->uim_slot_status_indication_id = g_signal_connect (priv->uim_client, + "slot-status", + G_CALLBACK (uim_slot_status_indication_cb), + self); + mm_obj_dbg (self, "registered for slot status indications"); + + /* Successful registration does not mean that the modem actually sends + * physical slot status indications; invoke Get Slot Status to find out if + * the modem really supports slot status. */ + qmi_client_uim_get_slot_status (client, + NULL, + 10, + NULL, + (GAsyncReadyCallback) uim_check_get_slot_status_ready, + task); + return; + } + + mm_obj_dbg (self, "not registered for slot status indications: %s", error->message); + uim_slot_status_not_supported (task); +} + +void +mm_shared_qmi_setup_sim_hot_swap (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(QmiMessageUimRegisterEventsInput) register_events_input = NULL; + GTask *task; + QmiClient *client = NULL; + Private *priv; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_UIM, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + priv = get_private (MM_SHARED_QMI (self)); + + g_assert (!priv->uim_slot_status_indication_id); + g_assert (!priv->uim_client); + priv->uim_client = g_object_ref (client); + + register_events_input = qmi_message_uim_register_events_input_new (); + qmi_message_uim_register_events_input_set_event_registration_mask (register_events_input, + QMI_UIM_EVENT_REGISTRATION_FLAG_PHYSICAL_SLOT_STATUS, + NULL); + qmi_client_uim_register_events (QMI_CLIENT_UIM (priv->uim_client), + register_events_input, + 10, + NULL, + (GAsyncReadyCallback) uim_register_events_ready, + task); +} + +/*****************************************************************************/ +/* FCC unlock (Modem interface) */ + +gboolean +mm_shared_qmi_fcc_unlock_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +dms_set_fcc_authentication_ready (QmiClientDms *client, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + g_autoptr(QmiMessageDmsSetFccAuthenticationOutput) output = NULL; + + output = qmi_client_dms_set_fcc_authentication_finish (client, res, &error); + if (!output || !qmi_message_dms_set_fcc_authentication_output_get_result (output, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +void +mm_shared_qmi_fcc_unlock (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + QmiClient *client = NULL; + + if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), + QMI_SERVICE_DMS, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + qmi_client_dms_set_fcc_authentication (QMI_CLIENT_DMS (client), + NULL, + 5, + NULL, + (GAsyncReadyCallback)dms_set_fcc_authentication_ready, + task); +} + +/*****************************************************************************/ +/* Location: Set SUPL server */ + +typedef struct { + QmiClient *client; + gchar *supl; + glong indication_id; + guint timeout_id; +} SetSuplServerContext; + +static void +set_supl_server_context_free (SetSuplServerContext *ctx) +{ + if (ctx->client) { + if (ctx->timeout_id) + g_source_remove (ctx->timeout_id); + if (ctx->indication_id) + g_signal_handler_disconnect (ctx->client, ctx->indication_id); + g_object_unref (ctx->client); + } + g_slice_free (SetSuplServerContext, ctx); +} + +static GArray * +parse_as_utf16_url (const gchar *supl) +{ + GArray *url; + gchar *utf16; + gsize utf16_len; + + utf16 = g_convert (supl, -1, "UTF-16BE", "UTF-8", NULL, &utf16_len, NULL); + url = g_array_append_vals (g_array_sized_new (FALSE, FALSE, sizeof (guint8), utf16_len), + utf16, utf16_len); + g_free (utf16); + return url; +} + +gboolean +mm_shared_qmi_location_set_supl_server_finish (MMIfaceModemLocation *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +pds_set_agps_config_ready (QmiClientPds *client, + GAsyncResult *res, + GTask *task) +{ + QmiMessagePdsSetAgpsConfigOutput *output; + GError *error = NULL; + + output = qmi_client_pds_set_agps_config_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!qmi_message_pds_set_agps_config_output_get_result (output, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); + + qmi_message_pds_set_agps_config_output_unref (output); +} + +static void +pds_set_supl_server (GTask *task) +{ + MMSharedQmi *self; + SetSuplServerContext *ctx; + QmiMessagePdsSetAgpsConfigInput *input; + guint32 ip; + guint16 port; + GArray *url; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + input = qmi_message_pds_set_agps_config_input_new (); + + /* For multimode devices, prefer UMTS by default */ + if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) + qmi_message_pds_set_agps_config_input_set_network_mode (input, QMI_PDS_NETWORK_MODE_UMTS, NULL); + else if (mm_iface_modem_is_cdma (MM_IFACE_MODEM (self))) + qmi_message_pds_set_agps_config_input_set_network_mode (input, QMI_PDS_NETWORK_MODE_CDMA, NULL); + + if (mm_parse_supl_address (ctx->supl, NULL, &ip, &port, NULL)) + qmi_message_pds_set_agps_config_input_set_location_server_address (input, ip, port, NULL); + else { url = parse_as_utf16_url (ctx->supl); qmi_message_pds_set_agps_config_input_set_location_server_url (input, url, NULL); g_array_unref (url); @@ -3828,15 +4911,15 @@ pds_location_event_report_indication_cb (QmiClientPds *clie output, &session_status, NULL)) { - mm_dbg ("[GPS] session status changed: '%s'", - qmi_pds_position_session_status_get_string (session_status)); + mm_obj_dbg (self, "[GPS] session status changed: '%s'", + qmi_pds_position_session_status_get_string (session_status)); } if (qmi_indication_pds_event_report_output_get_nmea_position ( output, &nmea, NULL)) { - mm_dbg ("[NMEA] %s", nmea); + mm_obj_dbg (self, "[NMEA] %s", nmea); mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), nmea); } } @@ -3852,10 +4935,234 @@ loc_location_nmea_indication_cb (QmiClientLoc *client, if (!nmea) return; - mm_dbg ("[NMEA] %s", nmea); + mm_obj_dbg (self, "[NMEA] %s", nmea); mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), nmea); } +/*****************************************************************************/ +/* Location: internal helper: setup minimum required NMEA traces */ + +typedef struct { + QmiClientLoc *client; + guint timeout_id; + gulong indication_id; +} SetupRequiredNmeaTracesContext; + +static void +setup_required_nmea_traces_cleanup_action (SetupRequiredNmeaTracesContext *ctx) +{ + if (ctx->indication_id) { + g_signal_handler_disconnect (ctx->client, ctx->indication_id); + ctx->indication_id = 0; + } + if (ctx->timeout_id) { + g_source_remove (ctx->timeout_id); + ctx->timeout_id = 0; + } +} + +static void +setup_required_nmea_traces_context_free (SetupRequiredNmeaTracesContext *ctx) +{ + setup_required_nmea_traces_cleanup_action (ctx); + g_clear_object (&ctx->client); + g_slice_free (SetupRequiredNmeaTracesContext, ctx); +} + +static gboolean +setup_required_nmea_traces_finish (MMSharedQmi *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static gboolean +setup_required_nmea_traces_timeout (GTask *task) +{ + SetupRequiredNmeaTracesContext *ctx; + + ctx = g_task_get_task_data (task); + g_assert (ctx->timeout_id); + setup_required_nmea_traces_cleanup_action (ctx); + + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, + "Operation timed out"); + g_object_unref (task); + return G_SOURCE_REMOVE; +} + +static void +loc_set_nmea_types_indication_cb (QmiClientLoc *client, + QmiIndicationLocSetNmeaTypesOutput *output, + GTask *task) +{ + SetupRequiredNmeaTracesContext *ctx; + QmiLocIndicationStatus status; + GError *error = NULL; + + ctx = g_task_get_task_data (task); + g_assert (ctx->indication_id); + setup_required_nmea_traces_cleanup_action (ctx); + + if (!qmi_indication_loc_set_nmea_types_output_get_indication_status (output, &status, &error) || + !mm_error_from_qmi_loc_indication_status (status, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +loc_set_nmea_types_ready (QmiClientLoc *client, + GAsyncResult *res, + GTask *task) +{ + SetupRequiredNmeaTracesContext *ctx; + GError *error = NULL; + g_autoptr(QmiMessageLocSetNmeaTypesOutput) output = NULL; + + output = qmi_client_loc_set_nmea_types_finish (client, res, &error); + if (!output || !qmi_message_loc_set_nmea_types_output_get_result (output, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* The task ownership is shared between signal and timeout; the one which is + * scheduled first will cancel the other. */ + ctx = g_task_get_task_data (task); + g_assert (!ctx->indication_id); + ctx->indication_id = g_signal_connect (ctx->client, + "set-nmea-types", + G_CALLBACK (loc_set_nmea_types_indication_cb), + task); + g_assert (!ctx->timeout_id); + ctx->timeout_id = g_timeout_add_seconds (10, + (GSourceFunc)setup_required_nmea_traces_timeout, + task); +} + +static void +loc_get_nmea_types_indication_cb (QmiClientLoc *client, + QmiIndicationLocGetNmeaTypesOutput *output, + GTask *task) +{ + SetupRequiredNmeaTracesContext *ctx; + QmiLocIndicationStatus status; + QmiLocNmeaType nmea_types_mask = 0; + QmiLocNmeaType desired_nmea_types_mask = (QMI_LOC_NMEA_TYPE_GGA | QMI_LOC_NMEA_TYPE_GSA | QMI_LOC_NMEA_TYPE_GSV); + GError *error = NULL; + g_autoptr(QmiMessageLocSetNmeaTypesInput) input = NULL; + + ctx = g_task_get_task_data (task); + g_assert (ctx->indication_id); + setup_required_nmea_traces_cleanup_action (ctx); + + if (!qmi_indication_loc_get_nmea_types_output_get_indication_status (output, &status, &error) || + !mm_error_from_qmi_loc_indication_status (status, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + qmi_indication_loc_get_nmea_types_output_get_nmea_types (output, &nmea_types_mask, NULL); + + /* If the configured NMEA types already include GGA, GSV and GSA, we're fine. For raw + * GPS sources GGA is the only required one, the other two are given for completeness */ + if ((nmea_types_mask & desired_nmea_types_mask) == desired_nmea_types_mask) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + input = qmi_message_loc_set_nmea_types_input_new (); + qmi_message_loc_set_nmea_types_input_set_nmea_types (input, (nmea_types_mask | desired_nmea_types_mask), NULL); + qmi_client_loc_set_nmea_types (ctx->client, + input, + 10, + NULL, + (GAsyncReadyCallback)loc_set_nmea_types_ready, + task); +} + +static void +loc_get_nmea_types_ready (QmiClientLoc *client, + GAsyncResult *res, + GTask *task) +{ + SetupRequiredNmeaTracesContext *ctx; + GError *error = NULL; + g_autoptr(QmiMessageLocGetNmeaTypesOutput) output = NULL; + + output = qmi_client_loc_get_nmea_types_finish (client, res, &error); + if (!output || !qmi_message_loc_get_nmea_types_output_get_result (output, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* The task ownership is shared between signal and timeout; the one which is + * scheduled first will cancel the other. */ + ctx = g_task_get_task_data (task); + g_assert (!ctx->indication_id); + ctx->indication_id = g_signal_connect (ctx->client, + "get-nmea-types", + G_CALLBACK (loc_get_nmea_types_indication_cb), + task); + g_assert (!ctx->timeout_id); + ctx->timeout_id = g_timeout_add_seconds (10, + (GSourceFunc)setup_required_nmea_traces_timeout, + task); +} + +static void +setup_required_nmea_traces (MMSharedQmi *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + QmiClient *client; + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + /* If using PDS, no further setup required */ + client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_PDS, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + if (client) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + /* Otherwise LOC */ + client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_LOC, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + if (client) { + SetupRequiredNmeaTracesContext *ctx; + + ctx = g_slice_new0 (SetupRequiredNmeaTracesContext); + ctx->client = g_object_ref (client); + g_task_set_task_data (task, ctx, (GDestroyNotify)setup_required_nmea_traces_context_free); + + qmi_client_loc_get_nmea_types (ctx->client, + NULL, + 10, + NULL, + (GAsyncReadyCallback)loc_get_nmea_types_ready, + task); + return; + } + + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't find any PDS/LOC client"); + g_object_unref (task); +} + /*****************************************************************************/ /* Location: internal helper: start gps engine */ @@ -4182,11 +5489,13 @@ pds_set_default_tracking_session_ready (QmiClientPds *client, GAsyncResult *res, GTask *task) { + MMSharedQmi *self; SetGpsOperationModeContext *ctx; QmiMessagePdsSetDefaultTrackingSessionOutput *output; GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); output = qmi_client_pds_set_default_tracking_session_finish (client, res, &error); if (!output) { @@ -4208,13 +5517,13 @@ pds_set_default_tracking_session_ready (QmiClientPds *client, switch (ctx->mode) { case GPS_OPERATION_MODE_AGPS_MSA: - mm_dbg ("MSA A-GPS operation mode enabled"); + mm_obj_dbg (self, "MSA A-GPS operation mode enabled"); break; case GPS_OPERATION_MODE_AGPS_MSB: - mm_dbg ("MSB A-GPS operation mode enabled"); + mm_obj_dbg (self, "MSB A-GPS operation mode enabled"); break; case GPS_OPERATION_MODE_STANDALONE: - mm_dbg ("Standalone mode enabled (A-GPS disabled)"); + mm_obj_dbg (self, "standalone mode enabled (A-GPS disabled)"); break; case GPS_OPERATION_MODE_UNKNOWN: default: @@ -4229,6 +5538,7 @@ pds_get_default_tracking_session_ready (QmiClientPds *client, GAsyncResult *res, GTask *task) { + MMSharedQmi *self; SetGpsOperationModeContext *ctx; QmiMessagePdsSetDefaultTrackingSessionInput *input; QmiMessagePdsGetDefaultTrackingSessionOutput *output; @@ -4238,6 +5548,9 @@ pds_get_default_tracking_session_ready (QmiClientPds *client, guint32 interval; guint32 accuracy_threshold; + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + output = qmi_client_pds_get_default_tracking_session_finish (client, res, &error); if (!output) { g_prefix_error (&error, "QMI operation failed: "); @@ -4254,8 +5567,6 @@ pds_get_default_tracking_session_ready (QmiClientPds *client, return; } - ctx = g_task_get_task_data (task); - qmi_message_pds_get_default_tracking_session_output_get_info ( output, &session_operation, @@ -4268,30 +5579,30 @@ pds_get_default_tracking_session_ready (QmiClientPds *client, if (ctx->mode == GPS_OPERATION_MODE_AGPS_MSA) { if (session_operation == QMI_PDS_OPERATING_MODE_MS_ASSISTED) { - mm_dbg ("MSA A-GPS already enabled"); + mm_obj_dbg (self, "MSA A-GPS already enabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to enable MSA A-GPS"); + mm_obj_dbg (self, "need to enable MSA A-GPS"); session_operation = QMI_PDS_OPERATING_MODE_MS_ASSISTED; } else if (ctx->mode == GPS_OPERATION_MODE_AGPS_MSB) { if (session_operation == QMI_PDS_OPERATING_MODE_MS_BASED) { - mm_dbg ("MSB A-GPS already enabled"); + mm_obj_dbg (self, "MSB A-GPS already enabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to enable MSB A-GPS"); + mm_obj_dbg (self, "need to enable MSB A-GPS"); session_operation = QMI_PDS_OPERATING_MODE_MS_BASED; } else if (ctx->mode == GPS_OPERATION_MODE_STANDALONE) { if (session_operation == QMI_PDS_OPERATING_MODE_STANDALONE) { - mm_dbg ("A-GPS already disabled"); + mm_obj_dbg (self, "A-GPS already disabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to disable A-GPS"); + mm_obj_dbg (self, "need to disable A-GPS"); session_operation = QMI_PDS_OPERATING_MODE_STANDALONE; } else g_assert_not_reached (); @@ -4333,11 +5644,13 @@ loc_location_set_operation_mode_indication_cb (QmiClientLoc QmiIndicationLocSetOperationModeOutput *output, GTask *task) { + MMSharedQmi *self; SetGpsOperationModeContext *ctx; QmiLocIndicationStatus status; GError *error = NULL; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!qmi_indication_loc_set_operation_mode_output_get_indication_status (output, &status, &error)) { g_prefix_error (&error, "QMI operation failed: "); @@ -4354,13 +5667,13 @@ loc_location_set_operation_mode_indication_cb (QmiClientLoc switch (ctx->mode) { case GPS_OPERATION_MODE_AGPS_MSA: - mm_dbg ("MSA A-GPS operation mode enabled"); + mm_obj_dbg (self, "MSA A-GPS operation mode enabled"); break; case GPS_OPERATION_MODE_AGPS_MSB: - mm_dbg ("MSB A-GPS operation mode enabled"); + mm_obj_dbg (self, "MSB A-GPS operation mode enabled"); break; case GPS_OPERATION_MODE_STANDALONE: - mm_dbg ("Standalone mode enabled (A-GPS disabled)"); + mm_obj_dbg (self, "standalone mode enabled (A-GPS disabled)"); break; case GPS_OPERATION_MODE_UNKNOWN: default: @@ -4414,13 +5727,15 @@ loc_location_get_operation_mode_indication_cb (QmiClientLoc QmiIndicationLocGetOperationModeOutput *output, GTask *task) { + MMSharedQmi *self; SetGpsOperationModeContext *ctx; QmiLocIndicationStatus status; GError *error = NULL; QmiLocOperationMode mode = QMI_LOC_OPERATION_MODE_DEFAULT; QmiMessageLocSetOperationModeInput *input; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); if (!qmi_indication_loc_get_operation_mode_output_get_indication_status (output, &status, &error)) { g_prefix_error (&error, "QMI operation failed: "); @@ -4439,30 +5754,30 @@ loc_location_get_operation_mode_indication_cb (QmiClientLoc if (ctx->mode == GPS_OPERATION_MODE_AGPS_MSA) { if (mode == QMI_LOC_OPERATION_MODE_MSA) { - mm_dbg ("MSA A-GPS already enabled"); + mm_obj_dbg (self, "MSA A-GPS already enabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to enable MSA A-GPS"); + mm_obj_dbg (self, "need to enable MSA A-GPS"); mode = QMI_LOC_OPERATION_MODE_MSA; } else if (ctx->mode == GPS_OPERATION_MODE_AGPS_MSB) { if (mode == QMI_LOC_OPERATION_MODE_MSB) { - mm_dbg ("MSB A-GPS already enabled"); + mm_obj_dbg (self, "MSB A-GPS already enabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to enable MSB A-GPS"); + mm_obj_dbg (self, "need to enable MSB A-GPS"); mode = QMI_LOC_OPERATION_MODE_MSB; } else if (ctx->mode == GPS_OPERATION_MODE_STANDALONE) { if (mode == QMI_LOC_OPERATION_MODE_STANDALONE) { - mm_dbg ("A-GPS already disabled"); + mm_obj_dbg (self, "A-GPS already disabled"); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } - mm_dbg ("Need to disable A-GPS"); + mm_obj_dbg (self, "need to disable A-GPS"); mode = QMI_LOC_OPERATION_MODE_STANDALONE; } else g_assert_not_reached (); @@ -4733,6 +6048,22 @@ start_gps_engine_ready (MMSharedQmi *self, g_object_unref (task); } +static void +setup_required_nmea_traces_ready (MMSharedQmi *self, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(GError) error = NULL; + + /* don't treat this error as fatal */ + if (!setup_required_nmea_traces_finish (self, res, &error)) + mm_obj_warn (self, "couldn't setup required NMEA traces: %s", error->message); + + start_gps_engine (self, + (GAsyncReadyCallback)start_gps_engine_ready, + task); +} + static void set_gps_operation_mode_agps_ready (MMSharedQmi *self, GAsyncResult *res, @@ -4805,11 +6136,11 @@ parent_enable_location_gathering_ready (MMIfaceModemLocation *_self, return; } - /* Only start GPS engine if not done already */ + /* Only setup NMEA traces and start GPS engine if not done already */ if (!(priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW))) { - start_gps_engine (self, - (GAsyncReadyCallback)start_gps_engine_ready, - task); + setup_required_nmea_traces (self, + (GAsyncReadyCallback)setup_required_nmea_traces_ready, + task); return; } @@ -5254,13 +6585,15 @@ inject_xtra_data_ready (QmiClientLoc *client, static void inject_xtra_data_next (GTask *task) { + MMSharedQmi *self; QmiMessageLocInjectXtraDataInput *input; InjectAssistanceDataContext *ctx; goffset total_bytes_left; gsize count; GArray *data; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); g_assert (ctx->data_size >= ctx->i); total_bytes_left = ctx->data_size - ctx->i; @@ -5295,8 +6628,8 @@ inject_xtra_data_next (GTask *task) ctx->i += count; - mm_info ("injecting xtra data: %" G_GSIZE_FORMAT " bytes (%u/%u)", - count, (guint) ctx->n_part, (guint) ctx->total_parts); + mm_obj_info (self, "injecting xtra data: %" G_GSIZE_FORMAT " bytes (%u/%u)", + count, (guint) ctx->n_part, (guint) ctx->total_parts); qmi_client_loc_inject_xtra_data (ctx->client, input, 10, @@ -5401,13 +6734,15 @@ inject_predicted_orbits_data_ready (QmiClientLoc *client, static void inject_assistance_data_next (GTask *task) { + MMSharedQmi *self; QmiMessageLocInjectPredictedOrbitsDataInput *input; InjectAssistanceDataContext *ctx; goffset total_bytes_left; gsize count; GArray *data; - ctx = g_task_get_task_data (task); + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); g_assert (ctx->data_size >= ctx->i); total_bytes_left = ctx->data_size - ctx->i; @@ -5446,8 +6781,8 @@ inject_assistance_data_next (GTask *task) ctx->i += count; - mm_info ("injecting predicted orbits data: %" G_GSIZE_FORMAT " bytes (%u/%u)", - count, (guint) ctx->n_part, (guint) ctx->total_parts); + mm_obj_info (self, "injecting predicted orbits data: %" G_GSIZE_FORMAT " bytes (%u/%u)", + count, (guint) ctx->n_part, (guint) ctx->total_parts); qmi_client_loc_inject_predicted_orbits_data (ctx->client, input, 10, @@ -5498,7 +6833,7 @@ mm_shared_qmi_location_inject_assistance_data (MMIfaceModemLocation *self, ctx->total_parts++; g_assert (ctx->total_parts <= G_MAXUINT16); - mm_dbg ("Injecting gpsOneXTRA data (%" G_GOFFSET_FORMAT " bytes)...", ctx->data_size); + mm_obj_dbg (self, "injecting gpsOneXTRA data (%" G_GOFFSET_FORMAT " bytes)...", ctx->data_size); inject_assistance_data_next (task); } diff --git a/src/mm-shared-qmi.h b/src/mm-shared-qmi.h index 093896e0..3c2bdc42 100644 --- a/src/mm-shared-qmi.h +++ b/src/mm-shared-qmi.h @@ -49,6 +49,7 @@ struct _MMSharedQmi { }; GType mm_shared_qmi_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSharedQmi, g_object_unref) QmiClient *mm_shared_qmi_peek_client (MMSharedQmi *self, QmiService service, @@ -163,6 +164,33 @@ void mm_shared_qmi_setup_carrier_config (MMIfaceMode gboolean mm_shared_qmi_setup_carrier_config_finish (MMIfaceModem *self, GAsyncResult *res, GError **error); +void mm_shared_qmi_load_sim_slots (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_shared_qmi_load_sim_slots_finish (MMIfaceModem *self, + GAsyncResult *res, + GPtrArray **sim_slots, + guint *primary_sim_slot, + GError **error); +void mm_shared_qmi_set_primary_sim_slot (MMIfaceModem *self, + guint sim_slot, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_shared_qmi_set_primary_sim_slot_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); +void mm_shared_qmi_setup_sim_hot_swap (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_shared_qmi_setup_sim_hot_swap_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); +void mm_shared_qmi_fcc_unlock (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_shared_qmi_fcc_unlock_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error); /* Shared QMI location support */ diff --git a/src/mm-sim-mbim.c b/src/mm-sim-mbim.c index a2aa1eaf..e8889fa1 100644 --- a/src/mm-sim-mbim.c +++ b/src/mm-sim-mbim.c @@ -24,9 +24,10 @@ #define _LIBMM_INSIDE_MM #include +#include "mm-broadband-modem-mbim.h" #include "mm-error-helpers.h" #include "mm-iface-modem.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-modem-helpers-mbim.h" #include "mm-sim-mbim.h" @@ -48,7 +49,7 @@ peek_device (gpointer self, NULL); g_assert (MM_IS_BASE_MODEM (modem)); - port = mm_base_modem_peek_port_mbim (modem); + port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (modem)); g_object_unref (modem); if (!port) { @@ -382,10 +383,10 @@ pin_set_enter_ready (MbimDevice *device, /* Sending PIN failed, build a better error to report */ if (pin_type == MBIM_PIN_TYPE_PIN1 && pin_state == MBIM_PIN_STATE_LOCKED) { g_error_free (error); - error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD); + error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, self); } else if (pin_type == MBIM_PIN_TYPE_PUK1 && pin_state == MBIM_PIN_STATE_LOCKED) { g_error_free (error); - error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK); + error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK, self); } } } @@ -416,7 +417,7 @@ send_pin (MMBaseSim *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("Sending PIN..."); + mm_obj_dbg (self, "sending PIN..."); message = (mbim_message_pin_set_new ( MBIM_PIN_TYPE_PIN1, MBIM_PIN_OPERATION_ENTER, @@ -480,9 +481,9 @@ puk_set_enter_ready (MbimDevice *device, if (pin_type == MBIM_PIN_TYPE_PUK1 && pin_state == MBIM_PIN_STATE_LOCKED) { g_error_free (error); if (remaining_attempts == 0) - error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG); + error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG, self); else - error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD); + error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, self); } } } @@ -514,7 +515,7 @@ send_puk (MMBaseSim *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("Sending PUK..."); + mm_obj_dbg (self, "sending PUK..."); message = (mbim_message_pin_set_new ( MBIM_PIN_TYPE_PUK1, MBIM_PIN_OPERATION_ENTER, @@ -605,7 +606,7 @@ enable_pin (MMBaseSim *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("%s PIN ...", enabled ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s PIN ...", enabled ? "enabling" : "disabling"); message = (mbim_message_pin_set_new ( MBIM_PIN_TYPE_PIN1, enabled ? MBIM_PIN_OPERATION_ENABLE : MBIM_PIN_OPERATION_DISABLE, @@ -696,7 +697,7 @@ change_pin (MMBaseSim *self, task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("Changing PIN"); + mm_obj_dbg (self, "changing PIN..."); message = (mbim_message_pin_set_new ( MBIM_PIN_TYPE_PIN1, MBIM_PIN_OPERATION_CHANGE, @@ -752,6 +753,7 @@ mm_sim_mbim_new (MMBaseModem *modem, callback, user_data, MM_BASE_SIM_MODEM, modem, + "active", TRUE, /* by default always active */ NULL); } diff --git a/src/mm-sim-mbim.h b/src/mm-sim-mbim.h index f7bf6ab1..eb6b1e2e 100644 --- a/src/mm-sim-mbim.h +++ b/src/mm-sim-mbim.h @@ -40,6 +40,7 @@ struct _MMSimMbimClass { }; GType mm_sim_mbim_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSimMbim, g_object_unref) void mm_sim_mbim_new (MMBaseModem *modem, GCancellable *cancellable, diff --git a/src/mm-sim-qmi.c b/src/mm-sim-qmi.c index 9294a1fc..4d8ad043 100644 --- a/src/mm-sim-qmi.c +++ b/src/mm-sim-qmi.c @@ -25,8 +25,10 @@ #define _LIBMM_INSIDE_MM #include -#include "mm-log.h" +#include "mm-broadband-modem-qmi.h" +#include "mm-log-object.h" #include "mm-sim-qmi.h" +#include "mm-modem-helpers-qmi.h" G_DEFINE_TYPE (MMSimQmi, mm_sim_qmi, MM_TYPE_BASE_SIM) @@ -59,7 +61,7 @@ ensure_qmi_client (GTask *task, NULL); g_assert (MM_IS_BASE_MODEM (modem)); - port = mm_base_modem_peek_port_qmi (modem); + port = mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (modem)); g_object_unref (modem); if (!port) { @@ -88,6 +90,131 @@ ensure_qmi_client (GTask *task, return TRUE; } +/*****************************************************************************/ +/* Wait for SIM ready */ + +#define SIM_READY_CHECKS_MAX 5 +#define SIM_READY_CHECKS_TIMEOUT_SECS 1 + +typedef struct { + QmiClient *client_uim; + guint ready_checks_n; +} WaitSimReadyContext; + +static void +wait_sim_ready_context_free (WaitSimReadyContext *ctx) +{ + g_clear_object (&ctx->client_uim); + g_slice_free (WaitSimReadyContext, ctx); +} + +static gboolean +wait_sim_ready_finish (MMBaseSim *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void sim_ready_check (GTask *task); + +static gboolean +sim_ready_retry_cb (GTask *task) +{ + sim_ready_check (task); + return G_SOURCE_REMOVE; +} + +static void +sim_ready_retry (GTask *task) +{ + g_timeout_add_seconds (SIM_READY_CHECKS_TIMEOUT_SECS, (GSourceFunc) sim_ready_retry_cb, task); +} + +static void +uim_get_card_status_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageUimGetCardStatusOutput) output = NULL; + g_autoptr(GError) error = NULL; + MMSimQmi *self; + + self = g_task_get_source_object (task); + + output = qmi_client_uim_get_card_status_finish (client, res, &error); + if (!output || + !qmi_message_uim_get_card_status_output_get_result (output, &error) || + (!mm_qmi_uim_get_card_status_output_parse (self, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &error) && + (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) || + g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)))) { + mm_obj_dbg (self, "sim not yet considered ready... retrying"); + sim_ready_retry (task); + return; + } + + /* SIM is considered ready now */ + mm_obj_dbg (self, "sim is ready"); + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +sim_ready_check (GTask *task) +{ + WaitSimReadyContext *ctx; + MMSimQmi *self; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + ctx->ready_checks_n++; + if (ctx->ready_checks_n == SIM_READY_CHECKS_MAX) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "failed waiting for SIM readiness"); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "checking SIM readiness"); + qmi_client_uim_get_card_status (QMI_CLIENT_UIM (ctx->client_uim), + NULL, + 5, + NULL, + (GAsyncReadyCallback) uim_get_card_status_ready, + task); +} + +static void +wait_sim_ready (MMBaseSim *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + QmiClient *client; + MMSimQmi *self; + GTask *task; + WaitSimReadyContext *ctx; + + self = MM_SIM_QMI (_self); + task = g_task_new (self, NULL, callback, user_data); + + mm_obj_dbg (self, "waiting for SIM to be ready..."); + if (!self->priv->dms_uim_deprecated) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + if (!ensure_qmi_client (task, self, QMI_SERVICE_UIM, &client)) + return; + + ctx = g_slice_new0 (WaitSimReadyContext); + ctx->client_uim = g_object_ref (client); + g_task_set_task_data (task, ctx, (GDestroyNotify) wait_sim_ready_context_free); + + sim_ready_check (task); +} + /*****************************************************************************/ /* Load SIM ID (ICCID) */ @@ -218,7 +345,8 @@ uim_get_iccid_ready (QmiClientUim *client, return; } - iccid = mm_bcd_to_string ((const guint8 *) read_result->data, read_result->len); + iccid = mm_bcd_to_string ((const guint8 *) read_result->data, read_result->len, + TRUE /* low_nybble_first */); g_assert (iccid); g_task_return_pointer (task, iccid, g_free); g_object_unref (task); @@ -298,7 +426,7 @@ load_sim_identifier (MMBaseSim *_self, self = MM_SIM_QMI (_self); task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading SIM identifier..."); + mm_obj_dbg (self, "loading SIM identifier..."); if (!self->priv->dms_uim_deprecated) dms_uim_get_iccid (self, task); else @@ -332,7 +460,8 @@ uim_get_imsi_ready (QmiClientUim *client, return; } - imsi = mm_bcd_to_string ((const guint8 *) read_result->data, read_result->len); + imsi = mm_bcd_to_string ((const guint8 *) read_result->data, read_result->len, + TRUE /* low_nybble_first */); g_assert (imsi); if (strlen (imsi) < 3) g_task_return_new_error (task, @@ -423,7 +552,7 @@ load_imsi (MMBaseSim *_self, self = MM_SIM_QMI (_self); task = g_task_new (self, NULL, callback, user_data); - mm_dbg ("loading IMSI..."); + mm_obj_dbg (self, "loading IMSI..."); if (!self->priv->dms_uim_deprecated) dms_uim_get_imsi (self, task); else @@ -540,7 +669,7 @@ load_operator_identifier (MMBaseSim *self, QMI_SERVICE_NAS, &client)) return; - mm_dbg ("loading SIM operator identifier..."); + mm_obj_dbg (self, "loading SIM operator identifier..."); qmi_client_nas_get_home_network (QMI_CLIENT_NAS (client), NULL, 5, @@ -589,7 +718,7 @@ load_operator_name (MMBaseSim *self, QMI_SERVICE_NAS, &client)) return; - mm_dbg ("loading SIM operator name..."); + mm_obj_dbg (self, "loading SIM operator name..."); qmi_client_nas_get_home_network (QMI_CLIENT_NAS (client), NULL, 5, @@ -733,7 +862,7 @@ dms_uim_verify_pin (MMSimQmi *self, return; } - mm_dbg ("Sending PIN..."); + mm_obj_dbg (self, "sending PIN..."); input = qmi_message_dms_uim_verify_pin_input_new (); qmi_message_dms_uim_verify_pin_input_set_info ( input, @@ -763,7 +892,7 @@ send_pin (MMBaseSim *_self, g_task_set_task_data (task, g_strdup (pin), g_free); - mm_dbg ("Verifying PIN..."); + mm_obj_dbg (self, "verifying PIN..."); if (!self->priv->dms_uim_deprecated) dms_uim_verify_pin (self, task); else @@ -933,7 +1062,7 @@ send_puk (MMBaseSim *_self, ctx->new_pin = g_strdup (new_pin); g_task_set_task_data (task, ctx, (GDestroyNotify) unblock_pin_context_free); - mm_dbg ("Unblocking PIN..."); + mm_obj_dbg (self, "unblocking PIN..."); if (!self->priv->dms_uim_deprecated) dms_uim_unblock_pin (self, task); else @@ -1103,7 +1232,7 @@ change_pin (MMBaseSim *_self, ctx->new_pin = g_strdup (new_pin); g_task_set_task_data (task, ctx, (GDestroyNotify) change_pin_context_free); - mm_dbg ("Changing PIN..."); + mm_obj_dbg (self, "changing PIN..."); if (!self->priv->dms_uim_deprecated) dms_uim_change_pin (self, task); else @@ -1272,7 +1401,7 @@ enable_pin (MMBaseSim *_self, ctx->enabled = enabled; g_task_set_task_data (task, ctx, (GDestroyNotify) enable_pin_context_free); - mm_dbg ("%s PIN...", enabled ? "Enabling" : "Disabling"); + mm_obj_dbg (self, "%s PIN...", enabled ? "enabling" : "disabling"); if (!self->priv->dms_uim_deprecated) dms_uim_enable_pin (self, task); else @@ -1315,9 +1444,43 @@ mm_sim_qmi_new (MMBaseModem *modem, user_data, MM_BASE_SIM_MODEM, modem, MM_SIM_QMI_DMS_UIM_DEPRECATED, dms_uim_deprecated, + "active", TRUE, /* by default always active */ NULL); } +MMBaseSim * +mm_sim_qmi_new_initialized (MMBaseModem *modem, + gboolean dms_uim_deprecated, + guint slot_number, + gboolean active, + const gchar *sim_identifier, + const gchar *imsi, + const gchar *eid, + const gchar *operator_identifier, + const gchar *operator_name, + const GStrv emergency_numbers) +{ + MMBaseSim *sim; + + sim = MM_BASE_SIM (g_object_new (MM_TYPE_SIM_QMI, + MM_BASE_SIM_MODEM, modem, + MM_SIM_QMI_DMS_UIM_DEPRECATED, dms_uim_deprecated, + MM_BASE_SIM_SLOT_NUMBER, slot_number, + "active", active, + "sim-identifier", sim_identifier, + "imsi", imsi, + "eid", eid, + "operator-identifier", operator_identifier, + "operator-name", operator_name, + "emergency-numbers", emergency_numbers, + NULL)); + + mm_base_sim_export (sim); + return sim; +} + +/*****************************************************************************/ + static void mm_sim_qmi_init (MMSimQmi *self) { @@ -1374,6 +1537,8 @@ mm_sim_qmi_class_init (MMSimQmiClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; + base_sim_class->wait_sim_ready = wait_sim_ready; + base_sim_class->wait_sim_ready_finish = wait_sim_ready_finish; base_sim_class->load_sim_identifier = load_sim_identifier; base_sim_class->load_sim_identifier_finish = load_sim_identifier_finish; base_sim_class->load_imsi = load_imsi; diff --git a/src/mm-sim-qmi.h b/src/mm-sim-qmi.h index 20954444..c0fe91b9 100644 --- a/src/mm-sim-qmi.h +++ b/src/mm-sim-qmi.h @@ -44,6 +44,7 @@ struct _MMSimQmiClass { }; GType mm_sim_qmi_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSimQmi, g_object_unref) void mm_sim_qmi_new (MMBaseModem *modem, gboolean dms_uim_deprecated, @@ -53,4 +54,15 @@ void mm_sim_qmi_new (MMBaseModem *modem, MMBaseSim *mm_sim_qmi_new_finish (GAsyncResult *res, GError **error); +MMBaseSim *mm_sim_qmi_new_initialized (MMBaseModem *modem, + gboolean dms_uim_deprecated, + guint slot_number, + gboolean active, + const gchar *sim_identifier, + const gchar *imsi, + const gchar *eid, + const gchar *operator_identifier, + const gchar *operator_name, + const GStrv emergency_numbers); + #endif /* MM_SIM_QMI_H */ diff --git a/src/mm-sleep-monitor.c b/src/mm-sleep-monitor.c index c5aae5aa..d3d181c1 100644 --- a/src/mm-sleep-monitor.c +++ b/src/mm-sleep-monitor.c @@ -26,7 +26,7 @@ #include #include -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-utils.h" #include "mm-sleep-monitor.h" @@ -57,7 +57,18 @@ enum { }; static guint signals[LAST_SIGNAL] = {0}; -G_DEFINE_TYPE (MMSleepMonitor, mm_sleep_monitor, G_TYPE_OBJECT); +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMSleepMonitor, mm_sleep_monitor, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) + +/*****************************************************************************/ + +static gchar * +log_object_build_id (MMLogObject *_self) +{ + return g_strdup ("sleep-monitor"); +} /********************************************************************/ @@ -65,7 +76,7 @@ static gboolean drop_inhibitor (MMSleepMonitor *self) { if (self->inhibit_fd >= 0) { - mm_dbg ("[sleep-monitor] dropping systemd sleep inhibitor"); + mm_obj_dbg (self, "dropping systemd sleep inhibitor"); close (self->inhibit_fd); self->inhibit_fd = -1; return TRUE; @@ -86,15 +97,15 @@ inhibit_done (GObject *source, res = g_dbus_proxy_call_with_unix_fd_list_finish (sd_proxy, &fd_list, result, &error); if (!res) { - mm_warn ("[sleep-monitor] inhibit failed: %s", error->message); + mm_obj_warn (self, "inhibit failed: %s", error->message); g_error_free (error); } else { if (!fd_list || g_unix_fd_list_get_length (fd_list) != 1) - mm_warn ("[sleep-monitor] didn't get a single fd back"); + mm_obj_warn (self, "didn't get a single fd back"); self->inhibit_fd = g_unix_fd_list_get (fd_list, 0, NULL); - mm_dbg ("[sleep-monitor] inhibitor fd is %d", self->inhibit_fd); + mm_obj_dbg (self, "inhibitor fd is %d", self->inhibit_fd); g_object_unref (fd_list); g_variant_unref (res); } @@ -105,7 +116,7 @@ take_inhibitor (MMSleepMonitor *self) { g_assert (self->inhibit_fd == -1); - mm_dbg ("[sleep-monitor] taking systemd sleep inhibitor"); + mm_obj_dbg (self, "taking systemd sleep inhibitor"); g_dbus_proxy_call_with_unix_fd_list (self->sd_proxy, "Inhibit", g_variant_new ("(ssss)", @@ -135,12 +146,13 @@ signal_cb (GDBusProxy *proxy, return; g_variant_get (args, "(b)", &is_about_to_suspend); - mm_dbg ("[sleep-monitor] received PrepareForSleep signal: %d", is_about_to_suspend); if (is_about_to_suspend) { + mm_obj_info (self, "system is about to suspend"); g_signal_emit (self, signals[SLEEPING], 0); drop_inhibitor (self); } else { + mm_obj_info (self, "system is resuming"); take_inhibitor (self); g_signal_emit (self, signals[RESUMING], 0); } @@ -175,7 +187,7 @@ on_proxy_acquired (GObject *object, self->sd_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (!self->sd_proxy) { - mm_warn ("[sleep-monitor] failed to acquire logind proxy: %s", error->message); + mm_obj_warn (self, "failed to acquire logind proxy: %s", error->message); g_clear_error (&error); return; } @@ -215,6 +227,12 @@ finalize (GObject *object) G_OBJECT_CLASS (mm_sleep_monitor_parent_class)->finalize (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_sleep_monitor_class_init (MMSleepMonitorClass *klass) { diff --git a/src/mm-sms-list.c b/src/mm-sms-list.c index ec3adca5..1a832216 100644 --- a/src/mm-sms-list.c +++ b/src/mm-sms-list.c @@ -27,9 +27,12 @@ #include "mm-iface-modem-messaging.h" #include "mm-sms-list.h" #include "mm-base-sms.h" -#include "mm-log.h" +#include "mm-log-object.h" -G_DEFINE_TYPE (MMSmsList, mm_sms_list, G_TYPE_OBJECT); +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMSmsList, mm_sms_list, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) enum { PROP_0, @@ -280,8 +283,7 @@ take_multipart (MMSmsList *self, (GCompareFunc)cmp_sms_by_concat_reference); if (l) { /* Try to take the part */ - mm_dbg ("Found existing multipart SMS object with reference '%u': adding new part", - concat_reference); + mm_obj_dbg (self, "found existing multipart SMS object with reference '%u': adding new part", concat_reference); return mm_base_sms_multipart_take_part (MM_BASE_SMS (l->data), part, error); } @@ -296,9 +298,9 @@ take_multipart (MMSmsList *self, if (!sms) return FALSE; - mm_dbg ("Creating new multipart SMS object: need to receive %u parts with reference '%u'", - mm_sms_part_get_concat_max (part), - concat_reference); + mm_obj_dbg (self, "creating new multipart SMS object: need to receive %u parts with reference '%u'", + mm_sms_part_get_concat_max (part), + concat_reference); self->priv->list = g_list_prepend (self->priv->list, sms); g_signal_emit (self, signals[SIGNAL_ADDED], 0, mm_base_sms_get_path (sms), @@ -349,33 +351,41 @@ mm_sms_list_take_part (MMSmsList *self, /* Did we just get a part of a multi-part SMS? */ if (mm_sms_part_should_concat (part)) { if (mm_sms_part_get_index (part) != SMS_PART_INVALID_INDEX) - mm_dbg ("SMS part at '%s/%u' is from a multipart SMS (reference: '%u', sequence: '%u/%u')", - mm_sms_storage_get_string (storage), - mm_sms_part_get_index (part), - mm_sms_part_get_concat_reference (part), - mm_sms_part_get_concat_sequence (part), - mm_sms_part_get_concat_max (part)); + mm_obj_dbg (self, "SMS part at '%s/%u' is from a multipart SMS (reference: '%u', sequence: '%u/%u')", + mm_sms_storage_get_string (storage), + mm_sms_part_get_index (part), + mm_sms_part_get_concat_reference (part), + mm_sms_part_get_concat_sequence (part), + mm_sms_part_get_concat_max (part)); else - mm_dbg ("SMS part (not stored) is from a multipart SMS (reference: '%u', sequence: '%u/%u')", - mm_sms_part_get_concat_reference (part), - mm_sms_part_get_concat_sequence (part), - mm_sms_part_get_concat_max (part)); + mm_obj_dbg (self, "SMS part (not stored) is from a multipart SMS (reference: '%u', sequence: '%u/%u')", + mm_sms_part_get_concat_reference (part), + mm_sms_part_get_concat_sequence (part), + mm_sms_part_get_concat_max (part)); return take_multipart (self, part, state, storage, error); } /* Otherwise, we build a whole new single-part MMSms just from this part */ if (mm_sms_part_get_index (part) != SMS_PART_INVALID_INDEX) - mm_dbg ("SMS part at '%s/%u' is from a singlepart SMS", - mm_sms_storage_get_string (storage), - mm_sms_part_get_index (part)); + mm_obj_dbg (self, "SMS part at '%s/%u' is from a singlepart SMS", + mm_sms_storage_get_string (storage), + mm_sms_part_get_index (part)); else - mm_dbg ("SMS part (not stored) is from a singlepart SMS"); + mm_obj_dbg (self, "SMS part (not stored) is from a singlepart SMS"); return take_singlepart (self, part, state, storage, error); } /*****************************************************************************/ +static gchar * +log_object_build_id (MMLogObject *_self) +{ + return g_strdup ("sms-list"); +} + +/*****************************************************************************/ + MMSmsList * mm_sms_list_new (MMBaseModem *modem) { @@ -397,6 +407,10 @@ set_property (GObject *object, case PROP_MODEM: g_clear_object (&self->priv->modem); self->priv->modem = g_value_dup_object (value); + if (self->priv->modem) { + /* Set owner ID */ + mm_log_object_set_owner_id (MM_LOG_OBJECT (self), mm_log_object_get_id (MM_LOG_OBJECT (self->priv->modem))); + } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -443,6 +457,12 @@ dispose (GObject *object) G_OBJECT_CLASS (mm_sms_list_parent_class)->dispose (object); } +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + static void mm_sms_list_class_init (MMSmsListClass *klass) { diff --git a/src/mm-sms-list.h b/src/mm-sms-list.h index 29370657..8a77d6ca 100644 --- a/src/mm-sms-list.h +++ b/src/mm-sms-list.h @@ -55,6 +55,7 @@ struct _MMSmsListClass { }; GType mm_sms_list_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsList, g_object_unref) MMSmsList *mm_sms_list_new (MMBaseModem *modem); diff --git a/src/mm-sms-mbim.c b/src/mm-sms-mbim.c index e20a83d2..792d37c4 100644 --- a/src/mm-sms-mbim.c +++ b/src/mm-sms-mbim.c @@ -24,11 +24,12 @@ #define _LIBMM_INSIDE_MM #include +#include "mm-broadband-modem-mbim.h" #include "mm-modem-helpers-mbim.h" #include "mm-iface-modem-messaging.h" #include "mm-sms-mbim.h" #include "mm-base-modem.h" -#include "mm-log.h" +#include "mm-log-object.h" #include "mm-sms-part-3gpp.h" G_DEFINE_TYPE (MMSmsMbim, mm_sms_mbim, MM_TYPE_BASE_SMS) @@ -51,7 +52,7 @@ peek_device (gpointer self, if (o_device) { MMPortMbim *port; - port = mm_base_modem_peek_port_mbim (modem); + port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (modem)); if (!port) { g_task_report_new_error (self, callback, @@ -138,6 +139,7 @@ sms_send_set_ready (MbimDevice *device, static void sms_send_next_part (GTask *task) { + MMSmsMbim *self; SmsSendContext *ctx; MbimMessage *message; guint8 *pdu; @@ -146,7 +148,9 @@ sms_send_next_part (GTask *task) GError *error = NULL; MbimSmsPduSendRecord send_record; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); + if (!ctx->current) { /* Done we are */ g_task_return_boolean (task, TRUE); @@ -155,7 +159,7 @@ sms_send_next_part (GTask *task) } /* Get PDU */ - pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error); + pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, self, &error); if (!pdu) { g_task_return_error (task, error); g_object_unref (task); @@ -237,11 +241,14 @@ sms_delete_set_ready (MbimDevice *device, GAsyncResult *res, GTask *task) { + MMSmsMbim *self; SmsDeletePartsContext *ctx; MbimMessage *response; GError *error = NULL; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); + response = mbim_device_command_finish (device, res, &error); if (response && mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) @@ -252,9 +259,9 @@ sms_delete_set_ready (MbimDevice *device, if (error) { ctx->n_failed++; - mm_dbg ("Couldn't delete SMS part with index %u: '%s'", - mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), - error->message); + mm_obj_dbg (self, "couldn't delete SMS part with index %u: %s", + mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), + error->message); g_error_free (error); } diff --git a/src/mm-sms-mbim.h b/src/mm-sms-mbim.h index f2f6f3ac..5743f262 100644 --- a/src/mm-sms-mbim.h +++ b/src/mm-sms-mbim.h @@ -43,6 +43,7 @@ struct _MMSmsMbimClass { }; GType mm_sms_mbim_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsMbim, g_object_unref) MMBaseSms *mm_sms_mbim_new (MMBaseModem *modem); diff --git a/src/mm-sms-part-3gpp.c b/src/mm-sms-part-3gpp.c index 3a59cdca..51f2cfeb 100644 --- a/src/mm-sms-part-3gpp.c +++ b/src/mm-sms-part-3gpp.c @@ -120,23 +120,26 @@ sms_string_to_bcd_semi_octets (guint8 *buf, gsize buflen, const char *string) } /* len is in semi-octets */ -static char * -sms_decode_address (const guint8 *address, int len) +static gchar * +sms_decode_address (const guint8 *address, + gint len, + GError **error) { guint8 addrtype, addrplan; - char *utf8; + gchar *utf8; addrtype = address[0] & SMS_NUMBER_TYPE_MASK; addrplan = address[0] & SMS_NUMBER_PLAN_MASK; address++; if (addrtype == SMS_NUMBER_TYPE_ALPHA) { - guint8 *unpacked; - guint32 unpacked_len; + g_autoptr(GByteArray) unpacked_array = NULL; + guint8 *unpacked = NULL; + guint32 unpacked_len; + unpacked = mm_charset_gsm_unpack (address, (len * 4) / 7, 0, &unpacked_len); - utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 (unpacked, - unpacked_len); - g_free (unpacked); + unpacked_array = g_byte_array_new_take (unpacked, unpacked_len); + utf8 = mm_modem_charset_bytearray_to_utf8 (unpacked_array, MM_MODEM_CHARSET_GSM, FALSE, error); } else if (addrtype == SMS_NUMBER_TYPE_INTL && addrplan == SMS_NUMBER_PLAN_TELEPHONE) { /* International telphone number, format as "+1234567890" */ @@ -239,50 +242,44 @@ sms_encoding_type (int dcs) return scheme; } -static char * -sms_decode_text (const guint8 *text, int len, MMSmsEncoding encoding, int bit_offset) +static gchar * +sms_decode_text (const guint8 *text, + int len, + MMSmsEncoding encoding, + int bit_offset, + gpointer log_object, + GError **error) { - char *utf8; - guint8 *unpacked; - guint32 unpacked_len; - if (encoding == MM_SMS_ENCODING_GSM7) { - mm_dbg ("Converting SMS part text from GSM-7 to UTF-8..."); + g_autoptr(GByteArray) unpacked_array = NULL; + guint8 *unpacked = NULL; + guint32 unpacked_len; + gchar *utf8; + unpacked = mm_charset_gsm_unpack ((const guint8 *) text, len, bit_offset, &unpacked_len); - utf8 = (char *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len); - mm_dbg (" Got UTF-8 text: '%s'", utf8); - g_free (unpacked); - } else if (encoding == MM_SMS_ENCODING_UCS2) { - /* Despite 3GPP TS 23.038 specifies that Unicode SMS messages are - * encoded in UCS-2, UTF-16 encoding is commonly used instead on many - * modern platforms to allow encoding code points that fall outside the - * Basic Multilingual Plane (BMP), such as Emoji. Most of the UCS-2 - * code points are identical to their equivalent UTF-16 code points. - * In UTF-16, non-BMP code points are encoded in a pair of surrogate - * code points (i.e. a high surrogate in 0xD800..0xDBFF, followed by a - * low surrogate in 0xDC00..0xDFFF). An isolated surrogate code point - * has no general interpretation in UTF-16, but could be a valid - * (though unmapped) code point in UCS-2. Here we first try to decode - * the SMS message in UTF-16BE, and if that fails, fall back to decode - * in UCS-2BE. - */ - mm_dbg ("Converting SMS part text from UTF-16BE to UTF-8..."); - utf8 = g_convert ((const gchar *) text, len, "UTF8", "UTF16BE", NULL, NULL, NULL); - if (!utf8) { - mm_dbg ("Converting SMS part text from UCS-2BE to UTF8..."); - utf8 = g_convert ((const gchar *) text, len, "UTF8", "UCS-2BE", NULL, NULL, NULL); - } - if (!utf8) { - mm_warn ("Couldn't convert SMS part contents from UTF-16BE/UCS-2BE to UTF-8: not decoding any text"); - utf8 = g_strdup (""); - } else - mm_dbg (" Got UTF-8 text: '%s'", utf8); - } else { - mm_warn ("Unexpected encoding '%s': not decoding any text", mm_sms_encoding_get_string (encoding)); - utf8 = g_strdup (""); + unpacked_array = g_byte_array_new_take (unpacked, unpacked_len); + utf8 = mm_modem_charset_bytearray_to_utf8 (unpacked_array, MM_MODEM_CHARSET_GSM, FALSE, error); + if (utf8) + mm_obj_dbg (log_object, "converted SMS part text from GSM-7 to UTF-8: %s", utf8); + return utf8; } - return utf8; + /* Always assume UTF-16 instead of UCS-2! */ + if (encoding == MM_SMS_ENCODING_UCS2) { + g_autoptr(GByteArray) bytearray = NULL; + gchar *utf8; + + bytearray = g_byte_array_append (g_byte_array_sized_new (len), (const guint8 *)text, len); + utf8 = mm_modem_charset_bytearray_to_utf8 (bytearray, MM_MODEM_CHARSET_UTF16, FALSE, error); + if (utf8) + mm_obj_dbg (log_object, "converted SMS part text from UTF-16BE to UTF-8: %s", utf8); + return utf8; + } + + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't convert SMS part contents from %s to UTF-8", + mm_sms_encoding_get_string (encoding)); + return NULL; } static guint @@ -343,35 +340,31 @@ validity_to_relative (guint validity) } MMSmsPart * -mm_sms_part_3gpp_new_from_pdu (guint index, - const gchar *hexpdu, - GError **error) +mm_sms_part_3gpp_new_from_pdu (guint index, + const gchar *hexpdu, + gpointer log_object, + GError **error) { - gsize pdu_len; - guint8 *pdu; - MMSmsPart *part; + g_autofree guint8 *pdu = NULL; + gsize pdu_len; /* Convert PDU from hex to binary */ - pdu = (guint8 *) mm_utils_hexstr2bin (hexpdu, &pdu_len); + pdu = mm_utils_hexstr2bin (hexpdu, -1, &pdu_len, error); if (!pdu) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't convert 3GPP PDU from hex to binary"); + g_prefix_error (error, "Couldn't convert 3GPP PDU from hex to binary: "); return NULL; } - part = mm_sms_part_3gpp_new_from_binary_pdu (index, pdu, pdu_len, error); - g_free (pdu); - - return part; + return mm_sms_part_3gpp_new_from_binary_pdu (index, pdu, pdu_len, log_object, FALSE, error); } MMSmsPart * -mm_sms_part_3gpp_new_from_binary_pdu (guint index, - const guint8 *pdu, - gsize pdu_len, - GError **error) +mm_sms_part_3gpp_new_from_binary_pdu (guint index, + const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + gboolean transfer_route, + GError **error) { MMSmsPart *sms_part; guint8 pdu_type; @@ -387,14 +380,15 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, guint tp_dcs_offset = 0; guint tp_user_data_len_offset = 0; MMSmsEncoding user_data_encoding = MM_SMS_ENCODING_UNKNOWN; + gchar *address; /* Create the new MMSmsPart */ sms_part = mm_sms_part_new (index, MM_SMS_PDU_TYPE_UNKNOWN); if (index != SMS_PART_INVALID_INDEX) - mm_dbg ("Parsing PDU (%u)...", index); + mm_obj_dbg (log_object, "parsing PDU (%u)...", index); else - mm_dbg ("Parsing PDU..."); + mm_obj_dbg (log_object, "parsing PDU..."); #define PDU_SIZE_CHECK(required_size, check_descr_str) \ if (pdu_len < required_size) { \ @@ -411,20 +405,28 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, offset = 0; - /* ---------------------------------------------------------------------- */ - /* SMSC, in address format, precedes the TPDU - * First byte represents the number of BYTES for the address value */ - PDU_SIZE_CHECK (1, "cannot read SMSC address length"); - smsc_addr_size_bytes = pdu[offset++]; - if (smsc_addr_size_bytes > 0) { - PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address"); - /* SMSC may not be given in DELIVER PDUs */ - mm_sms_part_take_smsc (sms_part, - sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1))); - mm_dbg (" SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part)); - offset += smsc_addr_size_bytes; + if (!transfer_route) { + /* ---------------------------------------------------------------------- */ + /* SMSC, in address format, precedes the TPDU + * First byte represents the number of BYTES for the address value */ + PDU_SIZE_CHECK (1, "cannot read SMSC address length"); + smsc_addr_size_bytes = pdu[offset++]; + if (smsc_addr_size_bytes > 0) { + PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address"); + /* SMSC may not be given in DELIVER PDUs */ + address = sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1), error); + if (!address) { + g_prefix_error (error, "Couldn't read SMSC address: "); + mm_sms_part_free (sms_part); + return NULL; + } + mm_sms_part_take_smsc (sms_part, g_steal_pointer (&address)); + mm_obj_dbg (log_object, " SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part)); + offset += smsc_addr_size_bytes; + } else + mm_obj_dbg (log_object, " no SMSC address given"); } else - mm_dbg (" No SMSC address given"); + mm_obj_dbg (log_object, " This is a transfer-route message"); /* ---------------------------------------------------------------------- */ @@ -434,15 +436,15 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, pdu_type = (pdu[offset] & SMS_TP_MTI_MASK); switch (pdu_type) { case SMS_TP_MTI_SMS_DELIVER: - mm_dbg (" Deliver type PDU detected"); + mm_obj_dbg (log_object, " deliver type PDU detected"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_DELIVER); break; case SMS_TP_MTI_SMS_SUBMIT: - mm_dbg (" Submit type PDU detected"); + mm_obj_dbg (log_object, " submit type PDU detected"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_SUBMIT); break; case SMS_TP_MTI_SMS_STATUS_REPORT: - mm_dbg (" Status report type PDU detected"); + mm_obj_dbg (log_object, " status report type PDU detected"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_STATUS_REPORT); break; default: @@ -475,7 +477,7 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, pdu_type == SMS_TP_MTI_SMS_SUBMIT) { PDU_SIZE_CHECK (offset + 1, "cannot read message reference"); - mm_dbg (" message reference: %u", (guint)pdu[offset]); + mm_obj_dbg (log_object, " message reference: %u", (guint)pdu[offset]); mm_sms_part_set_message_reference (sms_part, pdu[offset]); offset++; } @@ -492,10 +494,14 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, tp_addr_size_bytes = (tp_addr_size_digits + 1) >> 1; PDU_SIZE_CHECK (offset + tp_addr_size_bytes, "cannot read number"); - mm_sms_part_take_number (sms_part, - sms_decode_address (&pdu[offset], - tp_addr_size_digits)); - mm_dbg (" Number parsed: '%s'", mm_sms_part_get_number (sms_part)); + address = sms_decode_address (&pdu[offset], tp_addr_size_digits, error); + if (!address) { + g_prefix_error (error, "Couldn't read address: "); + mm_sms_part_free (sms_part); + return NULL; + } + mm_sms_part_take_number (sms_part, g_steal_pointer (&address)); + mm_obj_dbg (log_object, " number parsed: %s", mm_sms_part_get_number (sms_part)); offset += (1 + tp_addr_size_bytes); /* +1 due to the Type of Address byte */ /* ---------------------------------------------------------------------- */ @@ -531,20 +537,20 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, if (validity_format) { switch (validity_format) { case 0x10: - mm_dbg (" validity available, format relative"); + mm_obj_dbg (log_object, " validity available, format relative"); mm_sms_part_set_validity_relative (sms_part, relative_to_validity (pdu[offset])); offset++; break; case 0x08: /* TODO: support enhanced format; GSM 03.40 */ - mm_dbg (" validity available, format enhanced (not implemented)"); + mm_obj_dbg (log_object, " validity available, format enhanced (not implemented)"); /* 7 bytes for enhanced validity */ offset += 7; break; case 0x18: /* TODO: support absolute format; GSM 03.40 */ - mm_dbg (" validity available, format absolute (not implemented)"); + mm_obj_dbg (log_object, " validity available, format absolute (not implemented)"); /* 7 bytes for absolute validity */ offset += 7; break; @@ -574,7 +580,7 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, offset += 7; /* ----- TP-STATUS (1 byte) ------ */ - mm_dbg (" delivery state: %u", (guint)pdu[offset]); + mm_obj_dbg (log_object, " delivery state: %u", (guint)pdu[offset]); mm_sms_part_set_delivery_state (sms_part, pdu[offset]); offset++; @@ -599,7 +605,7 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, if (tp_pid_offset > 0) { PDU_SIZE_CHECK (tp_pid_offset + 1, "cannot read TP-PID"); - mm_dbg (" PID: %u", (guint)pdu[tp_pid_offset]); + mm_obj_dbg (log_object, " PID: %u", (guint)pdu[tp_pid_offset]); } /* Grab user data encoding and message class */ @@ -610,18 +616,20 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, user_data_encoding = sms_encoding_type (pdu[tp_dcs_offset]); switch (user_data_encoding) { case MM_SMS_ENCODING_GSM7: - mm_dbg (" user data encoding is GSM7"); + mm_obj_dbg (log_object, " user data encoding is GSM7"); break; case MM_SMS_ENCODING_UCS2: - mm_dbg (" user data encoding is UCS2"); + mm_obj_dbg (log_object, " user data encoding is UCS2"); break; case MM_SMS_ENCODING_8BIT: - mm_dbg (" user data encoding is 8bit"); + mm_obj_dbg (log_object, " user data encoding is 8bit"); break; case MM_SMS_ENCODING_UNKNOWN: - default: - mm_dbg (" user data encoding is unknown"); + mm_obj_dbg (log_object, " user data encoding is unknown"); break; + default: + g_assert_not_reached (); + } mm_sms_part_set_encoding (sms_part, user_data_encoding); @@ -639,13 +647,13 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, PDU_SIZE_CHECK (tp_user_data_len_offset + 1, "cannot read TP-UDL"); tp_user_data_size_elements = pdu[tp_user_data_len_offset]; - mm_dbg (" user data length: %u elements", tp_user_data_size_elements); + mm_obj_dbg (log_object, " user data length: %u elements", tp_user_data_size_elements); if (user_data_encoding == MM_SMS_ENCODING_GSM7) tp_user_data_size_bytes = (7 * (tp_user_data_size_elements + 1 )) / 8; else tp_user_data_size_bytes = tp_user_data_size_elements; - mm_dbg (" user data length: %u bytes", tp_user_data_size_bytes); + mm_obj_dbg (log_object, " user data length: %u bytes", tp_user_data_size_bytes); tp_user_data_offset = tp_user_data_len_offset + 1; PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read TP-UD"); @@ -721,23 +729,31 @@ mm_sms_part_3gpp_new_from_binary_pdu (guint index, switch (user_data_encoding) { case MM_SMS_ENCODING_GSM7: case MM_SMS_ENCODING_UCS2: - /* Otherwise if it's 7-bit or UCS2 we can decode it */ - mm_dbg ("Decoding SMS text with '%u' elements", tp_user_data_size_elements); - mm_sms_part_take_text (sms_part, - sms_decode_text (&pdu[tp_user_data_offset], - tp_user_data_size_elements, - user_data_encoding, - bit_offset)); - g_warn_if_fail (mm_sms_part_get_text (sms_part) != NULL); - break; - + { + gchar *text; + + /* Otherwise if it's 7-bit or UCS2 we can decode it */ + mm_obj_dbg (log_object, "decoding SMS text with %u elements", tp_user_data_size_elements); + text = sms_decode_text (&pdu[tp_user_data_offset], + tp_user_data_size_elements, + user_data_encoding, + bit_offset, + log_object, + error); + if (!text) { + mm_sms_part_free (sms_part); + return NULL; + } + mm_sms_part_take_text (sms_part, text); + break; + } case MM_SMS_ENCODING_8BIT: case MM_SMS_ENCODING_UNKNOWN: default: { GByteArray *raw; - mm_dbg ("Skipping SMS text: Unknown encoding (0x%02X)", user_data_encoding); + mm_obj_dbg (log_object, "skipping SMS text: unknown encoding (0x%02X)", user_data_encoding); PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read user data"); @@ -815,12 +831,14 @@ guint8 * mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, guint *out_pdulen, guint *out_msgstart, + gpointer log_object, GError **error) { guint8 *pdu; guint len, offset = 0; guint shift = 0; guint8 *udl_ptr; + MMSmsEncoding encoding; g_return_val_if_fail (mm_sms_part_get_number (part) != NULL, NULL); g_return_val_if_fail (mm_sms_part_get_text (part) != NULL || mm_sms_part_get_data (part) != NULL, NULL); @@ -834,13 +852,13 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, return NULL; } - mm_dbg ("Creating PDU for part..."); + mm_obj_dbg (log_object, "creating PDU for part..."); /* Build up the PDU */ pdu = g_malloc0 (PDU_SIZE); if (mm_sms_part_get_smsc (part)) { - mm_dbg (" adding SMSC to PDU..."); + mm_obj_dbg (log_object, " adding SMSC to PDU..."); len = mm_sms_part_3gpp_encode_address (mm_sms_part_get_smsc (part), pdu, PDU_SIZE, TRUE); if (len == 0) { g_set_error (error, @@ -863,13 +881,13 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, /* TP-VP present; format RELATIVE */ if (mm_sms_part_get_validity_relative (part) > 0) { - mm_dbg (" adding validity to PDU..."); + mm_obj_dbg (log_object, " adding validity to PDU..."); pdu[offset] |= 0x10; } /* Concatenation sequence only found in multipart SMS */ if (mm_sms_part_get_concat_sequence (part)) { - mm_dbg (" adding UDHI to PDU..."); + mm_obj_dbg (log_object, " adding UDHI to PDU..."); pdu[offset] |= 0x40; /* UDHI */ } @@ -878,7 +896,7 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, if (mm_sms_part_get_delivery_report_request (part) && (!mm_sms_part_get_concat_sequence (part) || mm_sms_part_get_concat_max (part) == mm_sms_part_get_concat_sequence (part))) { - mm_dbg (" requesting delivery report..."); + mm_obj_dbg (log_object, " requesting delivery report..."); pdu[offset] |= 0x20; } @@ -910,24 +928,26 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, pdu[offset] = 0x00; if (mm_sms_part_get_class (part) >= 0 && mm_sms_part_get_class (part) <= 3) { - mm_dbg (" using class %d...", mm_sms_part_get_class (part)); + mm_obj_dbg (log_object, " using class %d...", mm_sms_part_get_class (part)); pdu[offset] |= SMS_DCS_CLASS_VALID; pdu[offset] |= mm_sms_part_get_class (part); } - switch (mm_sms_part_get_encoding (part)) { + encoding = mm_sms_part_get_encoding (part); + + switch (encoding) { case MM_SMS_ENCODING_UCS2: - mm_dbg (" using UCS2 encoding..."); + mm_obj_dbg (log_object, " using UCS2 encoding..."); pdu[offset] |= SMS_DCS_CODING_UCS2; break; case MM_SMS_ENCODING_GSM7: - mm_dbg (" using GSM7 encoding..."); + mm_obj_dbg (log_object, " using GSM7 encoding..."); pdu[offset] |= SMS_DCS_CODING_DEFAULT; /* GSM */ break; case MM_SMS_ENCODING_8BIT: case MM_SMS_ENCODING_UNKNOWN: default: - mm_dbg (" using 8bit encoding..."); + mm_obj_dbg (log_object, " using 8bit encoding..."); pdu[offset] |= SMS_DCS_CODING_8BIT; break; } @@ -946,7 +966,7 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, /* Build UDH */ if (mm_sms_part_get_concat_sequence (part)) { - mm_dbg (" adding UDH header in PDU... (reference: %u, max: %u, sequence: %u)", + mm_obj_dbg (log_object, " adding UDH header in PDU... (reference: %u, max: %u, sequence: %u)", mm_sms_part_get_concat_reference (part), mm_sms_part_get_concat_max (part), mm_sms_part_get_concat_sequence (part)); @@ -968,13 +988,16 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, shift = 1; } - if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_GSM7) { - guint8 *unpacked, *packed; - guint32 unlen = 0, packlen = 0; + if (encoding == MM_SMS_ENCODING_GSM7) { + g_autoptr(GByteArray) unpacked = NULL; + g_autofree guint8 *packed = NULL; + guint32 packlen = 0; + + unpacked = mm_modem_charset_bytearray_from_utf8 (mm_sms_part_get_text (part), MM_MODEM_CHARSET_GSM, FALSE, error); + if (!unpacked) + goto error; - unpacked = mm_charset_utf8_to_unpacked_gsm (mm_sms_part_get_text (part), &unlen); - if (!unpacked || unlen == 0) { - g_free (unpacked); + if (unpacked->len == 0) { g_set_error_literal (error, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER, @@ -985,15 +1008,13 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, /* Set real data length, in septets * If we had UDH, add 7 septets */ - *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (7 + unlen) : unlen; - mm_dbg (" user data length is '%u' septets (%s UDH)", - *udl_ptr, - mm_sms_part_get_concat_sequence (part) ? "with" : "without"); + *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (7 + unpacked->len) : unpacked->len; + mm_obj_dbg (log_object, " user data length is %u septets (%s UDH)", + *udl_ptr, + mm_sms_part_get_concat_sequence (part) ? "with" : "without"); - packed = mm_charset_gsm_pack (unpacked, unlen, shift, &packlen); - g_free (unpacked); + packed = mm_charset_gsm_pack (unpacked->data, unpacked->len, shift, &packlen); if (!packed || packlen == 0) { - g_free (packed); g_set_error_literal (error, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER, @@ -1002,19 +1023,19 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, } memcpy (&pdu[offset], packed, packlen); - g_free (packed); offset += packlen; - } else if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_UCS2) { - GByteArray *array; + } else if (encoding == MM_SMS_ENCODING_UCS2) { + g_autoptr(GByteArray) array = NULL; + g_autoptr(GError) inner_error = NULL; - /* Try to guess a good value for the array */ - array = g_byte_array_sized_new (strlen (mm_sms_part_get_text (part)) * 2); - if (!mm_modem_charset_byte_array_append (array, mm_sms_part_get_text (part), FALSE, MM_MODEM_CHARSET_UCS2)) { - g_byte_array_free (array, TRUE); - g_set_error_literal (error, - MM_MESSAGE_ERROR, - MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER, - "Failed to convert message text to UCS2"); + /* Always assume UTF-16 instead of UCS-2! */ + array = mm_modem_charset_bytearray_from_utf8 (mm_sms_part_get_text (part), MM_MODEM_CHARSET_UTF16, FALSE, &inner_error); + if (!array) { + g_set_error (error, + MM_MESSAGE_ERROR, + MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER, + "Failed to convert message text to UTF-16: %s", + inner_error->message); goto error; } @@ -1022,13 +1043,12 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, * If we had UDH, add 6 octets */ *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (6 + array->len) : array->len; - mm_dbg (" user data length is '%u' octets (%s UDH)", - *udl_ptr, - mm_sms_part_get_concat_sequence (part) ? "with" : "without"); + mm_obj_dbg (log_object, " user data length is %u octets (%s UDH)", + *udl_ptr, + mm_sms_part_get_concat_sequence (part) ? "with" : "without"); memcpy (&pdu[offset], array->data, array->len); offset += array->len; - g_byte_array_free (array, TRUE); } else if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_8BIT) { const GByteArray *data; @@ -1038,7 +1058,7 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, * If we had UDH, add 6 octets */ *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (6 + data->len) : data->len; - mm_dbg (" binary user data length is '%u' octets (%s UDH)", + mm_obj_dbg (log_object, " binary user data length is %u octets (%s UDH)", *udl_ptr, mm_sms_part_get_concat_sequence (part) ? "with" : "without"); @@ -1056,21 +1076,109 @@ mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, return NULL; } -gchar ** -mm_sms_part_3gpp_util_split_text (const gchar *text, - MMSmsEncoding *encoding) +static gchar ** +util_split_text_gsm7 (const gchar *text, + gsize text_len, + gpointer log_object) { gchar **out; - guint n_chunks; - guint i; - guint j; - gsize in_len; + guint n_chunks; + guint i; + guint j; + + /* No splitting needed? */ + if (text_len <= 160) { + out = g_new0 (gchar *, 2); + out[0] = g_strdup (text); + return out; + } + + /* Compute number of chunks needed */ + n_chunks = text_len / 153; + if (text_len % 153 != 0) + n_chunks++; + + /* Fill in all chunks */ + out = g_new0 (gchar *, n_chunks + 1); + for (i = 0, j = 0; i < n_chunks; i++, j += 153) + out[i] = g_strndup (&text[j], 153); + + return out; +} + +static gchar ** +util_split_text_utf16_or_ucs2 (const gchar *text, + gsize text_len, + gpointer log_object) +{ + g_autoptr(GPtrArray) chunks = NULL; + const gchar *walker; + const gchar *chunk_start; + glong encoded_chunk_length; + glong total_encoded_chunk_length; + + chunks = g_ptr_array_new_with_free_func ((GDestroyNotify)g_free); + + walker = text; + chunk_start = text; + encoded_chunk_length = 0; + total_encoded_chunk_length = 0; + while (walker && *walker) { + g_autofree gunichar2 *unichar2 = NULL; + glong unichar2_written = 0; + glong unichar2_written_bytes = 0; + gunichar single; + + single = g_utf8_get_char (walker); + unichar2 = g_ucs4_to_utf16 (&single, 1, NULL, &unichar2_written, NULL); + g_assert (unichar2_written > 0); + + /* When splitting for UCS-2 encoding, only one single unichar2 will be + * written, because all codepoints represented in UCS2 fit in the BMP. + * When splitting for UTF-16, though, we may end up writing one or two + * unichar2 (without or with surrogate pairs), because UTF-16 covers the + * whole Unicode spectrum. */ + unichar2_written_bytes = (unichar2_written * sizeof (gunichar2)); + if ((encoded_chunk_length + unichar2_written_bytes) > 134) { + g_ptr_array_add (chunks, g_strndup (chunk_start, walker - chunk_start)); + chunk_start = walker; + encoded_chunk_length = unichar2_written_bytes; + } else + encoded_chunk_length += unichar2_written_bytes; + + total_encoded_chunk_length += unichar2_written_bytes; + walker = g_utf8_next_char (walker); + } + /* We have split the original string in chunks, where each chunk + * does not require more than 134 bytes when encoded in UTF-16. + * As a special case now, we consider the case that no splitting + * is necessary, i.e. if the total amount of bytes after encoding + * in UTF-16 is less or equal than 140. */ + if (total_encoded_chunk_length <= 140) { + gchar **out; + + out = g_new0 (gchar *, 2); + out[0] = g_strdup (text); + return out; + } + + /* Otherwise, we do need the splitted chunks. Add the last one + * with contents plus the last trailing NULL */ + g_ptr_array_add (chunks, g_strndup (chunk_start, walker - chunk_start)); + g_ptr_array_add (chunks, NULL); + + return (gchar **) g_ptr_array_free (g_steal_pointer (&chunks), FALSE); +} + +gchar ** +mm_sms_part_3gpp_util_split_text (const gchar *text, + MMSmsEncoding *encoding, + gpointer log_object) +{ if (!text) return NULL; - in_len = strlen (text); - /* Some info about the rules for splitting. * * The User Data can be up to 140 bytes in the SMS part: @@ -1085,78 +1193,25 @@ mm_sms_part_3gpp_util_split_text (const gchar *text, * 134 * 8 = 1072; 1072/7=153.14 * 2) If we're using UCS2 encoding, we can pack up to 70 characters in * 140 bytes (each with 2 bytes), or up to 67 characters in 134 bytes. + * 3) If we're using UTF-16 encoding (instead of UCS2), the amount of + * characters we can pack is variable, depends on how the characters + * are encoded in UTF-16 (e.g. if there are characters out of the BMP + * we'll need surrogate pairs and a single character will need 4 bytes + * instead of 2). * * This method does the split of the input string into N strings, so that * each of the strings can be placed in a SMS part. */ /* Check if we can do GSM encoding */ - if (!mm_charset_can_convert_to (text, MM_MODEM_CHARSET_GSM)) { - /* If cannot do it in GSM encoding, do it in UCS-2 */ - GByteArray *array; - - *encoding = MM_SMS_ENCODING_UCS2; - - /* Guess more or less the size of the output array to avoid multiple - * allocations */ - array = g_byte_array_sized_new (in_len * 2); - if (!mm_modem_charset_byte_array_append (array, - text, - FALSE, - MM_MODEM_CHARSET_UCS2)) { - g_byte_array_unref (array); - return NULL; - } - - /* Our bytearray has it in UCS-2 now. - * UCS-2 is a fixed-size encoding, which means that the text has exactly - * 2 bytes for each unicode point. We can now split this array into - * chunks of 67 UCS-2 characters (134 bytes). - * - * Note that UCS-2 covers unicode points between U+0000 and U+FFFF, which - * means that there is no direct relationship between the size of the - * input text in UTF-8 and the size of the text in UCS-2. A 3-byte UTF-8 - * encoded character will still be represented with 2 bytes in UCS-2. - */ - if (array->len <= 140) { - out = g_new (gchar *, 2); - out[0] = g_strdup (text); - out[1] = NULL; - } else { - n_chunks = array->len / 134; - if (array->len % 134 != 0) - n_chunks++; - - out = g_new0 (gchar *, n_chunks + 1); - for (i = 0, j = 0; i < n_chunks; i++, j += 134) { - out[i] = sms_decode_text (&array->data[j], - MIN (array->len - j, 134), - MM_SMS_ENCODING_UCS2, - 0); - } - } - g_byte_array_unref (array); - } else { - /* Do it with GSM encoding */ + if (mm_charset_can_convert_to (text, MM_MODEM_CHARSET_GSM)) { *encoding = MM_SMS_ENCODING_GSM7; - - if (in_len <= 160) { - out = g_new (gchar *, 2); - out[0] = g_strdup (text); - out[1] = NULL; - } else { - n_chunks = in_len / 153; - if (in_len % 153 != 0) - n_chunks++; - - out = g_new0 (gchar *, n_chunks + 1); - for (i = 0, j = 0; i < n_chunks; i++, j += 153) { - out[i] = g_strndup (&text[j], 153); - } - } + return util_split_text_gsm7 (text, strlen (text), log_object); } - return out; + /* Otherwise fallback to report UCS-2 and split supporting UTF-16 */ + *encoding = MM_SMS_ENCODING_UCS2; + return util_split_text_utf16_or_ucs2 (text, strlen (text), log_object); } GByteArray ** diff --git a/src/mm-sms-part-3gpp.h b/src/mm-sms-part-3gpp.h index bd6a242a..c6f4cf3f 100644 --- a/src/mm-sms-part-3gpp.h +++ b/src/mm-sms-part-3gpp.h @@ -22,31 +22,32 @@ #include "mm-sms-part.h" -MMSmsPart *mm_sms_part_3gpp_new_from_pdu (guint index, - const gchar *hexpdu, - GError **error); - -MMSmsPart *mm_sms_part_3gpp_new_from_binary_pdu (guint index, - const guint8 *pdu, - gsize pdu_len, - GError **error); - -guint8 *mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, - guint *out_pdulen, - guint *out_msgstart, - GError **error); +MMSmsPart *mm_sms_part_3gpp_new_from_pdu (guint index, + const gchar *hexpdu, + gpointer log_object, + GError **error); +MMSmsPart *mm_sms_part_3gpp_new_from_binary_pdu (guint index, + const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + gboolean transfer_route, + GError **error); +guint8 *mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part, + guint *out_pdulen, + guint *out_msgstart, + gpointer log_object, + GError **error); /* For testcases only */ -guint mm_sms_part_3gpp_encode_address (const gchar *address, - guint8 *buf, - gsize buflen, - gboolean is_smsc); - -gchar **mm_sms_part_3gpp_util_split_text (const gchar *text, - MMSmsEncoding *encoding); - -GByteArray **mm_sms_part_3gpp_util_split_data (const guint8 *data, - gsize data_len); +guint mm_sms_part_3gpp_encode_address (const gchar *address, + guint8 *buf, + gsize buflen, + gboolean is_smsc); +gchar **mm_sms_part_3gpp_util_split_text (const gchar *text, + MMSmsEncoding *encoding, + gpointer log_object); +GByteArray **mm_sms_part_3gpp_util_split_data (const guint8 *data, + gsize data_len); #endif /* MM_SMS_PART_3GPP_H */ diff --git a/src/mm-sms-part-cdma.c b/src/mm-sms-part-cdma.c index 0f40f653..d79a0f91 100644 --- a/src/mm-sms-part-cdma.c +++ b/src/mm-sms-part-cdma.c @@ -24,7 +24,7 @@ #include "mm-charsets.h" #include "mm-sms-part-cdma.h" -#include "mm-log.h" +#include "mm-log-object.h" /* * Documentation that you may want to have around: @@ -312,28 +312,22 @@ cause_code_to_delivery_state (guint8 error_class, /*****************************************************************************/ MMSmsPart * -mm_sms_part_cdma_new_from_pdu (guint index, - const gchar *hexpdu, - GError **error) +mm_sms_part_cdma_new_from_pdu (guint index, + const gchar *hexpdu, + gpointer log_object, + GError **error) { - gsize pdu_len; - guint8 *pdu; - MMSmsPart *part; + g_autofree guint8 *pdu = NULL; + gsize pdu_len; /* Convert PDU from hex to binary */ - pdu = (guint8 *) mm_utils_hexstr2bin (hexpdu, &pdu_len); + pdu = mm_utils_hexstr2bin (hexpdu, -1, &pdu_len, error); if (!pdu) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't convert CDMA PDU from hex to binary"); + g_prefix_error (error, "Couldn't convert CDMA PDU from hex to binary: "); return NULL; } - part = mm_sms_part_cdma_new_from_binary_pdu (index, pdu, pdu_len, error); - g_free (pdu); - - return part; + return mm_sms_part_cdma_new_from_binary_pdu (index, pdu, pdu_len, log_object, error); } struct Parameter { @@ -343,16 +337,17 @@ struct Parameter { } __attribute__((packed)); static void -read_teleservice_id (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_teleservice_id (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint16 teleservice_id; g_assert (parameter->parameter_id == PARAMETER_ID_TELESERVICE_ID); if (parameter->parameter_len != 2) { - mm_dbg (" invalid teleservice ID length found (%u != 2): ignoring", - parameter->parameter_len); + mm_obj_dbg (log_object, " invalid teleservice ID length found (%u != 2): ignoring", + parameter->parameter_len); return; } @@ -370,29 +365,30 @@ read_teleservice_id (MMSmsPart *sms_part, case MM_SMS_CDMA_TELESERVICE_ID_CATPT: break; default: - mm_dbg (" invalid teleservice ID found (%u): ignoring", teleservice_id); + mm_obj_dbg (log_object, " invalid teleservice ID found (%u): ignoring", teleservice_id); return; } - mm_dbg (" teleservice ID: %s (%u)", - mm_sms_cdma_teleservice_id_get_string (teleservice_id), - teleservice_id); + mm_obj_dbg (log_object, " teleservice ID: %s (%u)", + mm_sms_cdma_teleservice_id_get_string (teleservice_id), + teleservice_id); mm_sms_part_set_cdma_teleservice_id (sms_part, (MMSmsCdmaTeleserviceId)teleservice_id); } static void -read_service_category (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_service_category (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint16 service_category; g_assert (parameter->parameter_id == PARAMETER_ID_SERVICE_CATEGORY); if (parameter->parameter_len != 2) { - mm_dbg (" invalid service category length found (%u != 2): ignoring", - parameter->parameter_len); + mm_obj_dbg (log_object, " invalid service category length found (%u != 2): ignoring", + parameter->parameter_len); return; } @@ -438,20 +434,21 @@ read_service_category (MMSmsPart *sms_part, case MM_SMS_CDMA_SERVICE_CATEGORY_CMAS_TEST: break; default: - mm_dbg (" invalid service category found (%u): ignoring", service_category); + mm_obj_dbg (log_object, " invalid service category found (%u): ignoring", service_category); return; } - mm_dbg (" service category: %s (%u)", - mm_sms_cdma_service_category_get_string (service_category), - service_category); + mm_obj_dbg (log_object, " service category: %s (%u)", + mm_sms_cdma_service_category_get_string (service_category), + service_category); mm_sms_part_set_cdma_service_category (sms_part, - (MMSmsCdmaServiceCategory)service_category); + (MMSmsCdmaServiceCategory)service_category); } static guint8 -dtmf_to_ascii (guint8 dtmf) +dtmf_to_ascii (guint8 dtmf, + gpointer log_object) { static const gchar dtmf_to_ascii_digits[13] = { '\0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#' }; @@ -459,13 +456,14 @@ dtmf_to_ascii (guint8 dtmf) if (dtmf > 0 && dtmf < 13) return dtmf_to_ascii_digits[dtmf]; - mm_dbg (" invalid dtmf digit: %u", dtmf); + mm_obj_dbg (log_object, " invalid dtmf digit: %u", dtmf); return '\0'; } static void -read_address (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_address (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint8 digit_mode; guint8 number_mode; @@ -487,9 +485,9 @@ read_address (MMSmsPart *sms_part, #define PARAMETER_SIZE_CHECK(required_size) \ if (parameter->parameter_len < required_size) { \ - mm_dbg (" cannot read address, need at least %u bytes (got %u)", \ - required_size, \ - parameter->parameter_len); \ + mm_obj_dbg (log_object, " cannot read address, need at least %u bytes (got %u)", \ + required_size, \ + parameter->parameter_len); \ return; \ } @@ -502,10 +500,10 @@ read_address (MMSmsPart *sms_part, g_assert (digit_mode <= 1); switch (digit_mode) { case DIGIT_MODE_DTMF: - mm_dbg (" digit mode: dtmf"); + mm_obj_dbg (log_object, " digit mode: dtmf"); break; case DIGIT_MODE_ASCII: - mm_dbg (" digit mode: ascii"); + mm_obj_dbg (log_object, " digit mode: ascii"); break; default: g_assert_not_reached (); @@ -516,10 +514,10 @@ read_address (MMSmsPart *sms_part, OFFSETS_UPDATE (1); switch (number_mode) { case NUMBER_MODE_DIGIT: - mm_dbg (" number mode: digit"); + mm_obj_dbg (log_object, " number mode: digit"); break; case NUMBER_MODE_DATA_NETWORK_ADDRESS: - mm_dbg (" number mode: data network address"); + mm_obj_dbg (log_object, " number mode: data network address"); break; default: g_assert_not_reached (); @@ -532,25 +530,25 @@ read_address (MMSmsPart *sms_part, OFFSETS_UPDATE (3); switch (number_type) { case NUMBER_TYPE_UNKNOWN: - mm_dbg (" number type: unknown"); + mm_obj_dbg (log_object, " number type: unknown"); break; case NUMBER_TYPE_INTERNATIONAL: - mm_dbg (" number type: international"); + mm_obj_dbg (log_object, " number type: international"); break; case NUMBER_TYPE_NATIONAL: - mm_dbg (" number type: national"); + mm_obj_dbg (log_object, " number type: national"); break; case NUMBER_TYPE_NETWORK_SPECIFIC: - mm_dbg (" number type: specific"); + mm_obj_dbg (log_object, " number type: specific"); break; case NUMBER_TYPE_SUBSCRIBER: - mm_dbg (" number type: subscriber"); + mm_obj_dbg (log_object, " number type: subscriber"); break; case NUMBER_TYPE_ABBREVIATED: - mm_dbg (" number type: abbreviated"); + mm_obj_dbg (log_object, " number type: abbreviated"); break; default: - mm_dbg (" number type unknown (%u)", number_type); + mm_obj_dbg (log_object, " number type unknown (%u)", number_type); break; } } else @@ -564,22 +562,22 @@ read_address (MMSmsPart *sms_part, OFFSETS_UPDATE (4); switch (numbering_plan) { case NUMBERING_PLAN_UNKNOWN: - mm_dbg (" numbering plan: unknown"); + mm_obj_dbg (log_object, " numbering plan: unknown"); break; case NUMBERING_PLAN_ISDN: - mm_dbg (" numbering plan: isdn"); + mm_obj_dbg (log_object, " numbering plan: isdn"); break; case NUMBERING_PLAN_DATA: - mm_dbg (" numbering plan: data"); + mm_obj_dbg (log_object, " numbering plan: data"); break; case NUMBERING_PLAN_TELEX: - mm_dbg (" numbering plan: telex"); + mm_obj_dbg (log_object, " numbering plan: telex"); break; case NUMBERING_PLAN_PRIVATE: - mm_dbg (" numbering plan: private"); + mm_obj_dbg (log_object, " numbering plan: private"); break; default: - mm_dbg (" numbering plan unknown (%u)", numbering_plan); + mm_obj_dbg (log_object, " numbering plan unknown (%u)", numbering_plan); break; } } else @@ -589,7 +587,7 @@ read_address (MMSmsPart *sms_part, PARAMETER_SIZE_CHECK (byte_offset + 2); num_fields = read_bits (¶meter->parameter_value[byte_offset], bit_offset, 8); OFFSETS_UPDATE (8); - mm_dbg (" num fields: %u", num_fields); + mm_obj_dbg (log_object, " num fields: %u", num_fields); /* Address string */ @@ -598,7 +596,7 @@ read_address (MMSmsPart *sms_part, PARAMETER_SIZE_CHECK (byte_offset + 1 + ((bit_offset + (num_fields * 4)) / 8)); number = g_malloc (num_fields + 1); for (i = 0; i < num_fields; i++) { - number[i] = dtmf_to_ascii (read_bits (¶meter->parameter_value[byte_offset], bit_offset, 4)); + number[i] = dtmf_to_ascii (read_bits (¶meter->parameter_value[byte_offset], bit_offset, 4), log_object); OFFSETS_UPDATE (4); } number[i] = '\0'; @@ -634,9 +632,9 @@ read_address (MMSmsPart *sms_part, } number = g_string_free (str, FALSE); } else - mm_dbg (" data network address number type unknown (%u)", number_type); + mm_obj_dbg (log_object, " data network address number type unknown (%u)", number_type); - mm_dbg (" address: %s", number); + mm_obj_dbg (log_object, " address: %s", number); mm_sms_part_set_number (sms_part, number); g_free (number); @@ -646,28 +644,30 @@ read_address (MMSmsPart *sms_part, } static void -read_bearer_reply_option (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_bearer_reply_option (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint8 sequence; g_assert (parameter->parameter_id == PARAMETER_ID_BEARER_REPLY_OPTION); if (parameter->parameter_len != 1) { - mm_dbg (" invalid bearer reply option length found (%u != 1): ignoring", + mm_obj_dbg (log_object, " invalid bearer reply option length found (%u != 1): ignoring", parameter->parameter_len); return; } sequence = read_bits (¶meter->parameter_value[0], 0, 6); - mm_dbg (" sequence: %u", sequence); + mm_obj_dbg (log_object, " sequence: %u", sequence); mm_sms_part_set_message_reference (sms_part, sequence); } static void -read_cause_codes (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_cause_codes (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint8 sequence; guint8 error_class; @@ -677,38 +677,39 @@ read_cause_codes (MMSmsPart *sms_part, g_assert (parameter->parameter_id == PARAMETER_ID_BEARER_REPLY_OPTION); if (parameter->parameter_len != 1 && parameter->parameter_len != 2) { - mm_dbg (" invalid cause codes length found (%u): ignoring", + mm_obj_dbg (log_object, " invalid cause codes length found (%u): ignoring", parameter->parameter_len); return; } sequence = read_bits (¶meter->parameter_value[0], 0, 6); - mm_dbg (" sequence: %u", sequence); + mm_obj_dbg (log_object, " sequence: %u", sequence); error_class = read_bits (¶meter->parameter_value[0], 6, 2); - mm_dbg (" error class: %u", error_class); + mm_obj_dbg (log_object, " error class: %u", error_class); if (error_class != ERROR_CLASS_NO_ERROR) { if (parameter->parameter_len != 2) { - mm_dbg (" invalid cause codes length found (%u != 2): ignoring", + mm_obj_dbg (log_object, " invalid cause codes length found (%u != 2): ignoring", parameter->parameter_len); return; } cause_code = parameter->parameter_value[1]; - mm_dbg (" cause code: %u", cause_code); + mm_obj_dbg (log_object, " cause code: %u", cause_code); } else cause_code = 0; delivery_state = cause_code_to_delivery_state (error_class, cause_code); - mm_dbg (" delivery state: %s", mm_sms_delivery_state_get_string (delivery_state)); + mm_obj_dbg (log_object, " delivery state: %s", mm_sms_delivery_state_get_string (delivery_state)); mm_sms_part_set_message_reference (sms_part, sequence); mm_sms_part_set_delivery_state (sms_part, delivery_state); } static void -read_bearer_data_message_identifier (MMSmsPart *sms_part, - const struct Parameter *subparameter) +read_bearer_data_message_identifier (MMSmsPart *sms_part, + const struct Parameter *subparameter, + gpointer log_object) { guint8 message_type; guint16 message_id; @@ -717,7 +718,7 @@ read_bearer_data_message_identifier (MMSmsPart *sms_part, g_assert (subparameter->parameter_id == SUBPARAMETER_ID_MESSAGE_ID); if (subparameter->parameter_len != 3) { - mm_dbg (" invalid message identifier length found (%u): ignoring", + mm_obj_dbg (log_object, " invalid message identifier length found (%u): ignoring", subparameter->parameter_len); return; } @@ -725,49 +726,50 @@ read_bearer_data_message_identifier (MMSmsPart *sms_part, message_type = read_bits (&subparameter->parameter_value[0], 0, 4); switch (message_type) { case TELESERVICE_MESSAGE_TYPE_UNKNOWN: - mm_dbg (" message type: unknown"); + mm_obj_dbg (log_object, " message type: unknown"); break; case TELESERVICE_MESSAGE_TYPE_DELIVER: - mm_dbg (" message type: deliver"); + mm_obj_dbg (log_object, " message type: deliver"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_DELIVER); break; case TELESERVICE_MESSAGE_TYPE_SUBMIT: - mm_dbg (" message type: submit"); + mm_obj_dbg (log_object, " message type: submit"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_SUBMIT); break; case TELESERVICE_MESSAGE_TYPE_CANCELLATION: - mm_dbg (" message type: cancellation"); + mm_obj_dbg (log_object, " message type: cancellation"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_CANCELLATION); break; case TELESERVICE_MESSAGE_TYPE_DELIVERY_ACKNOWLEDGEMENT: - mm_dbg (" message type: delivery acknowledgement"); + mm_obj_dbg (log_object, " message type: delivery acknowledgement"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_DELIVERY_ACKNOWLEDGEMENT); break; case TELESERVICE_MESSAGE_TYPE_USER_ACKNOWLEDGEMENT: - mm_dbg (" message type: user acknowledgement"); + mm_obj_dbg (log_object, " message type: user acknowledgement"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_USER_ACKNOWLEDGEMENT); break; case TELESERVICE_MESSAGE_TYPE_READ_ACKNOWLEDGEMENT: - mm_dbg (" message type: read acknowledgement"); + mm_obj_dbg (log_object, " message type: read acknowledgement"); mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_CDMA_READ_ACKNOWLEDGEMENT); break; default: - mm_dbg (" message type unknown (%u)", message_type); + mm_obj_dbg (log_object, " message type unknown (%u)", message_type); break; } message_id = ((read_bits (&subparameter->parameter_value[0], 4, 8) << 8) | (read_bits (&subparameter->parameter_value[1], 4, 8))); message_id = GUINT16_FROM_BE (message_id); - mm_dbg (" message id: %u", (guint) message_id); + mm_obj_dbg (log_object, " message id: %u", (guint) message_id); header_ind = read_bits (&subparameter->parameter_value[2], 4, 1); - mm_dbg (" header indicator: %u", header_ind); + mm_obj_dbg (log_object, " header indicator: %u", header_ind); } static void -read_bearer_data_user_data (MMSmsPart *sms_part, - const struct Parameter *subparameter) +read_bearer_data_user_data (MMSmsPart *sms_part, + const struct Parameter *subparameter, + gpointer log_object) { guint8 message_encoding; guint8 message_type = 0; @@ -785,7 +787,7 @@ read_bearer_data_user_data (MMSmsPart *sms_part, #define SUBPARAMETER_SIZE_CHECK(required_size) \ if (subparameter->parameter_len < required_size) { \ - mm_dbg (" cannot read user data, need at least %u bytes (got %u)", \ + mm_obj_dbg (log_object, " cannot read user data, need at least %u bytes (got %u)", \ required_size, \ subparameter->parameter_len); \ return; \ @@ -797,21 +799,21 @@ read_bearer_data_user_data (MMSmsPart *sms_part, SUBPARAMETER_SIZE_CHECK (1); message_encoding = read_bits (&subparameter->parameter_value[byte_offset], bit_offset, 5); OFFSETS_UPDATE (5); - mm_dbg (" message encoding: %s", encoding_to_string (message_encoding)); + mm_obj_dbg (log_object, " message encoding: %s", encoding_to_string (message_encoding)); /* Message type, only if extended protocol message */ if (message_encoding == ENCODING_EXTENDED_PROTOCOL_MESSAGE) { SUBPARAMETER_SIZE_CHECK (2); message_type = read_bits (&subparameter->parameter_value[byte_offset], bit_offset, 8); OFFSETS_UPDATE (8); - mm_dbg (" message type: %u", message_type); + mm_obj_dbg (log_object, " message type: %u", message_type); } /* Number of fields */ SUBPARAMETER_SIZE_CHECK (byte_offset + 1 + ((bit_offset + 8) / 8)); num_fields = read_bits (&subparameter->parameter_value[byte_offset], bit_offset, 8); OFFSETS_UPDATE (8); - mm_dbg (" num fields: %u", num_fields); + mm_obj_dbg (log_object, " num fields: %u", num_fields); /* Now, process actual text or data */ switch (message_encoding) { @@ -828,7 +830,7 @@ read_bearer_data_user_data (MMSmsPart *sms_part, OFFSETS_UPDATE (8); } - mm_dbg (" data: (%u bytes)", num_fields); + mm_obj_dbg (log_object, " data: (%u bytes)", num_fields); mm_sms_part_take_data (sms_part, data); break; } @@ -837,7 +839,7 @@ read_bearer_data_user_data (MMSmsPart *sms_part, gchar *text; guint i; - SUBPARAMETER_SIZE_CHECK (byte_offset + 1 + ((bit_offset + (num_fields * 7)) / 8)); + SUBPARAMETER_SIZE_CHECK (byte_offset + ((bit_offset + (num_fields * 7)) / 8)); text = g_malloc (num_fields + 1); for (i = 0; i < num_fields; i++) { @@ -846,7 +848,7 @@ read_bearer_data_user_data (MMSmsPart *sms_part, } text[i] = '\0'; - mm_dbg (" text: '%s'", text); + mm_obj_dbg (log_object, " text: '%s'", text); mm_sms_part_take_text (sms_part, text); break; } @@ -865,11 +867,11 @@ read_bearer_data_user_data (MMSmsPart *sms_part, } latin[i] = '\0'; - text = g_convert (latin, -1, "UTF-8", "ISO−8859−1", NULL, NULL, NULL); + text = g_convert (latin, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); if (!text) { - mm_dbg (" text/data: ignored (latin to UTF-8 conversion error)"); + mm_obj_dbg (log_object, " text/data: ignored (latin to UTF-8 conversion error)"); } else { - mm_dbg (" text: '%s'", text); + mm_obj_dbg (log_object, " text: '%s'", text); mm_sms_part_take_text (sms_part, text); } @@ -896,9 +898,9 @@ read_bearer_data_user_data (MMSmsPart *sms_part, text = g_convert (utf16, num_bytes, "UTF-8", "UCS-2BE", NULL, NULL, NULL); if (!text) { - mm_dbg (" text/data: ignored (UTF-16 to UTF-8 conversion error)"); + mm_obj_dbg (log_object, " text/data: ignored (UTF-16 to UTF-8 conversion error)"); } else { - mm_dbg (" text: '%s'", text); + mm_obj_dbg (log_object, " text: '%s'", text); mm_sms_part_take_text (sms_part, text); } @@ -907,7 +909,7 @@ read_bearer_data_user_data (MMSmsPart *sms_part, } default: - mm_dbg (" text/data: ignored (unsupported encoding)"); + mm_obj_dbg (log_object, " text/data: ignored (unsupported encoding)"); } #undef OFFSETS_UPDATE @@ -915,16 +917,17 @@ read_bearer_data_user_data (MMSmsPart *sms_part, } static void -read_bearer_data (MMSmsPart *sms_part, - const struct Parameter *parameter) +read_bearer_data (MMSmsPart *sms_part, + const struct Parameter *parameter, + gpointer log_object) { guint offset; #define PARAMETER_SIZE_CHECK(required_size) \ if (parameter->parameter_len < required_size) { \ - mm_dbg (" cannot read bearer data, need at least %u bytes (got %u)", \ - required_size, \ - parameter->parameter_len); \ + mm_obj_dbg (log_object, " cannot read bearer data, need at least %u bytes (got %u)", \ + required_size, \ + parameter->parameter_len); \ return; \ } @@ -941,81 +944,81 @@ read_bearer_data (MMSmsPart *sms_part, switch (subparameter->parameter_id) { case SUBPARAMETER_ID_MESSAGE_ID: - mm_dbg (" reading message ID..."); - read_bearer_data_message_identifier (sms_part, subparameter); + mm_obj_dbg (log_object, " reading message ID..."); + read_bearer_data_message_identifier (sms_part, subparameter, log_object); break; case SUBPARAMETER_ID_USER_DATA: - mm_dbg (" reading user data..."); - read_bearer_data_user_data (sms_part, subparameter); + mm_obj_dbg (log_object, " reading user data..."); + read_bearer_data_user_data (sms_part, subparameter, log_object); break; case SUBPARAMETER_ID_USER_RESPONSE_CODE: - mm_dbg (" skipping user response code..."); + mm_obj_dbg (log_object, " skipping user response code..."); break; case SUBPARAMETER_ID_MESSAGE_CENTER_TIME_STAMP: - mm_dbg (" skipping message center timestamp..."); + mm_obj_dbg (log_object, " skipping message center timestamp..."); break; case SUBPARAMETER_ID_VALIDITY_PERIOD_ABSOLUTE: - mm_dbg (" skipping absolute validity period..."); + mm_obj_dbg (log_object, " skipping absolute validity period..."); break; case SUBPARAMETER_ID_VALIDITY_PERIOD_RELATIVE: - mm_dbg (" skipping relative validity period..."); + mm_obj_dbg (log_object, " skipping relative validity period..."); break; case SUBPARAMETER_ID_DEFERRED_DELIVERY_TIME_ABSOLUTE: - mm_dbg (" skipping absolute deferred delivery time..."); + mm_obj_dbg (log_object, " skipping absolute deferred delivery time..."); break; case SUBPARAMETER_ID_DEFERRED_DELIVERY_TIME_RELATIVE: - mm_dbg (" skipping relative deferred delivery time..."); + mm_obj_dbg (log_object, " skipping relative deferred delivery time..."); break; case SUBPARAMETER_ID_PRIORITY_INDICATOR: - mm_dbg (" skipping priority indicator..."); + mm_obj_dbg (log_object, " skipping priority indicator..."); break; case SUBPARAMETER_ID_PRIVACY_INDICATOR: - mm_dbg (" skipping privacy indicator..."); + mm_obj_dbg (log_object, " skipping privacy indicator..."); break; case SUBPARAMETER_ID_REPLY_OPTION: - mm_dbg (" skipping reply option..."); + mm_obj_dbg (log_object, " skipping reply option..."); break; case SUBPARAMETER_ID_NUMBER_OF_MESSAGES: - mm_dbg (" skipping number of messages..."); + mm_obj_dbg (log_object, " skipping number of messages..."); break; case SUBPARAMETER_ID_ALERT_ON_MESSAGE_DELIVERY: - mm_dbg (" skipping alert on message delivery..."); + mm_obj_dbg (log_object, " skipping alert on message delivery..."); break; case SUBPARAMETER_ID_LANGUAGE_INDICATOR: - mm_dbg (" skipping language indicator..."); + mm_obj_dbg (log_object, " skipping language indicator..."); break; case SUBPARAMETER_ID_CALL_BACK_NUMBER: - mm_dbg (" skipping call back number..."); + mm_obj_dbg (log_object, " skipping call back number..."); break; case SUBPARAMETER_ID_MESSAGE_DISPLAY_MODE: - mm_dbg (" skipping message display mode..."); + mm_obj_dbg (log_object, " skipping message display mode..."); break; case SUBPARAMETER_ID_MULTIPLE_ENCODING_USER_DATA: - mm_dbg (" skipping multiple encoding user data..."); + mm_obj_dbg (log_object, " skipping multiple encoding user data..."); break; case SUBPARAMETER_ID_MESSAGE_DEPOSIT_INDEX: - mm_dbg (" skipping message deposit index..."); + mm_obj_dbg (log_object, " skipping message deposit index..."); break; case SUBPARAMETER_ID_SERVICE_CATEGORY_PROGRAM_DATA: - mm_dbg (" skipping service category program data..."); + mm_obj_dbg (log_object, " skipping service category program data..."); break; case SUBPARAMETER_ID_SERVICE_CATEGORY_PROGRAM_RESULT: - mm_dbg (" skipping service category program result..."); + mm_obj_dbg (log_object, " skipping service category program result..."); break; case SUBPARAMETER_ID_MESSAGE_STATUS: - mm_dbg (" skipping message status..."); + mm_obj_dbg (log_object, " skipping message status..."); break; case SUBPARAMETER_ID_TP_FAILURE_CAUSE: - mm_dbg (" skipping TP failure case..."); + mm_obj_dbg (log_object, " skipping TP failure case..."); break; case SUBPARAMETER_ID_ENHANCED_VMN: - mm_dbg (" skipping enhanced vmn..."); + mm_obj_dbg (log_object, " skipping enhanced vmn..."); break; case SUBPARAMETER_ID_ENHANCED_VMN_ACK: - mm_dbg (" skipping enhanced vmn ack..."); + mm_obj_dbg (log_object, " skipping enhanced vmn ack..."); break; default: - mm_dbg (" unknown subparameter found: '%u' (ignoring)", + mm_obj_dbg (log_object, " unknown subparameter found: '%u' (ignoring)", subparameter->parameter_id); break; } @@ -1025,10 +1028,11 @@ read_bearer_data (MMSmsPart *sms_part, } MMSmsPart * -mm_sms_part_cdma_new_from_binary_pdu (guint index, - const guint8 *pdu, - gsize pdu_len, - GError **error) +mm_sms_part_cdma_new_from_binary_pdu (guint index, + const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + GError **error) { MMSmsPart *sms_part; guint offset; @@ -1038,9 +1042,9 @@ mm_sms_part_cdma_new_from_binary_pdu (guint index, sms_part = mm_sms_part_new (index, MM_SMS_PDU_TYPE_UNKNOWN); if (index != SMS_PART_INVALID_INDEX) - mm_dbg ("Parsing CDMA PDU (%u)...", index); + mm_obj_dbg (log_object, "parsing CDMA PDU (%u)...", index); else - mm_dbg ("Parsing CDMA PDU..."); + mm_obj_dbg (log_object, "parsing CDMA PDU..."); #define PDU_SIZE_CHECK(required_size, check_descr_str) \ if (pdu_len < required_size) { \ @@ -1088,47 +1092,47 @@ mm_sms_part_cdma_new_from_binary_pdu (guint index, switch (parameter->parameter_id) { case PARAMETER_ID_TELESERVICE_ID: - mm_dbg (" reading teleservice ID..."); - read_teleservice_id (sms_part, parameter); + mm_obj_dbg (log_object, " reading teleservice ID..."); + read_teleservice_id (sms_part, parameter, log_object); break; case PARAMETER_ID_SERVICE_CATEGORY: - mm_dbg (" reading service category..."); - read_service_category (sms_part, parameter); + mm_obj_dbg (log_object, " reading service category..."); + read_service_category (sms_part, parameter, log_object); break; case PARAMETER_ID_ORIGINATING_ADDRESS: - mm_dbg (" reading originating address..."); + mm_obj_dbg (log_object, " reading originating address..."); if (mm_sms_part_get_number (sms_part)) - mm_dbg (" cannot read originating address; an address field was already read"); + mm_obj_dbg (log_object, " cannot read originating address; an address field was already read"); else - read_address (sms_part, parameter); + read_address (sms_part, parameter, log_object); break; case PARAMETER_ID_ORIGINATING_SUBADDRESS: - mm_dbg (" skipping originating subaddress..."); + mm_obj_dbg (log_object, " skipping originating subaddress..."); break; case PARAMETER_ID_DESTINATION_ADDRESS: - mm_dbg (" reading destination address..."); + mm_obj_dbg (log_object, " reading destination address..."); if (mm_sms_part_get_number (sms_part)) - mm_dbg (" cannot read destination address; an address field was already read"); + mm_obj_dbg (log_object, " cannot read destination address; an address field was already read"); else - read_address (sms_part, parameter); + read_address (sms_part, parameter, log_object); break; case PARAMETER_ID_DESTINATION_SUBADDRESS: - mm_dbg (" skipping destination subaddress..."); + mm_obj_dbg (log_object, " skipping destination subaddress..."); break; case PARAMETER_ID_BEARER_REPLY_OPTION: - mm_dbg (" reading bearer reply option..."); - read_bearer_reply_option (sms_part, parameter); + mm_obj_dbg (log_object, " reading bearer reply option..."); + read_bearer_reply_option (sms_part, parameter, log_object); break; case PARAMETER_ID_CAUSE_CODES: - mm_dbg (" reading cause codes..."); - read_cause_codes (sms_part, parameter); + mm_obj_dbg (log_object, " reading cause codes..."); + read_cause_codes (sms_part, parameter, log_object); break; case PARAMETER_ID_BEARER_DATA: - mm_dbg (" reading bearer data..."); - read_bearer_data (sms_part, parameter); + mm_obj_dbg (log_object, " reading bearer data..."); + read_bearer_data (sms_part, parameter, log_object); break; default: - mm_dbg (" unknown parameter found: '%u' (ignoring)", + mm_obj_dbg (log_object, " unknown parameter found: '%u' (ignoring)", parameter->parameter_id); break; } @@ -1138,15 +1142,15 @@ mm_sms_part_cdma_new_from_binary_pdu (guint index, switch (message_type) { case MESSAGE_TYPE_POINT_TO_POINT: if (mm_sms_part_get_cdma_teleservice_id (sms_part) == MM_SMS_CDMA_TELESERVICE_ID_UNKNOWN) - mm_dbg (" mandatory parameter missing: teleservice ID not found or invalid in point-to-point message"); + mm_obj_dbg (log_object, " mandatory parameter missing: teleservice ID not found or invalid in point-to-point message"); break; case MESSAGE_TYPE_BROADCAST: if (mm_sms_part_get_cdma_service_category (sms_part) == MM_SMS_CDMA_SERVICE_CATEGORY_UNKNOWN) - mm_dbg (" mandatory parameter missing: service category not found or invalid in broadcast message"); + mm_obj_dbg (log_object, " mandatory parameter missing: service category not found or invalid in broadcast message"); break; case MESSAGE_TYPE_ACKNOWLEDGE: if (mm_sms_part_get_message_reference (sms_part) == 0) - mm_dbg (" mandatory parameter missing: cause codes not found or invalid in acknowledge message"); + mm_obj_dbg (log_object, " mandatory parameter missing: cause codes not found or invalid in acknowledge message"); break; default: break; @@ -1197,7 +1201,8 @@ write_bits (guint8 *bytes, /*****************************************************************************/ static guint8 -dtmf_from_ascii (guint8 ascii) +dtmf_from_ascii (guint8 ascii, + gpointer log_object) { if (ascii >= '1' && ascii <= '9') return ascii - '0'; @@ -1208,19 +1213,20 @@ dtmf_from_ascii (guint8 ascii) if (ascii == '#') return 12; - mm_dbg (" invalid ascii digit in dtmf conversion: %c", ascii); + mm_obj_dbg (log_object, " invalid ascii digit in dtmf conversion: %c", ascii); return 0; } static gboolean -write_teleservice_id (MMSmsPart *part, - guint8 *pdu, - guint *absolute_offset, - GError **error) +write_teleservice_id (MMSmsPart *part, + guint8 *pdu, + guint *absolute_offset, + gpointer log_object, + GError **error) { guint16 aux16; - mm_dbg (" writing teleservice ID..."); + mm_obj_dbg (log_object, " writing teleservice ID..."); if (mm_sms_part_get_cdma_teleservice_id (part) != MM_SMS_CDMA_TELESERVICE_ID_WMT) { g_set_error (error, @@ -1232,9 +1238,9 @@ write_teleservice_id (MMSmsPart *part, return FALSE; } - mm_dbg (" teleservice ID: %s (%u)", - mm_sms_cdma_teleservice_id_get_string (MM_SMS_CDMA_TELESERVICE_ID_WMT), - MM_SMS_CDMA_TELESERVICE_ID_WMT); + mm_obj_dbg (log_object, " teleservice ID: %s (%u)", + mm_sms_cdma_teleservice_id_get_string (MM_SMS_CDMA_TELESERVICE_ID_WMT), + MM_SMS_CDMA_TELESERVICE_ID_WMT); /* Teleservice ID: WMT always */ pdu[0] = PARAMETER_ID_TELESERVICE_ID; @@ -1247,10 +1253,11 @@ write_teleservice_id (MMSmsPart *part, } static gboolean -write_destination_address (MMSmsPart *part, - guint8 *pdu, - guint *absolute_offset, - GError **error) +write_destination_address (MMSmsPart *part, + guint8 *pdu, + guint *absolute_offset, + gpointer log_object, + GError **error) { const gchar *number; guint bit_offset; @@ -1258,7 +1265,7 @@ write_destination_address (MMSmsPart *part, guint n_digits; guint i; - mm_dbg (" writing destination address..."); + mm_obj_dbg (log_object, " writing destination address..."); #define OFFSETS_UPDATE(n_bits) do { \ bit_offset += n_bits; \ @@ -1278,12 +1285,12 @@ write_destination_address (MMSmsPart *part, bit_offset = 0; /* Digit mode: DTMF always */ - mm_dbg (" digit mode: dtmf"); + mm_obj_dbg (log_object, " digit mode: dtmf"); write_bits (&pdu[byte_offset], bit_offset, 1, DIGIT_MODE_DTMF); OFFSETS_UPDATE (1); /* Number mode: DIGIT always */ - mm_dbg (" number mode: digit"); + mm_obj_dbg (log_object, " number mode: digit"); write_bits (&pdu[byte_offset], bit_offset, 1, NUMBER_MODE_DIGIT); OFFSETS_UPDATE (1); @@ -1298,16 +1305,16 @@ write_destination_address (MMSmsPart *part, n_digits); return FALSE; } - mm_dbg (" num fields: %u", n_digits); + mm_obj_dbg (log_object, " num fields: %u", n_digits); write_bits (&pdu[byte_offset], bit_offset, 8, n_digits); OFFSETS_UPDATE (8); /* Actual DTMF encoded number */ - mm_dbg (" address: %s", number); + mm_obj_dbg (log_object, " address: %s", number); for (i = 0; i < n_digits; i++) { guint8 dtmf; - dtmf = dtmf_from_ascii (number[i]); + dtmf = dtmf_from_ascii (number[i], log_object); if (!dtmf) { g_set_error (error, MM_CORE_ERROR, @@ -1339,15 +1346,16 @@ write_destination_address (MMSmsPart *part, } static gboolean -write_bearer_data_message_identifier (MMSmsPart *part, - guint8 *pdu, - guint *parameter_offset, - GError **error) +write_bearer_data_message_identifier (MMSmsPart *part, + guint8 *pdu, + guint *parameter_offset, + gpointer log_object, + GError **error) { pdu[0] = SUBPARAMETER_ID_MESSAGE_ID; pdu[1] = 3; /* subparameter_len, always 3 */ - mm_dbg (" writing message identifier: submit"); + mm_obj_dbg (log_object, " writing message identifier: submit"); /* Message type */ write_bits (&pdu[2], 0, 4, TELESERVICE_MESSAGE_TYPE_SUBMIT); @@ -1360,66 +1368,57 @@ write_bearer_data_message_identifier (MMSmsPart *part, return TRUE; } -static void +static GByteArray * decide_best_encoding (const gchar *text, - GByteArray **out, - guint *num_fields, - guint *num_bits_per_field, - Encoding *encoding) + gpointer log_object, + guint *num_fields, + guint *num_bits_per_field, + Encoding *encoding, + GError **error) { - guint ascii_unsupported = 0; - guint i; - guint len; + g_autoptr(GByteArray) barray = NULL; + MMModemCharset target_charset = MM_MODEM_CHARSET_UNKNOWN; + guint len; len = strlen (text); - /* Check if we can do ASCII-7 */ - for (i = 0; i < len; i++) { - if (text[i] & 0x80) { - ascii_unsupported++; - break; - } + if (mm_charset_can_convert_to (text, MM_MODEM_CHARSET_IRA)) + target_charset = MM_MODEM_CHARSET_IRA; + else if (mm_charset_can_convert_to (text, MM_MODEM_CHARSET_8859_1)) + target_charset = MM_MODEM_CHARSET_8859_1; + else + target_charset = MM_MODEM_CHARSET_UCS2; + + barray = mm_modem_charset_bytearray_from_utf8 (text, target_charset, FALSE, error); + if (!barray) { + g_prefix_error (error, "Couldn't decide best encoding: "); + return NULL; } - /* If ASCII-7 already supported, done we are */ - if (!ascii_unsupported) { - *out = g_byte_array_sized_new (len); - g_byte_array_append (*out, (const guint8 *)text, len); + if (target_charset == MM_MODEM_CHARSET_IRA) { *num_fields = len; *num_bits_per_field = 7; *encoding = ENCODING_ASCII_7BIT; - return; - } - - /* Check if we can do Latin encoding */ - if (mm_charset_can_convert_to (text, MM_MODEM_CHARSET_8859_1)) { - *out = g_byte_array_sized_new (len); - mm_modem_charset_byte_array_append (*out, - text, - FALSE, - MM_MODEM_CHARSET_8859_1); - *num_fields = (*out)->len; + } else if (target_charset == MM_MODEM_CHARSET_8859_1) { + *num_fields = barray->len; *num_bits_per_field = 8; *encoding = ENCODING_LATIN; - return; - } + } else if (target_charset == MM_MODEM_CHARSET_UCS2) { + *num_fields = barray->len / 2; + *num_bits_per_field = 16; + *encoding = ENCODING_UNICODE; + } else + g_assert_not_reached (); - /* If no Latin and no ASCII, default to UTF-16 */ - *out = g_byte_array_sized_new (len * 2); - mm_modem_charset_byte_array_append (*out, - text, - FALSE, - MM_MODEM_CHARSET_UCS2); - *num_fields = (*out)->len / 2; - *num_bits_per_field = 16; - *encoding = ENCODING_UNICODE; + return g_steal_pointer (&barray); } static gboolean -write_bearer_data_user_data (MMSmsPart *part, - guint8 *pdu, - guint *parameter_offset, - GError **error) +write_bearer_data_user_data (MMSmsPart *part, + guint8 *pdu, + guint *parameter_offset, + gpointer log_object, + GError **error) { const gchar *text; const GByteArray *data; @@ -1433,7 +1432,7 @@ write_bearer_data_user_data (MMSmsPart *part, const GByteArray *aux; guint num_bits_per_iter; - mm_dbg (" writing user data..."); + mm_obj_dbg (log_object, " writing user data..."); #define OFFSETS_UPDATE(n_bits) do { \ bit_offset += n_bits; \ @@ -1455,11 +1454,14 @@ write_bearer_data_user_data (MMSmsPart *part, /* Text or Data */ if (text) { - decide_best_encoding (text, - &converted, - &num_fields, - &num_bits_per_field, - &encoding); + converted = decide_best_encoding (text, + log_object, + &num_fields, + &num_bits_per_field, + &encoding, + error); + if (!converted) + return FALSE; aux = (const GByteArray *)converted; } else { aux = data; @@ -1469,7 +1471,7 @@ write_bearer_data_user_data (MMSmsPart *part, } /* Message encoding*/ - mm_dbg (" message encoding: %s", encoding_to_string (encoding)); + mm_obj_dbg (log_object, " message encoding: %s", encoding_to_string (encoding)); write_bits (&pdu[byte_offset], bit_offset, 5, encoding); OFFSETS_UPDATE (5); @@ -1484,16 +1486,16 @@ write_bearer_data_user_data (MMSmsPart *part, num_fields); return FALSE; } - mm_dbg (" num fields: %u", num_fields); + mm_obj_dbg (log_object, " num fields: %u", num_fields); write_bits (&pdu[byte_offset], bit_offset, 8, num_fields); OFFSETS_UPDATE (8); /* For ASCII-7, write 7 bits in each iteration; for the remaining ones * go byte per byte */ if (text) - mm_dbg (" text: '%s'", text); + mm_obj_dbg (log_object, " text: '%s'", text); else - mm_dbg (" data: (%u bytes)", num_fields); + mm_obj_dbg (log_object, " data: (%u bytes)", num_fields); num_bits_per_iter = num_bits_per_field < 8 ? num_bits_per_field : 8; for (i = 0; i < aux->len; i++) { write_bits (&pdu[byte_offset], bit_offset, num_bits_per_iter, aux->data[i]); @@ -1522,24 +1524,25 @@ write_bearer_data_user_data (MMSmsPart *part, } static gboolean -write_bearer_data (MMSmsPart *part, - guint8 *pdu, - guint *absolute_offset, - GError **error) +write_bearer_data (MMSmsPart *part, + guint8 *pdu, + guint *absolute_offset, + gpointer log_object, + GError **error) { GError *inner_error = NULL; guint offset = 0; - mm_dbg (" writing bearer data..."); + mm_obj_dbg (log_object, " writing bearer data..."); pdu[0] = PARAMETER_ID_BEARER_DATA; /* Write parameter length at the end */ offset = 2; - if (!write_bearer_data_message_identifier (part, &pdu[offset], &offset, &inner_error)) - mm_dbg ("Error writing message identifier: %s", inner_error->message); - else if (!write_bearer_data_user_data (part, &pdu[offset], &offset, &inner_error)) - mm_dbg ("Error writing user data: %s", inner_error->message); + if (!write_bearer_data_message_identifier (part, &pdu[offset], &offset, log_object, &inner_error)) + mm_obj_dbg (log_object, "error writing message identifier: %s", inner_error->message); + else if (!write_bearer_data_user_data (part, &pdu[offset], &offset, log_object, &inner_error)) + mm_obj_dbg (log_object, "error writing user data: %s", inner_error->message); if (inner_error) { g_propagate_error (error, inner_error); @@ -1564,9 +1567,10 @@ write_bearer_data (MMSmsPart *part, } guint8 * -mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, - guint *out_pdulen, - GError **error) +mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, + guint *out_pdulen, + gpointer log_object, + GError **error) { GError *inner_error = NULL; guint offset = 0; @@ -1584,7 +1588,7 @@ mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, return NULL; } - mm_dbg ("Creating PDU for part..."); + mm_obj_dbg (log_object, "creating PDU for part..."); /* Current max size estimations: * Message type: 1 byte @@ -1597,12 +1601,12 @@ mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, /* First byte: SMS message type */ pdu[offset++] = MESSAGE_TYPE_POINT_TO_POINT; - if (!write_teleservice_id (part, &pdu[offset], &offset, &inner_error)) - mm_dbg ("Error writing Teleservice ID: %s", inner_error->message); - else if (!write_destination_address (part, &pdu[offset], &offset, &inner_error)) - mm_dbg ("Error writing destination address: %s", inner_error->message); - else if (!write_bearer_data (part, &pdu[offset], &offset, &inner_error)) - mm_dbg ("Error writing bearer data: %s", inner_error->message); + if (!write_teleservice_id (part, &pdu[offset], &offset, log_object, &inner_error)) + mm_obj_dbg (log_object, "error writing teleservice ID: %s", inner_error->message); + else if (!write_destination_address (part, &pdu[offset], &offset, log_object, &inner_error)) + mm_obj_dbg (log_object, "error writing destination address: %s", inner_error->message); + else if (!write_bearer_data (part, &pdu[offset], &offset, log_object, &inner_error)) + mm_obj_dbg (log_object, "error writing bearer data: %s", inner_error->message); if (inner_error) { g_propagate_error (error, inner_error); diff --git a/src/mm-sms-part-cdma.h b/src/mm-sms-part-cdma.h index 7331c892..804f67b1 100644 --- a/src/mm-sms-part-cdma.h +++ b/src/mm-sms-part-cdma.h @@ -21,17 +21,18 @@ #include "mm-sms-part.h" -MMSmsPart *mm_sms_part_cdma_new_from_pdu (guint index, - const gchar *hexpdu, - GError **error); - -MMSmsPart *mm_sms_part_cdma_new_from_binary_pdu (guint index, - const guint8 *pdu, - gsize pdu_len, - GError **error); - -guint8 *mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, - guint *out_pdulen, - GError **error); +MMSmsPart *mm_sms_part_cdma_new_from_pdu (guint index, + const gchar *hexpdu, + gpointer log_object, + GError **error); +MMSmsPart *mm_sms_part_cdma_new_from_binary_pdu (guint index, + const guint8 *pdu, + gsize pdu_len, + gpointer log_object, + GError **error); +guint8 *mm_sms_part_cdma_get_submit_pdu (MMSmsPart *part, + guint *out_pdulen, + gpointer log_object, + GError **error); #endif /* MM_SMS_PART_CDMA_H */ diff --git a/src/mm-sms-part.h b/src/mm-sms-part.h index 92f39b11..133d2e08 100644 --- a/src/mm-sms-part.h +++ b/src/mm-sms-part.h @@ -20,11 +20,27 @@ #include #include +/* Despite 3GPP TS 23.038 specifies that Unicode SMS messages are + * encoded in UCS-2, UTF-16 encoding is commonly used instead on many + * modern platforms to allow encoding code points that fall outside the + * Basic Multilingual Plane (BMP), such as Emoji. Most of the UCS-2 + * code points are identical to their equivalent UTF-16 code points. + * In UTF-16, non-BMP code points are encoded in a pair of surrogate + * code points (i.e. a high surrogate in 0xD800..0xDBFF, followed by a + * low surrogate in 0xDC00..0xDFFF). An isolated surrogate code point + * has no general interpretation in UTF-16, but could be a valid + * (though unmapped) code point in UCS-2. + * + * The current implementation in ModemManager just assumes that whenever + * possible (i.e. when parsing received PDUs or when creating submit + * PDUs) UTF-16 will be used instead of plain UCS-2 (even if the PDUs + * report the encoding as UCS-2). + */ typedef enum { /*< underscore_name=mm_sms_encoding >*/ MM_SMS_ENCODING_UNKNOWN = 0x0, MM_SMS_ENCODING_GSM7, MM_SMS_ENCODING_8BIT, - MM_SMS_ENCODING_UCS2 + MM_SMS_ENCODING_UCS2, } MMSmsEncoding; typedef struct _MMSmsPart MMSmsPart; @@ -43,6 +59,8 @@ MMSmsPart *mm_sms_part_new (guint index, MMSmsPduType type); void mm_sms_part_free (MMSmsPart *part); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsPart, mm_sms_part_free) + guint mm_sms_part_get_index (MMSmsPart *part); void mm_sms_part_set_index (MMSmsPart *part, guint index); diff --git a/src/mm-sms-qmi.c b/src/mm-sms-qmi.c index fabd417a..81c6f476 100644 --- a/src/mm-sms-qmi.c +++ b/src/mm-sms-qmi.c @@ -24,6 +24,7 @@ #define _LIBMM_INSIDE_MM #include +#include "mm-broadband-modem-qmi.h" #include "mm-modem-helpers-qmi.h" #include "mm-iface-modem.h" #include "mm-iface-modem-messaging.h" @@ -31,7 +32,7 @@ #include "mm-base-modem.h" #include "mm-sms-part-3gpp.h" #include "mm-sms-part-cdma.h" -#include "mm-log.h" +#include "mm-log-object.h" G_DEFINE_TYPE (MMSmsQmi, mm_sms_qmi, MM_TYPE_BASE_SMS) @@ -53,7 +54,7 @@ ensure_qmi_client (MMSmsQmi *self, NULL); g_assert (MM_IS_BASE_MODEM (modem)); - port = mm_base_modem_peek_port_qmi (modem); + port = mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (modem)); g_object_unref (modem); if (!port) { @@ -190,6 +191,7 @@ store_ready (QmiClientWms *client, static void sms_store_next_part (GTask *task) { + MMSmsQmi *self; SmsStoreContext *ctx; QmiMessageWmsRawWriteInput *input; guint8 *pdu = NULL; @@ -198,6 +200,7 @@ sms_store_next_part (GTask *task) GArray *array; GError *error = NULL; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); if (!ctx->current) { @@ -209,9 +212,9 @@ sms_store_next_part (GTask *task) /* Get PDU */ if (MM_SMS_PART_IS_3GPP ((MMSmsPart *)ctx->current->data)) - pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error); + pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, self, &error); else if (MM_SMS_PART_IS_CDMA ((MMSmsPart *)ctx->current->data)) - pdu = mm_sms_part_cdma_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &error); + pdu = mm_sms_part_cdma_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, self, &error); if (!pdu) { if (error) @@ -329,11 +332,14 @@ send_generic_ready (QmiClientWms *client, GAsyncResult *res, GTask *task) { + MMSmsQmi *self; SmsSendContext *ctx; QmiMessageWmsRawSendOutput *output = NULL; GError *error = NULL; guint16 message_id; + self = g_task_get_source_object (task); + output = qmi_client_wms_raw_send_finish (client, res, &error); if (!output) { g_prefix_error (&error, "QMI operation failed: "); @@ -351,11 +357,11 @@ send_generic_ready (QmiClientWms *client, &rp_cause, &tp_cause, NULL)) { - mm_warn ("Couldn't send SMS; RP cause (%u): '%s'; TP cause (%u): '%s'", - rp_cause, - qmi_wms_gsm_umts_rp_cause_get_string (rp_cause), - tp_cause, - qmi_wms_gsm_umts_tp_cause_get_string (tp_cause)); + mm_obj_warn (self, "couldn't send SMS; RP cause (%u): %s; TP cause (%u): %s", + rp_cause, + qmi_wms_gsm_umts_rp_cause_get_string (rp_cause), + tp_cause, + qmi_wms_gsm_umts_tp_cause_get_string (tp_cause)); } qmi_message_wms_raw_send_output_unref (output); @@ -381,6 +387,7 @@ send_generic_ready (QmiClientWms *client, static void sms_send_generic (GTask *task) { + MMSmsQmi *self; SmsSendContext *ctx; QmiMessageWmsRawSendInput *input; guint8 *pdu = NULL; @@ -389,13 +396,14 @@ sms_send_generic (GTask *task) GArray *array; GError *error = NULL; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); /* Get PDU */ if (MM_SMS_PART_IS_3GPP ((MMSmsPart *)ctx->current->data)) - pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error); + pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, self, &error); else if (MM_SMS_PART_IS_CDMA ((MMSmsPart *)ctx->current->data)) - pdu = mm_sms_part_cdma_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &error); + pdu = mm_sms_part_cdma_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, self, &error); if (!pdu) { if (error) @@ -442,11 +450,13 @@ send_from_storage_ready (QmiClientWms *client, GAsyncResult *res, GTask *task) { + MMSmsQmi *self; SmsSendContext *ctx; QmiMessageWmsSendFromMemoryStorageOutput *output = NULL; GError *error = NULL; guint16 message_id; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); output = qmi_client_wms_send_from_memory_storage_finish (client, res, &error); @@ -454,8 +464,7 @@ send_from_storage_ready (QmiClientWms *client, if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED)) { - mm_dbg ("Couldn't send SMS from storage: '%s'; trying generic send...", - error->message); + mm_obj_dbg (self, "couldn't send SMS from storage: %s; trying generic send...", error->message); g_error_free (error); ctx->from_storage = FALSE; sms_send_next_part (task); @@ -473,8 +482,7 @@ send_from_storage_ready (QmiClientWms *client, if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) { - mm_dbg ("Couldn't send SMS from storage: '%s'; trying generic send...", - error->message); + mm_obj_dbg (self, "couldn't send SMS from storage: %s; trying generic send...", error->message); g_error_free (error); ctx->from_storage = FALSE; sms_send_next_part (task); @@ -489,29 +497,29 @@ send_from_storage_ready (QmiClientWms *client, &rp_cause, &tp_cause, NULL)) { - mm_warn ("Couldn't send SMS; RP cause (%u): '%s'; TP cause (%u): '%s'", - rp_cause, - qmi_wms_gsm_umts_rp_cause_get_string (rp_cause), - tp_cause, - qmi_wms_gsm_umts_tp_cause_get_string (tp_cause)); + mm_obj_warn (self, "couldn't send SMS; RP cause (%u): %s; TP cause (%u): %s", + rp_cause, + qmi_wms_gsm_umts_rp_cause_get_string (rp_cause), + tp_cause, + qmi_wms_gsm_umts_tp_cause_get_string (tp_cause)); } if (qmi_message_wms_send_from_memory_storage_output_get_cdma_cause_code ( output, &cdma_cause_code, NULL)) { - mm_warn ("Couldn't send SMS; cause code (%u): '%s'", - cdma_cause_code, - qmi_wms_cdma_cause_code_get_string (cdma_cause_code)); + mm_obj_warn (self, "couldn't send SMS; cause code (%u): %s", + cdma_cause_code, + qmi_wms_cdma_cause_code_get_string (cdma_cause_code)); } if (qmi_message_wms_send_from_memory_storage_output_get_cdma_error_class ( output, &cdma_error_class, NULL)) { - mm_warn ("Couldn't send SMS; error class (%u): '%s'", - cdma_error_class, - qmi_wms_cdma_error_class_get_string (cdma_error_class)); + mm_obj_warn (self, "couldn't send SMS; error class (%u): %s", + cdma_error_class, + qmi_wms_cdma_error_class_get_string (cdma_error_class)); } g_prefix_error (&error, "Couldn't write SMS part: "); @@ -658,24 +666,26 @@ delete_part_ready (QmiClientWms *client, GAsyncResult *res, GTask *task) { + MMSmsQmi *self; SmsDeletePartsContext *ctx; QmiMessageWmsDeleteOutput *output = NULL; GError *error = NULL; + self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); output = qmi_client_wms_delete_finish (client, res, &error); if (!output) { ctx->n_failed++; - mm_dbg ("QMI operation failed: Couldn't delete SMS part with index %u: '%s'", - mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), - error->message); + mm_obj_dbg (self, "QMI operation failed: couldn't delete SMS part with index %u: %s", + mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), + error->message); g_error_free (error); } else if (!qmi_message_wms_delete_output_get_result (output, &error)) { ctx->n_failed++; - mm_dbg ("Couldn't delete SMS part with index %u: '%s'", - mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), - error->message); + mm_obj_dbg (self, "couldn't delete SMS part with index %u: %s", + mm_sms_part_get_index ((MMSmsPart *)ctx->current->data), + error->message); g_error_free (error); } diff --git a/src/mm-sms-qmi.h b/src/mm-sms-qmi.h index 64a2f300..af60a7f5 100644 --- a/src/mm-sms-qmi.h +++ b/src/mm-sms-qmi.h @@ -45,6 +45,7 @@ struct _MMSmsQmiClass { }; GType mm_sms_qmi_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsQmi, g_object_unref) MMBaseSms *mm_sms_qmi_new (MMBaseModem *modem); diff --git a/src/mm-utils.c b/src/mm-utils.c new file mode 100644 index 00000000..95fbb552 --- /dev/null +++ b/src/mm-utils.c @@ -0,0 +1,47 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Singleton support imported from NetworkManager. + * (C) Copyright 2014 Red Hat, Inc. + * + * GPtrArray lookup with GEqualFunc imported from GLib 2.48 + */ + +#include "mm-utils.h" + +#if !GLIB_CHECK_VERSION(2,54,0) + +gboolean +mm_ptr_array_find_with_equal_func (GPtrArray *haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint *index_) +{ + guint i; + + g_return_val_if_fail (haystack != NULL, FALSE); + + if (equal_func == NULL) + equal_func = g_direct_equal; + + for (i = 0; i < haystack->len; i++) { + if (equal_func (g_ptr_array_index (haystack, i), needle)) { + if (index_ != NULL) + *index_ = i; + return TRUE; + } + } + + return FALSE; +} + +#endif diff --git a/src/mm-utils.h b/src/mm-utils.h index 395c39e1..613205a3 100644 --- a/src/mm-utils.h +++ b/src/mm-utils.h @@ -12,6 +12,8 @@ * * Singleton support imported from NetworkManager. * (C) Copyright 2014 Red Hat, Inc. + * + * GPtrArray lookup with GEqualFunc imported from GLib 2.48 */ #ifndef MM_UTILS_H @@ -20,7 +22,7 @@ #include #include -#include "mm-log.h" +#include "mm-log-object.h" /*****************************************************************************/ @@ -32,7 +34,7 @@ _singleton_instance_weak_ref_cb (gpointer data, \ GObject *where_the_object_was) \ { \ - mm_dbg ("disposing %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + mm_obj_dbg (singleton_instance, "singleton disposed"); \ singleton_instance = NULL; \ } \ static inline void \ @@ -47,7 +49,7 @@ { \ if (singleton_instance) { \ if (G_OBJECT (singleton_instance)->ref_count > 1) \ - mm_dbg ("disown %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + mm_obj_dbg (singleton_instance, "singleton disowned"); \ g_object_unref (singleton_instance); \ } \ } @@ -70,12 +72,24 @@ g_assert (!_already_created || (MM_DEFINE_SINGLETON_ALLOW_MULTIPLE)); \ _already_created = TRUE; \ singleton_instance = (g_object_new (GTYPE, ##__VA_ARGS__, NULL)); \ - g_assert (singleton_instance); \ - mm_singleton_instance_weak_ref_register (); \ - mm_dbg ("create %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + g_assert (singleton_instance); \ + mm_singleton_instance_weak_ref_register (); \ + mm_obj_dbg (singleton_instance, "singleton created"); \ } \ return singleton_instance; \ } \ MM_DEFINE_SINGLETON_DESTRUCTOR(TYPE) + +#if !GLIB_CHECK_VERSION(2,54,0) + +/* Pointer Array lookup with a GEqualFunc, imported from GLib 2.54 */ +#define g_ptr_array_find_with_equal_func mm_ptr_array_find_with_equal_func +gboolean mm_ptr_array_find_with_equal_func (GPtrArray *haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint *index_); + +#endif + #endif /* MM_UTILS_H */ diff --git a/src/tests/test-at-serial-port.c b/src/tests/test-at-serial-port.c index c864701f..5372c478 100644 --- a/src/tests/test-at-serial-port.c +++ b/src/tests/test-at-serial-port.c @@ -18,13 +18,20 @@ #include #include "mm-port-serial-at.h" -#include "mm-log.h" +#include "mm-serial-parsers.h" +#include "mm-log-test.h" typedef struct { const gchar *original; const gchar *without_echo; } EchoRemovalTest; +typedef struct { + const gchar *response; + const gboolean found; + const gboolean expected_error; +} ParseResponseTest; + static const EchoRemovalTest echo_removal_tests[] = { { "\r\n", "\r\n" }, { "\r", "\r" }, @@ -41,6 +48,41 @@ static const EchoRemovalTest echo_removal_tests[] = { { "\r\nthis is valid\r\nand so is this\r\n", "\r\nthis is valid\r\nand so is this\r\n" }, }; +static const ParseResponseTest parse_ok_tests[] = { + { "\r\nOK\r\n", TRUE, FALSE}, + { "\r\nOK\r\n\r\n+CMTI: \"ME\",1\r\n", TRUE, FALSE}, + { "\r\nOK\r\n\r\n+CIEV: 7,1\r\n\r\n+CRING: VOICE\r\n\r\n+CLIP: \"+0123456789\",145,,,,0\r\n", TRUE, FALSE}, + { "\r\nUNKNOWN COMMAND\r\n", FALSE, FALSE} +}; + +static const ParseResponseTest parse_error_tests[] = { + { "\r\nUNKNOWN COMMAND\r\n", FALSE, FALSE}, + { "\r\nERROR\r\n", TRUE, TRUE}, + { "\r\nERROR\r\n\r\noooops\r\n", TRUE, TRUE}, + { "\r\n+CME ERROR: raspberry\r\n", TRUE, TRUE}, + { "\r\n+CME ERROR: 123\r\n", TRUE, TRUE}, + { "\r\n+CME ERROR: \r\n", TRUE, TRUE}, + { "\r\n+CME ERROR:\r\n", FALSE, FALSE}, + { "\r\n+CMS ERROR: bananas\r\n", TRUE, TRUE}, + { "\r\n+CMS ERROR: 456\r\n", TRUE, TRUE}, + { "\r\n+CMS ERROR: \r\n", TRUE, TRUE}, + { "\r\n+CMS ERROR:\r\n", FALSE, FALSE}, + { "\r\nMODEM ERROR: 5\r\n", TRUE, TRUE}, + { "\r\nMODEM ERROR: apple\r\n", FALSE, FALSE}, + { "\r\nMODEM ERROR: \r\n", FALSE, FALSE}, + { "\r\nMODEM ERROR:\r\n", FALSE, FALSE}, + { "\r\nCOMMAND NOT SUPPORT\r\n", TRUE, TRUE}, + { "\r\nCOMMAND NOT SUPPORT\r\n\r\nSomething extra\r\n", TRUE, TRUE}, + { "\r\nNO CARRIER\r\n", TRUE, TRUE}, + { "\r\nNO CARRIER\r\n\r\nSomething extra\r\n", TRUE, TRUE}, + { "\r\nBUSY\r\n", TRUE, TRUE}, + { "\r\nBUSY\r\n\r\nSomething extra\r\n", TRUE, TRUE}, + { "\r\nNO ANSWER\r\n", TRUE, TRUE}, + { "\r\nNO ANSWER\r\n\r\nSomething extra\r\n", TRUE, TRUE}, + { "\r\nNO DIALTONE\r\n", TRUE, TRUE}, + { "\r\nNO DIALTONE\r\n\r\nSomething extra\r\n", TRUE, TRUE} +}; + static void at_serial_echo_removal (void) { @@ -64,24 +106,47 @@ at_serial_echo_removal (void) } } -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) +static void +_run_parse_test (const ParseResponseTest tests[], guint number_of_tests) { - va_list args; - gchar *msg; + guint i; + gpointer parser; + GError *error = NULL; + gboolean found = FALSE; + GString *response; + + for (i = 0; i < number_of_tests; i++) { + parser = mm_serial_parser_v1_new (); + response = g_string_new (tests[i].response); + found = mm_serial_parser_v1_parse (parser, response, NULL, &error); + + /* Verify if we expect a match or not */ + g_assert_cmpint (found, ==, tests[i].found); + + /* Error expected */ + if (tests[i].expected_error) { + g_assert (error != NULL); + } + /* No error expected */ + else { + g_assert_no_error (error); + } + + g_string_free (response, TRUE); + error = NULL ; + } +} - if (!g_test_verbose ()) - return; +static void +at_serial_parse_ok (void) +{ + _run_parse_test (parse_ok_tests, G_N_ELEMENTS(parse_ok_tests)); +} - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); +static void +at_serial_parse_error (void) +{ + _run_parse_test (parse_error_tests, G_N_ELEMENTS(parse_error_tests)); } int main (int argc, char **argv) @@ -89,6 +154,8 @@ int main (int argc, char **argv) g_test_init (&argc, &argv, NULL); g_test_add_func ("/ModemManager/AT-serial/echo-removal", at_serial_echo_removal); + g_test_add_func ("/ModemManager/AT-serial/parse-ok", at_serial_parse_ok); + g_test_add_func ("/ModemManager/AT-serial/parse-error", at_serial_parse_error); return g_test_run (); } diff --git a/src/tests/test-charsets.c b/src/tests/test-charsets.c index 01a5b7a7..8735fd22 100644 --- a/src/tests/test-charsets.c +++ b/src/tests/test-charsets.c @@ -18,28 +18,29 @@ #include #include "mm-modem-helpers.h" -#include "mm-log.h" +#include "mm-log-test.h" static void common_test_gsm7 (const gchar *in_utf8) { - guint32 unpacked_gsm_len = 0; guint32 packed_gsm_len = 0; guint32 unpacked_gsm_len_2 = 0; - g_autofree guint8 *unpacked_gsm = NULL; + g_autoptr(GByteArray) unpacked_gsm = NULL; g_autofree guint8 *packed_gsm = NULL; - g_autofree guint8 *unpacked_gsm_2 = NULL; + guint8 *unpacked_gsm_2 = NULL; + g_autoptr(GByteArray) unpacked_gsm_2_array = NULL; g_autofree gchar *built_utf8 = NULL; + g_autoptr(GError) error = NULL; /* Convert to GSM */ - unpacked_gsm = mm_charset_utf8_to_unpacked_gsm (in_utf8, &unpacked_gsm_len); + unpacked_gsm = mm_modem_charset_bytearray_from_utf8 (in_utf8, MM_MODEM_CHARSET_GSM, FALSE, &error); g_assert_nonnull (unpacked_gsm); - g_assert_cmpuint (unpacked_gsm_len, >, 0); + g_assert_no_error (error); /* Pack */ - packed_gsm = mm_charset_gsm_pack (unpacked_gsm, unpacked_gsm_len, 0, &packed_gsm_len); + packed_gsm = mm_charset_gsm_pack (unpacked_gsm->data, unpacked_gsm->len, 0, &packed_gsm_len); g_assert_nonnull (packed_gsm); - g_assert_cmpuint (packed_gsm_len, <=, unpacked_gsm_len); + g_assert_cmpuint (packed_gsm_len, <=, unpacked_gsm->len); #if 0 { @@ -56,10 +57,12 @@ common_test_gsm7 (const gchar *in_utf8) /* Unpack */ unpacked_gsm_2 = mm_charset_gsm_unpack (packed_gsm, packed_gsm_len * 8 / 7, 0, &unpacked_gsm_len_2); g_assert_nonnull (unpacked_gsm_2); + unpacked_gsm_2_array = g_byte_array_new_take (unpacked_gsm_2, unpacked_gsm_len_2); /* And back to UTF-8 */ - built_utf8 = (gchar *) mm_charset_gsm_unpacked_to_utf8 (unpacked_gsm_2, unpacked_gsm_len_2); + built_utf8 = mm_modem_charset_bytearray_to_utf8 (unpacked_gsm_2_array, MM_MODEM_CHARSET_GSM, FALSE, &error); g_assert_nonnull (built_utf8); + g_assert_no_error (error); g_assert_cmpstr (built_utf8, ==, in_utf8); } @@ -314,38 +317,71 @@ test_gsm7_pack_7_chars_offset (void) } static void -test_take_convert_ucs2_hex_utf8 (void) +test_str_ucs2_to_from_utf8 (void) { - gchar *src, *converted; - - /* Ensure hex-encoded UCS-2 works */ - src = g_strdup ("0054002d004d006f00620069006c0065"); - converted = mm_charset_take_and_convert_to_utf8 (src, MM_MODEM_CHARSET_UCS2); - g_assert_cmpstr (converted, ==, "T-Mobile"); - g_free (converted); + const gchar *src = "0054002D004D006F00620069006C0065"; + g_autofree gchar *utf8 = NULL; + g_autofree gchar *dst = NULL; + g_autoptr(GError) error = NULL; + + utf8 = mm_modem_charset_str_to_utf8 (src, -1, MM_MODEM_CHARSET_UCS2, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (utf8, ==, "T-Mobile"); + + dst = mm_modem_charset_str_from_utf8 (utf8, MM_MODEM_CHARSET_UCS2, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (dst, ==, src); } static void -test_take_convert_ucs2_bad_ascii (void) +test_str_gsm_to_from_utf8 (void) { - gchar *src, *converted; + const gchar *src = "T-Mobile"; + g_autofree gchar *utf8 = NULL; + g_autofree gchar *dst = NULL; + g_autoptr(GError) error = NULL; + + /* Note: as long as the GSM string doesn't contain the '@' character, str_to_utf8() + * and str_from_utf8() can safely be used */ + + utf8 = mm_modem_charset_str_to_utf8 (src, -1, MM_MODEM_CHARSET_GSM, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (utf8, ==, src); - /* Test that something mostly ASCII returns most of the original string */ - src = g_strdup ("Orange\241"); - converted = mm_charset_take_and_convert_to_utf8 (src, MM_MODEM_CHARSET_UCS2); - g_assert_cmpstr (converted, ==, "Orange"); - g_free (converted); + dst = mm_modem_charset_str_from_utf8 (utf8, MM_MODEM_CHARSET_GSM, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (dst, ==, src); } static void -test_take_convert_ucs2_bad_ascii2 (void) +test_str_gsm_to_from_utf8_with_at (void) { - gchar *src, *converted; - - /* Ensure something completely screwed up doesn't crash */ - src = g_strdup ("\241\255\254\250\244\234"); - converted = mm_charset_take_and_convert_to_utf8 (src, MM_MODEM_CHARSET_UCS2); - g_assert (converted == NULL); + /* The NULs are '@' chars, except for the trailing one which is always taken as end-of-string */ + const gchar src[] = { 'T', '-', 'M', 0x00, 'o', 'b', 'i', 0x00, 'l', 'e', 0x00 }; + const gchar *utf8_expected = "T-M@obi@le"; + const gchar *src_translit = "T-M?obi?le"; + g_autofree gchar *utf8 = NULL; + g_autofree gchar *dst = NULL; + g_autoptr(GError) error = NULL; + + /* Note: as long as the GSM string doesn't contain the '@' character, str_to_utf8() + * and str_from_utf8() can safely be used */ + + utf8 = mm_modem_charset_str_to_utf8 (src, G_N_ELEMENTS (src), MM_MODEM_CHARSET_GSM, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (utf8, ==, utf8_expected); + + /* if charset conversion from UTF-8 contains '@' chars, running without transliteration + * will return an error */ + dst = mm_modem_charset_str_from_utf8 (utf8, MM_MODEM_CHARSET_GSM, FALSE, &error); + g_assert_nonnull (error); + g_assert_null (dst); + g_clear_error (&error); + + /* with transliteration, '@'->'?' */ + dst = mm_modem_charset_str_from_utf8 (utf8, MM_MODEM_CHARSET_GSM, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (dst, ==, src_translit); } struct charset_can_convert_to_test_s { @@ -354,6 +390,7 @@ struct charset_can_convert_to_test_s { gboolean to_ira; gboolean to_8859_1; gboolean to_ucs2; + gboolean to_utf16; gboolean to_pccp437; gboolean to_pcdn; }; @@ -364,35 +401,35 @@ test_charset_can_covert_to (void) static const struct charset_can_convert_to_test_s charset_can_convert_to_test[] = { { .utf8 = "", - .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, + .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, }, { .utf8 = " ", - .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, + .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, }, { .utf8 = "some basic ascii", - .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, + .to_gsm = TRUE, .to_ira = TRUE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, }, { .utf8 = "ホモ・サピエンス 喂人类 katakana, chinese, english: UCS2 takes it all", - .to_gsm = FALSE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, + .to_gsm = FALSE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, }, { .utf8 = "Some from the GSM7 basic set: a % Ψ Ω ñ ö è æ", - .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, + .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, }, { .utf8 = "More from the GSM7 extended set: {} [] ~ € |", - .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, + .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = FALSE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = FALSE, .to_pcdn = FALSE, }, { .utf8 = "patín cannot be encoded in GSM7 or IRA, but is valid UCS2, ISO-8859-1, CP437 and CP850", - .to_gsm = FALSE, .to_ira = FALSE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, + .to_gsm = FALSE, .to_ira = FALSE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, }, { .utf8 = "ècole can be encoded in multiple ways, but not in IRA", - .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, + .to_gsm = TRUE, .to_ira = FALSE, .to_8859_1 = TRUE, .to_ucs2 = TRUE, .to_utf16 = TRUE, .to_pccp437 = TRUE, .to_pcdn = TRUE, }, }; guint i; @@ -403,31 +440,12 @@ test_charset_can_covert_to (void) g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_IRA) == charset_can_convert_to_test[i].to_ira); g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_8859_1) == charset_can_convert_to_test[i].to_8859_1); g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_UCS2) == charset_can_convert_to_test[i].to_ucs2); + g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_UTF16) == charset_can_convert_to_test[i].to_utf16); g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_PCCP437) == charset_can_convert_to_test[i].to_pccp437); g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_PCDN) == charset_can_convert_to_test[i].to_pcdn); } } -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - int main (int argc, char **argv) { setlocale (LC_ALL, ""); @@ -447,9 +465,9 @@ int main (int argc, char **argv) g_test_add_func ("/MM/charsets/gsm7/pack/last-septet-alone", test_gsm7_pack_last_septet_alone); g_test_add_func ("/MM/charsets/gsm7/pack/7-chars-offset", test_gsm7_pack_7_chars_offset); - g_test_add_func ("/MM/charsets/take-convert/ucs2/hex", test_take_convert_ucs2_hex_utf8); - g_test_add_func ("/MM/charsets/take-convert/ucs2/bad-ascii", test_take_convert_ucs2_bad_ascii); - g_test_add_func ("/MM/charsets/take-convert/ucs2/bad-ascii-2", test_take_convert_ucs2_bad_ascii2); + g_test_add_func ("/MM/charsets/str-from-to/ucs2", test_str_ucs2_to_from_utf8); + g_test_add_func ("/MM/charsets/str-from-to/gsm", test_str_gsm_to_from_utf8); + g_test_add_func ("/MM/charsets/str-from-to/gsm-with-at", test_str_gsm_to_from_utf8_with_at); g_test_add_func ("/MM/charsets/can-convert-to", test_charset_can_covert_to); diff --git a/src/tests/test-error-helpers.c b/src/tests/test-error-helpers.c index 228dfc02..ddff9a0d 100644 --- a/src/tests/test-error-helpers.c +++ b/src/tests/test-error-helpers.c @@ -38,7 +38,7 @@ \ enum_value = g_enum_get_value (enum_class, i); \ if (enum_value) { \ - error = mm_## ERROR_SMALL ## _for_code ((MM##ERROR_CAMEL)i); \ + error = mm_## ERROR_SMALL ## _for_code ((MM##ERROR_CAMEL)i, NULL); \ g_assert_error (error, MM_ ## ERROR_CAPS, i); \ g_error_free (error); \ } \ @@ -52,26 +52,6 @@ TEST_ERROR_HELPER (MESSAGE_ERROR, message_error, MessageError) /*****************************************************************************/ -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - int main (int argc, char **argv) { setlocale (LC_ALL, ""); diff --git a/src/tests/test-modem-helpers-qmi.c b/src/tests/test-modem-helpers-qmi.c index d6b491c5..fbd6cdba 100644 --- a/src/tests/test-modem-helpers-qmi.c +++ b/src/tests/test-modem-helpers-qmi.c @@ -21,7 +21,7 @@ #include "mm-enums-types.h" #include "mm-modem-helpers-qmi.h" -#include "mm-log.h" +#include "mm-log-test.h" static void test_capabilities_expected (MMQmiCapabilitiesContext *ctx, @@ -31,7 +31,7 @@ test_capabilities_expected (MMQmiCapabilitiesContext *ctx, gchar *expected_str; gchar *built_str; - built = mm_modem_capability_from_qmi_capabilities_context (ctx); + built = mm_modem_capability_from_qmi_capabilities_context (ctx, NULL); expected_str = mm_modem_capability_build_string_from_mask (expected); built_str = mm_modem_capability_build_string_from_mask (built); @@ -309,26 +309,6 @@ test_gobi3k_cdma (void) /*****************************************************************************/ -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - int main (int argc, char **argv) { setlocale (LC_ALL, ""); diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index bd747448..9624c520 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -22,7 +22,7 @@ #define _LIBMM_INSIDE_MM #include #include "mm-modem-helpers.h" -#include "mm-log.h" +#include "mm-log-test.h" #define g_assert_cmpfloat_tolerance(val1, val2, tolerance) \ g_assert_cmpfloat (fabs (val1 - val2), <, tolerance) @@ -37,7 +37,7 @@ test_ifc_response (const gchar *str, MMFlowControl mask; GError *error = NULL; - mask = mm_parse_ifc_test_response (str, &error); + mask = mm_parse_ifc_test_response (str, NULL, &error); g_assert_no_error (error); g_assert_cmpuint (mask, ==, expected); } @@ -486,7 +486,7 @@ test_cops_results (const gchar *desc, g_debug ("Testing %s +COPS response...", desc); - results = mm_3gpp_parse_cops_test_response (reply, cur_charset, &error); + results = mm_3gpp_parse_cops_test_response (reply, cur_charset, NULL, &error); g_assert (results); g_assert_no_error (error); g_assert_cmpuint (g_list_length (results), ==, expected_results_len); @@ -626,9 +626,10 @@ test_cops_response_motoc (void *f, gpointer d) static void test_cops_response_mf627a (void *f, gpointer d) { + /* The '@' in this string is ASCII 0x40, and 0x40 is a valid GSM-7 char: '¡' (which is 0xc2,0xa1 in UTF-8) */ const char *reply = "+COPS: (2,\"AT&T@\",\"AT&TD\",\"310410\",0),(3,\"Vstream Wireless\",\"VSTREAM\",\"31026\",0),"; static MM3gppNetworkInfo expected[] = { - { MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT, (gchar *) "AT&T@", (gchar *) "AT&TD", (gchar *) "310410", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, + { MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT, (gchar *) "AT&T¡", (gchar *) "AT&TD", (gchar *) "310410", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, { MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN, (gchar *) "Vstream Wireless", (gchar *) "VSTREAM", (gchar *) "31026", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, }; @@ -638,9 +639,10 @@ test_cops_response_mf627a (void *f, gpointer d) static void test_cops_response_mf627b (void *f, gpointer d) { + /* The '@' in this string is ASCII 0x40, and 0x40 is a valid GSM-7 char: '¡' (which is 0xc2,0xa1 in UTF-8) */ const char *reply = "+COPS: (2,\"AT&Tp\",\"AT&T@\",\"310410\",0),(3,\"\",\"\",\"31026\",0),"; static MM3gppNetworkInfo expected[] = { - { MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT, (gchar *) "AT&Tp", (gchar *) "AT&T@", (gchar *) "310410", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, + { MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT, (gchar *) "AT&Tp", (gchar *) "AT&T¡", (gchar *) "310410", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, { MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN, NULL, NULL, (gchar *) "31026", MM_MODEM_ACCESS_TECHNOLOGY_GSM }, }; @@ -916,7 +918,7 @@ test_cops_response_gsm_invalid (void *f, gpointer d) GList *results; GError *error = NULL; - results = mm_3gpp_parse_cops_test_response (reply, MM_MODEM_CHARSET_GSM, &error); + results = mm_3gpp_parse_cops_test_response (reply, MM_MODEM_CHARSET_GSM, NULL, &error); g_assert (results == NULL); g_assert_no_error (error); } @@ -928,7 +930,7 @@ test_cops_response_umts_invalid (void *f, gpointer d) GList *results; GError *error = NULL; - results = mm_3gpp_parse_cops_test_response (reply, MM_MODEM_CHARSET_GSM, &error); + results = mm_3gpp_parse_cops_test_response (reply, MM_MODEM_CHARSET_GSM, NULL, &error); g_assert (results == NULL); g_assert_no_error (error); } @@ -1041,7 +1043,7 @@ common_test_normalize_operator (const NormalizeOperatorTest *t) gchar *str; str = g_strdup (t->input); - mm_3gpp_normalize_operator (&str, t->charset); + mm_3gpp_normalize_operator (&str, t->charset, NULL); if (!t->normalized) g_assert (!str); else @@ -1094,6 +1096,7 @@ typedef struct { guint regex_num; gboolean cgreg; gboolean cereg; + gboolean c5greg; } CregResult; static void @@ -1109,7 +1112,7 @@ test_creg_match (const char *test, MMModemAccessTechnology access_tech = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; gulong lac = 0, ci = 0; GError *error = NULL; - gboolean success, cgreg = FALSE, cereg = FALSE; + gboolean success, cgreg = FALSE, cereg = FALSE, c5greg = FALSE; guint regex_num = 0; GPtrArray *array; @@ -1129,7 +1132,7 @@ test_creg_match (const char *test, if (g_regex_match (r, reply, 0, &info)) { g_debug (" matched with %d", i); - regex_num = i + 1; + regex_num = i; break; } g_match_info_free (info); @@ -1143,19 +1146,18 @@ test_creg_match (const char *test, g_assert (info != NULL); g_assert_cmpuint (regex_num, ==, result->regex_num); - success = mm_3gpp_parse_creg_response (info, &state, &lac, &ci, &access_tech, &cgreg, &cereg, &error); + success = mm_3gpp_parse_creg_response (info, NULL, &state, &lac, &ci, &access_tech, &cgreg, &cereg, &c5greg, &error); + g_match_info_free (info); g_assert (success); g_assert_no_error (error); g_assert_cmpuint (state, ==, result->state); - g_assert (lac == result->lac); - g_assert (ci == result->ci); - - g_debug (" access_tech (%d) == result->act (%d)", - access_tech, result->act); + g_assert_cmpuint (lac, ==, result->lac); + g_assert_cmpuint (ci, ==, result->ci); g_assert_cmpuint (access_tech, ==, result->act); g_assert_cmpuint (cgreg, ==, result->cgreg); g_assert_cmpuint (cereg, ==, result->cereg); + g_assert_cmpuint (c5greg, ==, result->c5greg); } static void @@ -1163,7 +1165,7 @@ test_creg1_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG: 1,3"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 2, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, FALSE, FALSE, FALSE }; test_creg_match ("CREG=1", TRUE, reply, data, &result); } @@ -1173,7 +1175,7 @@ test_creg1_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 3\r\n"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 1, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, FALSE, FALSE }; test_creg_match ("CREG=1", FALSE, reply, data, &result); } @@ -1182,8 +1184,8 @@ static void test_creg2_mercury_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; - const char *reply = "+CREG: 0,1,84CD,00D30173"; - const CregResult result = { 1, 0x84cd, 0xd30173, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const char *reply = "+CREG: 1,1,84CD,00D30173"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x84cd, 0xd30173, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Sierra Mercury CREG=2", TRUE, reply, data, &result); } @@ -1193,7 +1195,7 @@ test_creg2_mercury_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 1,84CD,00D30156\r\n"; - const CregResult result = { 1, 0x84cd, 0xd30156, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 3, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x84cd, 0xd30156, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 2, FALSE, FALSE, FALSE }; test_creg_match ("Sierra Mercury CREG=2", FALSE, reply, data, &result); } @@ -1203,7 +1205,7 @@ test_creg2_sek850i_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG: 2,1,\"CE00\",\"01CEAD8F\""; - const CregResult result = { 1, 0xce00, 0x01cead8f, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0xce00, 0x01cead8f, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Sony Ericsson K850i CREG=2", TRUE, reply, data, &result); } @@ -1213,7 +1215,7 @@ test_creg2_sek850i_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 1,\"CE00\",\"00005449\"\r\n"; - const CregResult result = { 1, 0xce00, 0x5449, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 3, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0xce00, 0x5449, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 2, FALSE, FALSE, FALSE }; test_creg_match ("Sony Ericsson K850i CREG=2", FALSE, reply, data, &result); } @@ -1223,7 +1225,7 @@ test_creg2_e160g_solicited_unregistered (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG: 2,0,00,0"; - const CregResult result = { 0, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_IDLE, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Huawei E160G unregistered CREG=2", TRUE, reply, data, &result); } @@ -1233,7 +1235,7 @@ test_creg2_e160g_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG: 2,1,8BE3,2BAF"; - const CregResult result = { 1, 0x8be3, 0x2baf, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x8be3, 0x2baf, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Huawei E160G CREG=2", TRUE, reply, data, &result); } @@ -1242,8 +1244,8 @@ static void test_creg2_e160g_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; - const char *reply = "\r\n+CREG: 2,8BE3,2BAF\r\n"; - const CregResult result = { 2, 0x8be3, 0x2baf, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 3, FALSE, FALSE }; + const char *reply = "\r\n+CREG: 1,8BE3,2BAF\r\n"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x8be3, 0x2baf, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 2, FALSE, FALSE, FALSE }; test_creg_match ("Huawei E160G CREG=2", FALSE, reply, data, &result); } @@ -1253,7 +1255,7 @@ test_creg2_tm506_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG: 2,1,\"8BE3\",\"00002BAF\""; - const CregResult result = { 1, 0x8BE3, 0x2BAF, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x8BE3, 0x2BAF, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; /* Test leading zeros in the CI */ test_creg_match ("Sony Ericsson TM-506 CREG=2", TRUE, reply, data, &result); @@ -1264,7 +1266,7 @@ test_creg2_xu870_unsolicited_unregistered (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 2,,\r\n"; - const CregResult result = { 2, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 3, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 2, FALSE, FALSE, FALSE }; test_creg_match ("Novatel XU870 unregistered CREG=2", FALSE, reply, data, &result); } @@ -1274,7 +1276,7 @@ test_creg2_iridium_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG:002,001,\"18d8\",\"ffff\""; - const CregResult result = { 1, 0x18D8, 0xFFFF, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 5, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x18D8, 0xFFFF, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 4, FALSE, FALSE, FALSE }; test_creg_match ("Iridium, CREG=2", TRUE, reply, data, &result); } @@ -1284,7 +1286,7 @@ test_creg2_no_leading_zeros_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG:2,1,0001,0010"; - const CregResult result = { 1, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("solicited CREG=2 with no leading zeros in integer fields", TRUE, reply, data, &result); } @@ -1294,7 +1296,7 @@ test_creg2_leading_zeros_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CREG:002,001,\"0001\",\"0010\""; - const CregResult result = { 1, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 5, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 4, FALSE, FALSE, FALSE }; test_creg_match ("solicited CREG=2 with leading zeros in integer fields", TRUE, reply, data, &result); } @@ -1304,7 +1306,7 @@ test_creg2_no_leading_zeros_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 1,0001,0010,0\r\n"; - const CregResult result = { 1, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 6, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 5, FALSE, FALSE, FALSE }; test_creg_match ("unsolicited CREG=2 with no leading zeros in integer fields", FALSE, reply, data, &result); } @@ -1314,7 +1316,7 @@ test_creg2_leading_zeros_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 001,\"0001\",\"0010\",000\r\n"; - const CregResult result = { 1, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 7, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0001, 0x0010, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 6, FALSE, FALSE, FALSE }; test_creg_match ("unsolicited CREG=2 with leading zeros in integer fields", FALSE, reply, data, &result); } @@ -1324,8 +1326,7 @@ test_creg2_ublox_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const gchar *reply = "\r\n+CREG: 2,6,\"8B37\",\"0A265185\",7\r\n"; - /* NOTE: '6' means registered for "SMS only", home network; we just assume UNKNOWN in this case */ - const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 8, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 7, FALSE, FALSE, FALSE }; test_creg_match ("Ublox Toby-L2 solicited while on LTE", TRUE, reply, data, &result); } @@ -1335,8 +1336,7 @@ test_creg2_ublox_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const gchar *reply = "\r\n+CREG: 6,\"8B37\",\"0A265185\",7\r\n"; - /* NOTE: '6' means registered for "SMS only", home network; we just assume UNKNOWN in this case */ - const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 6, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 5, FALSE, FALSE, FALSE }; test_creg_match ("Ublox Toby-L2 unsolicited while on LTE", FALSE, reply, data, &result); } @@ -1346,7 +1346,7 @@ test_cgreg1_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CGREG: 1,3"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 2, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, TRUE, FALSE, FALSE }; test_creg_match ("CGREG=1", TRUE, reply, data, &result); } @@ -1356,7 +1356,7 @@ test_cgreg1_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 3\r\n"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 1, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, TRUE, FALSE, FALSE }; test_creg_match ("CGREG=1", FALSE, reply, data, &result); } @@ -1366,7 +1366,7 @@ test_cgreg2_f3607gw_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CGREG: 2,1,\"8BE3\",\"00002B5D\",3"; - const CregResult result = { 1, 0x8BE3, 0x2B5D, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 8, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x8BE3, 0x2B5D, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 7, TRUE, FALSE, FALSE }; test_creg_match ("Ericsson F3607gw CGREG=2", TRUE, reply, data, &result); } @@ -1376,7 +1376,7 @@ test_cgreg2_f3607gw_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 1,\"8BE3\",\"00002B5D\",3\r\n"; - const CregResult result = { 1, 0x8BE3, 0x2B5D, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 6, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x8BE3, 0x2B5D, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 5, TRUE, FALSE, FALSE }; test_creg_match ("Ericsson F3607gw CGREG=2", FALSE, reply, data, &result); } @@ -1386,7 +1386,7 @@ test_creg2_md400_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 2,5,\"0502\",\"0404736D\"\r\n"; - const CregResult result = { 5, 0x0502, 0x0404736D, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING, 0x0502, 0x0404736D, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Sony-Ericsson MD400 CREG=2", FALSE, reply, data, &result); } @@ -1396,7 +1396,7 @@ test_cgreg2_md400_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 5,\"0502\",\"0404736D\",2\r\n"; - const CregResult result = { 5, 0x0502, 0x0404736D, MM_MODEM_ACCESS_TECHNOLOGY_UMTS, 6, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING, 0x0502, 0x0404736D, MM_MODEM_ACCESS_TECHNOLOGY_UMTS, 5, TRUE, FALSE, FALSE }; test_creg_match ("Sony-Ericsson MD400 CGREG=2", FALSE, reply, data, &result); } @@ -1406,7 +1406,7 @@ test_creg_cgreg_multi_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 5\r\n\r\n+CGREG: 0\r\n"; - const CregResult result = { 5, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, FALSE, FALSE }; test_creg_match ("Multi CREG/CGREG", FALSE, reply, data, &result); } @@ -1416,7 +1416,7 @@ test_creg_cgreg_multi2_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 0\r\n\r\n+CREG: 5\r\n"; - const CregResult result = { 0, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_IDLE, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, TRUE, FALSE, FALSE }; test_creg_match ("Multi CREG/CGREG #2", FALSE, reply, data, &result); } @@ -1426,7 +1426,7 @@ test_cgreg2_x220_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 2,1, 81ED, 1A9CEB\r\n"; - const CregResult result = { 1, 0x81ED, 0x1A9CEB, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 4, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x81ED, 0x1A9CEB, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, TRUE, FALSE, FALSE }; /* Tests random spaces in response */ test_creg_match ("Alcatel One-Touch X220D CGREG=2", FALSE, reply, data, &result); @@ -1437,7 +1437,7 @@ test_creg2_s8500_wave_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 2,1,000B,2816, B, C2816\r\n"; - const CregResult result = { 1, 0x000B, 0x2816, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 9, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x000B, 0x2816, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 8, FALSE, FALSE, FALSE }; test_creg_match ("Samsung Wave S8500 CREG=2", FALSE, reply, data, &result); } @@ -1447,7 +1447,7 @@ test_creg2_gobi_weird_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CREG: 2,1, 0 5, 2715\r\n"; - const CregResult result = { 1, 0x0000, 0x2715, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 4, FALSE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0000, 0x2715, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, FALSE, FALSE, FALSE }; test_creg_match ("Qualcomm Gobi 1000 CREG=2", TRUE, reply, data, &result); } @@ -1457,7 +1457,7 @@ test_cgreg2_unsolicited_with_rac (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CGREG: 1,\"1422\",\"00000142\",3,\"00\"\r\n"; - const CregResult result = { 1, 0x1422, 0x0142, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 10, TRUE, FALSE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1422, 0x0142, MM_MODEM_ACCESS_TECHNOLOGY_EDGE, 9, TRUE, FALSE, FALSE }; test_creg_match ("CGREG=2 with RAC", FALSE, reply, data, &result); } @@ -1467,7 +1467,7 @@ test_cereg1_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "+CEREG: 1,3"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 2, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, FALSE, TRUE, FALSE }; test_creg_match ("CEREG=1", TRUE, reply, data, &result); } @@ -1477,7 +1477,7 @@ test_cereg1_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 3\r\n"; - const CregResult result = { 3, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN , 1, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, TRUE, FALSE }; test_creg_match ("CEREG=1", FALSE, reply, data, &result); } @@ -1487,7 +1487,7 @@ test_cereg2_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 2,1, 1F00, 79D903 ,7\r\n"; - const CregResult result = { 1, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 8, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 7, FALSE, TRUE, FALSE }; test_creg_match ("CEREG=2", TRUE, reply, data, &result); } @@ -1497,7 +1497,7 @@ test_cereg2_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 1, 1F00, 79D903 ,7\r\n"; - const CregResult result = { 1, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 6, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 5, FALSE, TRUE, FALSE }; test_creg_match ("CEREG=2", FALSE, reply, data, &result); } @@ -1507,7 +1507,7 @@ test_cereg2_altair_lte_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 1, 2, 0001, 00000100, 7\r\n"; - const CregResult result = { 2, 0x0001, 0x00000100, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 8, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING, 0x0001, 0x00000100, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 7, FALSE, TRUE, FALSE }; test_creg_match ("Altair LTE CEREG=2", FALSE, reply, data, &result); } @@ -1517,7 +1517,7 @@ test_cereg2_altair_lte_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 2, 0001, 00000100, 7\r\n"; - const CregResult result = { 2, 0x0001, 0x00000100, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 6, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING, 0x0001, 0x00000100, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 5, FALSE, TRUE, FALSE }; test_creg_match ("Altair LTE CEREG=2", FALSE, reply, data, &result); } @@ -1527,7 +1527,7 @@ test_cereg2_novatel_lte_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 2,1, 1F00, 20 ,79D903 ,7\r\n"; - const CregResult result = { 1, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 13, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 11, FALSE, TRUE, FALSE }; test_creg_match ("Novatel LTE E362 CEREG=2", TRUE, reply, data, &result); } @@ -1537,7 +1537,7 @@ test_cereg2_novatel_lte_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; const char *reply = "\r\n+CEREG: 1, 1F00, 20 ,79D903 ,7\r\n"; - const CregResult result = { 1, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 12, FALSE, TRUE }; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 10, FALSE, TRUE, FALSE }; test_creg_match ("Novatel LTE E362 CEREG=2", FALSE, reply, data, &result); } @@ -1546,8 +1546,8 @@ static void test_cgreg2_thuraya_solicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; - const char *reply = "+CGREG: 1, \"0426\", \"F0,0F\""; - const CregResult result = { 1, 0x0426, 0x00F0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 11, TRUE, FALSE }; + const char *reply = "+CGREG: 2, 1, \"0426\", \"F00F\""; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0426, 0xF00F, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 3, TRUE, FALSE, FALSE }; test_creg_match ("Thuraya solicited CREG=2", TRUE, reply, data, &result); } @@ -1556,12 +1556,52 @@ static void test_cgreg2_thuraya_unsolicited (void *f, gpointer d) { RegTestData *data = (RegTestData *) d; - const char *reply = "\r\n+CGREG: 1, \"0426\", \"F0,0F\"\r\n"; - const CregResult result = { 1, 0x0426, 0x00F0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 11, TRUE, FALSE }; + const char *reply = "\r\n+CGREG: 1, \"0426\", \"F00F\"\r\n"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x0426, 0xF00F, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 2, TRUE, FALSE, FALSE }; test_creg_match ("Thuraya unsolicited CREG=2", FALSE, reply, data, &result); } +static void +test_c5greg1_solicited (void *f, gpointer d) +{ + RegTestData *data = (RegTestData *) d; + const char *reply = "+C5GREG: 1,3"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 1, FALSE, FALSE, TRUE }; + + test_creg_match ("C5GREG=1", TRUE, reply, data, &result); +} + +static void +test_c5greg1_unsolicited (void *f, gpointer d) +{ + RegTestData *data = (RegTestData *) d; + const char *reply = "\r\n+C5GREG: 3\r\n"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_DENIED, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, FALSE, TRUE }; + + test_creg_match ("C5GREG=1", FALSE, reply, data, &result); +} + +static void +test_c5greg2_solicited (void *f, gpointer d) +{ + RegTestData *data = (RegTestData *) d; + const char *reply = "+C5GREG: 2,1,1F00,79D903,11,6,ABCDEF"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_5GNR, 13, FALSE, FALSE, TRUE }; + + test_creg_match ("C5GREG=2", TRUE, reply, data, &result); +} + +static void +test_c5greg2_unsolicited (void *f, gpointer d) +{ + RegTestData *data = (RegTestData *) d; + const char *reply = "\r\n+C5GREG: 1,1F00,79D903,11,6,ABCDEF\r\n"; + const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0x1F00, 0x79D903, MM_MODEM_ACCESS_TECHNOLOGY_5GNR, 12, FALSE, FALSE, TRUE }; + + test_creg_match ("C5GREG=2", FALSE, reply, data, &result); +} + /*****************************************************************************/ /* Test CSCS responses */ @@ -1911,6 +1951,7 @@ test_devid_item (void *f, gpointer d) g_debug ("%s... ", item->desc); devid = mm_create_device_identifier (item->vid, item->pid, + NULL, item->ati, item->ati1, item->gsn, @@ -1937,7 +1978,7 @@ test_cmer_response (const gchar *str, MM3gppCmerInd inds = MM_3GPP_CMER_IND_NONE; GError *error = NULL; - ret = mm_3gpp_parse_cmer_test_response (str, &modes, &inds, &error); + ret = mm_3gpp_parse_cmer_test_response (str, NULL, &modes, &inds, &error); g_assert_no_error (error); g_assert (ret); @@ -2439,7 +2480,7 @@ test_cgdcont_test_results (const gchar *desc, g_debug ("Testing %s +CGDCONT test response...", desc); - results = mm_3gpp_parse_cgdcont_test_response (reply, &error); + results = mm_3gpp_parse_cgdcont_test_response (reply, NULL, &error); g_assert (results); g_assert_no_error (error); g_assert_cmpuint (g_list_length (results), ==, expected_results_len); @@ -2858,11 +2899,12 @@ test_cid_selection (void) test = &cid_selection_tests[i]; - context_format_list = test->cgdcont_test ? mm_3gpp_parse_cgdcont_test_response (test->cgdcont_test, NULL) : NULL; + context_format_list = test->cgdcont_test ? mm_3gpp_parse_cgdcont_test_response (test->cgdcont_test, NULL, NULL) : NULL; context_list = test->cgdcont_query ? mm_3gpp_parse_cgdcont_read_response (test->cgdcont_query, NULL) : NULL; cid = mm_3gpp_select_best_cid (test->apn, test->ip_family, context_list, context_format_list, + NULL, &cid_reused, &cid_overwritten); g_assert_cmpuint (cid, ==, test->expected_cid); @@ -2899,10 +2941,12 @@ test_cpms_response_cinterion (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing Cinterion +CPMS=? response..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 2); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_ME)); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_MT)); @@ -2927,10 +2971,12 @@ test_cpms_response_huawei_mu609 (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing Huawei MU609 +CPMS=? response..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 1); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_ME)); g_assert_cmpuint (mem2->len, ==, 1); @@ -2951,10 +2997,12 @@ test_cpms_response_nokia_c6 (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing Nokia C6 response..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 0); g_assert_cmpuint (mem2->len, ==, 0); g_assert_cmpuint (mem3->len, ==, 0); @@ -2976,10 +3024,12 @@ test_cpms_response_mixed (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing mixed +CPMS=? response..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 2); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_ME)); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_MT)); @@ -3001,10 +3051,12 @@ test_cpms_response_mixed_spaces (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing mixed +CPMS=? response with spaces..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 2); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_ME)); g_assert (is_storage_supported (mem1, MM_SMS_STORAGE_MT)); @@ -3030,10 +3082,12 @@ test_cpms_response_empty_fields (void *f, gpointer d) GArray *mem1 = NULL; GArray *mem2 = NULL; GArray *mem3 = NULL; + GError *error = NULL; g_debug ("Testing mixed +CPMS=? response..."); - g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3)); + g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3, &error)); + g_assert_no_error (error); g_assert_cmpuint (mem1->len, ==, 0); g_assert_cmpuint (mem2->len, ==, 0); g_assert_cmpuint (mem3->len, ==, 0); @@ -3422,7 +3476,7 @@ test_supported_mode_filter (void *f, gpointer d) /* Only 2G supported */ all = build_mode_all (MM_MODEM_MODE_2G); - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, NULL); g_assert_cmpuint (filtered->len, ==, 1); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE)); g_array_unref (filtered); @@ -3430,7 +3484,7 @@ test_supported_mode_filter (void *f, gpointer d) /* Only 3G supported */ all = build_mode_all (MM_MODEM_MODE_3G); - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, NULL); g_assert_cmpuint (filtered->len, ==, 1); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE)); g_array_unref (filtered); @@ -3438,7 +3492,7 @@ test_supported_mode_filter (void *f, gpointer d) /* 2G and 3G supported */ all = build_mode_all (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, NULL); g_assert_cmpuint (filtered->len, ==, 3); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE)); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE)); @@ -3448,7 +3502,7 @@ test_supported_mode_filter (void *f, gpointer d) /* 3G and 4G supported */ all = build_mode_all (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, NULL); g_assert_cmpuint (filtered->len, ==, 3); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE)); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_4G, MM_MODEM_MODE_NONE)); @@ -3458,7 +3512,7 @@ test_supported_mode_filter (void *f, gpointer d) /* 2G, 3G and 4G supported */ all = build_mode_all (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - filtered = mm_filter_supported_modes (all, combinations); + filtered = mm_filter_supported_modes (all, combinations, NULL); g_assert_cmpuint (filtered->len, ==, 6); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_2G, MM_MODEM_MODE_NONE)); g_assert (find_mode_combination (filtered, MM_MODEM_MODE_3G, MM_MODEM_MODE_NONE)); @@ -3472,98 +3526,6 @@ test_supported_mode_filter (void *f, gpointer d) g_array_unref (combinations); } -/*****************************************************************************/ - -static gboolean -find_capability_combination (GArray *capabilities, - MMModemCapability capability) -{ - guint i; - - for (i = 0; i < capabilities->len; i++) { - MMModemCapability capability_i; - - capability_i = g_array_index (capabilities, MMModemCapability, i); - if (capability_i == capability) - return TRUE; - } - - return FALSE; -} - -static void -test_supported_capability_filter (void *f, gpointer d) -{ - MMModemCapability capability; - GArray *combinations; - GArray *filtered; - - combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), 6); - - /* GSM/UMTS only */ - capability = MM_MODEM_CAPABILITY_GSM_UMTS; - g_array_append_val (combinations, capability); - /* CDMA/EVDO only */ - capability = MM_MODEM_CAPABILITY_CDMA_EVDO; - g_array_append_val (combinations, capability); - /* GSM/UMTS and CDMA/EVDO */ - capability = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_GSM_UMTS); - g_array_append_val (combinations, capability); - /* GSM/UMTS+LTE */ - capability = (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE); - g_array_append_val (combinations, capability); - /* CDMA/EVDO+LTE */ - capability = (MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_LTE); - g_array_append_val (combinations, capability); - /* GSM/UMTS+CDMA/EVDO+LTE */ - capability = (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_CDMA_EVDO | MM_MODEM_CAPABILITY_LTE); - g_array_append_val (combinations, capability); - - /* Only GSM-UMTS supported */ - filtered = mm_filter_supported_capabilities (MM_MODEM_CAPABILITY_GSM_UMTS, combinations); - g_assert_cmpuint (filtered->len, ==, 1); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS)); - g_array_unref (filtered); - - /* Only CDMA-EVDO supported */ - filtered = mm_filter_supported_capabilities (MM_MODEM_CAPABILITY_CDMA_EVDO, combinations); - g_assert_cmpuint (filtered->len, ==, 1); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO)); - g_array_unref (filtered); - - /* GSM-UMTS and CDMA-EVDO supported */ - filtered = mm_filter_supported_capabilities ((MM_MODEM_CAPABILITY_CDMA_EVDO | - MM_MODEM_CAPABILITY_GSM_UMTS), - combinations); - g_assert_cmpuint (filtered->len, ==, 3); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO)); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS)); - g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS | - MM_MODEM_CAPABILITY_CDMA_EVDO))); - g_array_unref (filtered); - - /* GSM-UMTS, CDMA-EVDO and LTE supported */ - filtered = mm_filter_supported_capabilities ((MM_MODEM_CAPABILITY_CDMA_EVDO | - MM_MODEM_CAPABILITY_GSM_UMTS | - MM_MODEM_CAPABILITY_LTE), - combinations); - g_assert_cmpuint (filtered->len, ==, 6); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_CDMA_EVDO)); - g_assert (find_capability_combination (filtered, MM_MODEM_CAPABILITY_GSM_UMTS)); - g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS | - MM_MODEM_CAPABILITY_CDMA_EVDO))); - g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS | - MM_MODEM_CAPABILITY_LTE))); - g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_CDMA_EVDO | - MM_MODEM_CAPABILITY_LTE))); - g_assert (find_capability_combination (filtered, (MM_MODEM_CAPABILITY_GSM_UMTS | - MM_MODEM_CAPABILITY_CDMA_EVDO | - MM_MODEM_CAPABILITY_LTE))); - g_array_unref (filtered); - - g_array_unref (combinations); -} - /*****************************************************************************/ /* Test +CCLK responses */ @@ -4000,6 +3962,7 @@ test_cesq_response_to_signal (void) MMSignal *lte = NULL; success = mm_3gpp_cesq_response_to_signal_info (cesq_response_tests[i].str, + NULL, &gsm, &umts, <e, &error); g_assert_no_error (error); @@ -4222,7 +4185,7 @@ common_test_ccwa_response (const gchar *response, GError *error = NULL; gboolean result; - result = mm_3gpp_parse_ccwa_service_query_response (response, &status, &error); + result = mm_3gpp_parse_ccwa_service_query_response (response, NULL, &status, &error); if (expected_error) { g_assert (!result); @@ -4280,7 +4243,7 @@ common_test_clcc_response (const gchar *str, GList *call_info_list = NULL; GList *l; - result = mm_3gpp_parse_clcc_response (str, &call_info_list, &error); + result = mm_3gpp_parse_clcc_response (str, NULL, &call_info_list, &error); g_assert_no_error (error); g_assert (result); @@ -4468,20 +4431,22 @@ test_parse_uint_list (void) typedef struct { const guint8 bcd[10]; gsize bcd_len; - const gchar *str; + const gchar *low_nybble_first_str; + const gchar *high_nybble_first_str; } BcdToStringTest; static const BcdToStringTest bcd_to_string_tests[] = { - { { }, 0, "" }, - { { 0x01 }, 1, "10" }, - { { 0x1F }, 1, "" }, - { { 0xE2 }, 1, "2" }, - { { 0xD3 }, 1, "3" }, - { { 0xC4 }, 1, "4" }, - { { 0xB1, 0x23 }, 2, "1" }, - { { 0x01, 0x23, 0x45, 0x67 }, 4, "10325476" }, - { { 0x01, 0x23, 0x45, 0xA7 }, 4, "1032547" }, - { { 0x01, 0x23, 0x45, 0x67 }, 2, "1032" }, + { { }, 0, "", "" }, + { { 0x01 }, 1, "10", "01" }, + { { 0x1F }, 1, "", "1" }, + { { 0xE2 }, 1, "2", "" }, + { { 0xD3 }, 1, "3", "" }, + { { 0xC4 }, 1, "4", "" }, + { { 0xB1, 0x23 }, 2, "1", "" }, + { { 0x01, 0x2A }, 2, "10", "012" }, + { { 0x01, 0x23, 0x45, 0x67 }, 4, "10325476", "01234567" }, + { { 0x01, 0x23, 0x45, 0xA7 }, 4, "1032547", "012345" }, + { { 0x01, 0x23, 0x45, 0x67 }, 2, "1032", "0123" }, }; static void @@ -4493,34 +4458,21 @@ test_bcd_to_string (void *f, gpointer d) gchar *str; str = mm_bcd_to_string (bcd_to_string_tests[i].bcd, - bcd_to_string_tests[i].bcd_len); - g_assert_cmpstr (str, ==, bcd_to_string_tests[i].str); + bcd_to_string_tests[i].bcd_len, + TRUE /* low_nybble_first */); + g_assert_cmpstr (str, ==, bcd_to_string_tests[i].low_nybble_first_str); + g_free (str); + + str = mm_bcd_to_string (bcd_to_string_tests[i].bcd, + bcd_to_string_tests[i].bcd_len, + FALSE /* low_nybble_first */); + g_assert_cmpstr (str, ==, bcd_to_string_tests[i].high_nybble_first_str); g_free (str); } } /*****************************************************************************/ -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - #define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (GTestFixtureFunc) t, NULL) int main (int argc, char **argv) @@ -4633,6 +4585,11 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_cereg2_novatel_lte_solicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_cereg2_novatel_lte_unsolicited, reg_data)); + g_test_suite_add (suite, TESTCASE (test_c5greg1_solicited, reg_data)); + g_test_suite_add (suite, TESTCASE (test_c5greg1_unsolicited, reg_data)); + g_test_suite_add (suite, TESTCASE (test_c5greg2_solicited, reg_data)); + g_test_suite_add (suite, TESTCASE (test_c5greg2_unsolicited, reg_data)); + g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, reg_data)); @@ -4718,8 +4675,6 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_supported_mode_filter, NULL)); - g_test_suite_add (suite, TESTCASE (test_supported_capability_filter, NULL)); - g_test_suite_add (suite, TESTCASE (test_cclk_response, NULL)); g_test_suite_add (suite, TESTCASE (test_crsm_response, NULL)); diff --git a/src/tests/test-qcdm-serial-port.c b/src/tests/test-qcdm-serial-port.c index c5233f9c..2a9e1c47 100644 --- a/src/tests/test-qcdm-serial-port.c +++ b/src/tests/test-qcdm-serial-port.c @@ -34,7 +34,7 @@ #include "libqcdm/src/utils.h" #include "libqcdm/src/com.h" #include "libqcdm/src/errors.h" -#include "mm-log.h" +#include "mm-log-test.h" typedef struct { int master; @@ -54,7 +54,7 @@ wait_for_child (TestData *d, guint32 timeout) status = 0; ret = waitpid (d->child, &status, WNOHANG); g_get_current_time (&now); - if (d->child && (now.tv_sec - start.tv_sec > timeout)) { + if (d->child && (now.tv_sec - start.tv_sec > (glong)timeout)) { /* Kill it */ if (g_test_verbose ()) g_message ("Killing running child process %d", d->child); @@ -437,26 +437,6 @@ test_pty_cleanup (TestData *d) } } -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - typedef void (*TCFunc) (TestData *, gconstpointer); #define TESTCASE_PTY(s, t) g_test_add (s, TestData, NULL, (TCFunc)test_pty_create, (TCFunc)t, (TCFunc)test_pty_cleanup); diff --git a/src/tests/test-sms-part-3gpp.c b/src/tests/test-sms-part-3gpp.c index d9152405..db6aa7a0 100644 --- a/src/tests/test-sms-part-3gpp.c +++ b/src/tests/test-sms-part-3gpp.c @@ -24,7 +24,7 @@ #include #include "mm-sms-part-3gpp.h" -#include "mm-log.h" +#include "mm-log-test.h" /********************* PDU PARSER TESTS *********************/ @@ -41,7 +41,7 @@ common_test_part_from_hexpdu (const gchar *hexpdu, MMSmsPart *part; GError *error = NULL; - part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, NULL, &error); g_assert_no_error (error); g_assert (part != NULL); @@ -339,7 +339,7 @@ test_pdu_insufficient_data (void) }; hexpdu = mm_utils_bin2hexstr (pdu, sizeof (pdu)); - part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, NULL, &error); g_assert (part == NULL); /* We don't care for the specific error type */ g_assert (error != NULL); @@ -531,7 +531,7 @@ common_test_create_pdu (const gchar *smsc, MMSmsEncoding encoding = MM_SMS_ENCODING_UNKNOWN; /* Detect best encoding */ - out = mm_sms_part_3gpp_util_split_text (text, &encoding); + out = mm_sms_part_3gpp_util_split_text (text, &encoding, NULL); g_strfreev (out); mm_sms_part_set_text (part, text); mm_sms_part_set_encoding (part, encoding); @@ -544,6 +544,7 @@ common_test_create_pdu (const gchar *smsc, pdu = mm_sms_part_3gpp_get_submit_pdu (part, &len, &msgstart, + NULL, &error); mm_sms_part_free (part); @@ -552,8 +553,7 @@ common_test_create_pdu (const gchar *smsc, g_assert_no_error (error); g_assert (pdu != NULL); - g_assert_cmpuint (len, ==, expected_size); - g_assert_cmpint (memcmp (pdu, expected, len), ==, 0); + g_assert_cmpmem (pdu, len, expected, expected_size); g_assert_cmpint (msgstart, ==, expected_msgstart); g_free (pdu); @@ -719,7 +719,7 @@ common_test_text_split (const gchar *text, MMSmsEncoding out_encoding = MM_SMS_ENCODING_UNKNOWN; guint i; - out = mm_sms_part_3gpp_util_split_text (text, &out_encoding); + out = mm_sms_part_3gpp_util_split_text (text, &out_encoding, NULL); g_assert (out != NULL); g_assert (out_encoding != MM_SMS_ENCODING_UNKNOWN); @@ -734,7 +734,7 @@ common_test_text_split (const gchar *text, } static void -test_text_split_short (void) +test_text_split_short_gsm7 (void) { const gchar *text = "Hello"; const gchar *expected [] = { @@ -748,7 +748,7 @@ test_text_split_short (void) static void test_text_split_short_ucs2 (void) { - const gchar *text = "你好"; + const gchar *text = "你好"; /* (UTF-8) e4 bd a0 e5 a5 bd */ const gchar *expected [] = { "你好", NULL @@ -758,7 +758,19 @@ test_text_split_short_ucs2 (void) } static void -test_text_split_max_single_pdu (void) +test_text_split_short_utf16 (void) +{ + const gchar *text = "😉"; /* U+1F609, winking face */ + const gchar *expected [] = { + "😉", + NULL + }; + + common_test_text_split (text, expected, MM_SMS_ENCODING_UCS2); +} + +static void +test_text_split_max_single_pdu_gsm7 (void) { const gchar *text = "0123456789012345678901234567890123456789" @@ -797,7 +809,23 @@ test_text_split_max_single_pdu_ucs2 (void) } static void -test_text_split_two_pdu (void) +test_text_split_max_single_pdu_utf16 (void) +{ + /* NOTE: this string contains 35 Bhaiksuki characters, each of + * them requiring 4 bytes both in UTF-8 and in UTF-16 (140 bytes + * in total). */ + const gchar *text = + "𑰀𑰁𑰂𑰃𑰄𑰅𑰆𑰇𑰈𑰊𑰋𑰌𑰍𑰎𑰏𑰐𑰑𑰒𑰓𑰔𑰕𑰖𑰗𑰘𑰙𑰚𑰛𑰜𑰝𑰞𑰟𑰠𑰡𑰢𑰣"; + const gchar *expected [] = { + "𑰀𑰁𑰂𑰃𑰄𑰅𑰆𑰇𑰈𑰊𑰋𑰌𑰍𑰎𑰏𑰐𑰑𑰒𑰓𑰔𑰕𑰖𑰗𑰘𑰙𑰚𑰛𑰜𑰝𑰞𑰟𑰠𑰡𑰢𑰣", + NULL + }; + + common_test_text_split (text, expected, MM_SMS_ENCODING_UCS2); +} + +static void +test_text_split_two_pdu_gsm7 (void) { const gchar *text = "0123456789012345678901234567890123456789" @@ -838,28 +866,32 @@ test_text_split_two_pdu_ucs2 (void) common_test_text_split (text, expected, MM_SMS_ENCODING_UCS2); } -/************************************************************/ - -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) +static void +test_text_split_two_pdu_utf16 (void) { - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; + /* NOTE: this string contains 35 Bhaiksuki characters, each of + * them requiring 4 bytes both in UTF-8 and in UTF-16 (140 bytes + * in total) plus one ASCII char (encoded with 1 byte in UTF-8 and + * 2 bytes in UTF-16), making it a total of 142 bytes when in + * UTF-16 (so not fitting in one single PDU) + * + * When split in chunks, the last chunk will hold 2 Bhaiksuki + * characters plus the last ASCII one (9 bytes in UTF-16) so that + * the first chunk contains the leading 33 Bhaiksuki characters + * (132 characters, less than 134) */ + const gchar *text = + "𑰀𑰁𑰂𑰃𑰄𑰅𑰆𑰇𑰈𑰊𑰋𑰌𑰍𑰎𑰏𑰐𑰑𑰒𑰓𑰔𑰕𑰖𑰗𑰘𑰙𑰚𑰛𑰜𑰝𑰞𑰟𑰠𑰡𑰢𑰣a"; + const gchar *expected [] = { + "𑰀𑰁𑰂𑰃𑰄𑰅𑰆𑰇𑰈𑰊𑰋𑰌𑰍𑰎𑰏𑰐𑰑𑰒𑰓𑰔𑰕𑰖𑰗𑰘𑰙𑰚𑰛𑰜𑰝𑰞𑰟𑰠𑰡", + "𑰢𑰣a", + NULL + }; - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); + common_test_text_split (text, expected, MM_SMS_ENCODING_UCS2); } +/************************************************************/ + int main (int argc, char **argv) { setlocale (LC_ALL, ""); @@ -893,12 +925,15 @@ int main (int argc, char **argv) g_test_add_func ("/MM/SMS/3GPP/PDU-Creator/GSM-3", test_create_pdu_gsm_3); g_test_add_func ("/MM/SMS/3GPP/PDU-Creator/GSM-no-validity", test_create_pdu_gsm_no_validity); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/short", test_text_split_short); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/short-UCS2", test_text_split_short_ucs2); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/max-single-pdu", test_text_split_max_single_pdu); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/max-single-pdu-UCS2", test_text_split_max_single_pdu_ucs2); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/two-pdu", test_text_split_two_pdu); - g_test_add_func ("/MM/SMS/3GPP/Text-Split/two-pdu-UCS2", test_text_split_two_pdu_ucs2); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/gsm7/short", test_text_split_short_gsm7); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/ucs2/short", test_text_split_short_ucs2); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/utf16/short", test_text_split_short_utf16); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/gsm7/max-single-pdu", test_text_split_max_single_pdu_gsm7); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/ucs2/max-single-pdu", test_text_split_max_single_pdu_ucs2); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/utf16/max-single-pdu", test_text_split_max_single_pdu_utf16); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/gsm7/two-pdu", test_text_split_two_pdu_gsm7); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/ucs2/two-pdu", test_text_split_two_pdu_ucs2); + g_test_add_func ("/MM/SMS/3GPP/Text-Split/utf16/two-pdu", test_text_split_two_pdu_utf16); return g_test_run (); } diff --git a/src/tests/test-sms-part-cdma.c b/src/tests/test-sms-part-cdma.c index e1559261..eb095f34 100644 --- a/src/tests/test-sms-part-cdma.c +++ b/src/tests/test-sms-part-cdma.c @@ -23,7 +23,7 @@ #include #include "mm-sms-part-cdma.h" -#include "mm-log.h" +#include "mm-log-test.h" /********************* PDU PARSER TESTS *********************/ @@ -38,8 +38,7 @@ common_test_part_from_hexpdu (const gchar *hexpdu, MMSmsPart *part; GError *error = NULL; - mm_dbg (" "); - part = mm_sms_part_cdma_new_from_pdu (0, hexpdu, &error); + part = mm_sms_part_cdma_new_from_pdu (0, hexpdu, NULL, &error); g_assert_no_error (error); g_assert (part != NULL); @@ -88,8 +87,7 @@ common_test_invalid_part_from_hexpdu (const gchar *hexpdu) MMSmsPart *part; GError *error = NULL; - mm_dbg (" "); - part = mm_sms_part_cdma_new_from_pdu (0, hexpdu, &error); + part = mm_sms_part_cdma_new_from_pdu (0, hexpdu, NULL, &error); g_assert (part == NULL); /* We don't care for the specific error type */ g_assert (error != NULL); @@ -396,7 +394,7 @@ common_test_create_pdu (MMSmsCdmaTeleserviceId teleservice_id, mm_sms_part_take_data (part, data_bytearray); } - pdu = mm_sms_part_cdma_get_submit_pdu (part, &len, &error); + pdu = mm_sms_part_cdma_get_submit_pdu (part, &len, NULL, &error); mm_sms_part_free (part); if (g_test_verbose ()) @@ -502,28 +500,46 @@ test_create_pdu_text_unicode_encoding (void) expected, sizeof (expected)); } -/************************************************************/ - -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) +static void +test_create_parse_pdu_text_ascii_encoding (void) { - va_list args; - gchar *msg; +#define MAX_TEXT_LEN 100 + guint i; + gchar text[MAX_TEXT_LEN + 1]; + + memset (text, 0, sizeof (text)); + + for (i = 0; i < MAX_TEXT_LEN; i++) { + MMSmsPart *part; + guint8 *pdu; + guint len = 0; + GError *error = NULL; - if (!g_test_verbose ()) - return; + text[i]='A'; - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); + part = mm_sms_part_new (0, MM_SMS_PDU_TYPE_CDMA_SUBMIT); + mm_sms_part_set_cdma_teleservice_id (part, MM_SMS_CDMA_TELESERVICE_ID_WMT); + mm_sms_part_set_number (part, "123456789"); + mm_sms_part_set_text (part, text); + pdu = mm_sms_part_cdma_get_submit_pdu (part, &len, NULL, &error); + g_assert_no_error (error); + g_assert (pdu != NULL); + mm_sms_part_free (part); + + part = mm_sms_part_cdma_new_from_binary_pdu (0, pdu, len, NULL, &error); + g_assert_no_error (error); + g_assert (part != NULL); + g_assert_cmpuint (MM_SMS_CDMA_TELESERVICE_ID_WMT, ==, mm_sms_part_get_cdma_teleservice_id (part)); + g_assert_cmpstr ("123456789", ==, mm_sms_part_get_number (part)); + g_assert_cmpstr (text, ==, mm_sms_part_get_text (part)); + mm_sms_part_free (part); + + g_free (pdu); + } } +/************************************************************/ + int main (int argc, char **argv) { setlocale (LC_ALL, ""); @@ -542,5 +558,7 @@ int main (int argc, char **argv) g_test_add_func ("/MM/SMS/CDMA/PDU-Creator/latin-encoding", test_create_pdu_text_latin_encoding); g_test_add_func ("/MM/SMS/CDMA/PDU-Creator/unicode-encoding", test_create_pdu_text_unicode_encoding); + g_test_add_func ("/MM/SMS/CDMA/PDU-Creator-Parser/ascii-encoding", test_create_parse_pdu_text_ascii_encoding); + return g_test_run (); } diff --git a/src/tests/test-udev-rules.c b/src/tests/test-udev-rules.c index 3398e419..cdc962e0 100644 --- a/src/tests/test-udev-rules.c +++ b/src/tests/test-udev-rules.c @@ -23,7 +23,7 @@ #include #include "mm-kernel-device-generic-rules.h" -#include "mm-log.h" +#include "mm-log-test.h" /************************************************************/ @@ -43,26 +43,6 @@ test_load_cleanup_core (void) /************************************************************/ -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!g_test_verbose ()) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - int main (int argc, char **argv) { setlocale (LC_ALL, ""); diff --git a/test/mmrules.c b/test/mmrules.c index 17976d25..3538f44d 100644 --- a/test/mmrules.c +++ b/test/mmrules.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #define PROGRAM_NAME "mmrules" @@ -50,26 +50,6 @@ static GOptionEntry main_entries[] = { { NULL } }; -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!verbose_flag) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - static void print_version_and_exit (void) { diff --git a/test/mmsmspdu.c b/test/mmsmspdu.c index c5e9693d..3a56ffc5 100644 --- a/test/mmsmspdu.c +++ b/test/mmsmspdu.c @@ -26,7 +26,7 @@ #include #define _LIBMM_INSIDE_MM #include -#include "mm-log.h" +#include "mm-log-test.h" #include "mm-sms-part-3gpp.h" #define PROGRAM_NAME "mmsmspdu" @@ -163,26 +163,6 @@ show_part_info (MMSmsPart *part) } } -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!verbose_flag) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - static void print_version_and_exit (void) { @@ -219,7 +199,7 @@ int main (int argc, char **argv) exit (EXIT_FAILURE); } - part = mm_sms_part_3gpp_new_from_pdu (0, pdu, &error); + part = mm_sms_part_3gpp_new_from_pdu (0, pdu, NULL, &error); if (!part) { g_printerr ("error: couldn't parse PDU: %s\n", error->message); exit (EXIT_FAILURE); diff --git a/test/mmtty.c b/test/mmtty.c index 966225c7..28df6285 100644 --- a/test/mmtty.c +++ b/test/mmtty.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -83,26 +83,6 @@ signals_handler (int signum) } } -void -_mm_log (const char *loc, - const char *func, - guint32 level, - const char *fmt, - ...) -{ - va_list args; - gchar *msg; - - if (!verbose_flag) - return; - - va_start (args, fmt); - msg = g_strdup_vprintf (fmt, args); - va_end (args); - g_print ("%s\n", msg); - g_free (msg); -} - static void print_version_and_exit (void) { diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..af87c73b --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = . tests + +EXTRA_DIST = test-modemmanager-service.py diff --git a/tools/test-modemmanager-service.py b/tools/test-modemmanager-service.py new file mode 100755 index 00000000..2ca18b9f --- /dev/null +++ b/tools/test-modemmanager-service.py @@ -0,0 +1,490 @@ +#!/usr/bin/env python3 +# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +from __future__ import print_function + +import gi +gi.require_version('ModemManager', '1.0') +from gi.repository import GLib, ModemManager +import argparse +import sys +import dbus +import dbus.service +import dbus.mainloop.glib +import random +import collections + +mainloop = GLib.MainLoop() + +######################################################### +IFACE_DBUS = 'org.freedesktop.DBus' + +class UnknownInterfaceException(dbus.DBusException): + def __init__(self, *args, **kwargs): + self._dbus_error_name = '{}.UnknownInterface'.format(IFACE_DBUS) + super().__init__(*args, **kwargs) + +class UnknownPropertyException(dbus.DBusException): + def __init__(self, *args, **kwargs): + self._dbus_error_name = '{}.UnknownProperty'.format(IFACE_DBUS) + super().__init__(*args, **kwargs) + +class MobileEquipmentException(dbus.DBusException): + _dbus_error_name = '{}.Error.MobileEquipment'.format(IFACE_DBUS) + def __init__(self, *args, **kwargs): + equipment_error_num = kwargs.pop('equipment_error', None) + if equipment_error_num is not None: + equipment_error_except = ModemManager.MobileEquipmentError(equipment_error_num) + self._dbus_error_name = '{}.Error.MobileEquipment.{}'.format(IFACE_DBUS, equipment_error_except.value_nick) + super().__init__(*args, **kwargs) + +def log(msg): + if log_file: + try: + log_file.write(msg + "\n") + log_file.flush() + except Exception: + pass + else: + print(msg) + +def to_path_array(src): + array = dbus.Array([], signature=dbus.Signature('o')) + for o in src: + array.append(to_path(o)) + return array + +def to_path(src): + if src: + return dbus.ObjectPath(src.path) + return dbus.ObjectPath("/") + +class ExportedObj(dbus.service.Object): + + DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'get_props_func', 'set_props_func', 'prop_changed_func']) + + def __init__(self, bus, object_path): + super(ExportedObj, self).__init__(bus, object_path) + self._bus = bus + self.path = object_path + self.__ensure_dbus_ifaces() + log("Will add object with path '%s' to object manager" % object_path) + object_manager.add_object(self) + + def __ensure_dbus_ifaces(self): + if not hasattr(self, '_ExportedObj__dbus_ifaces'): + self.__dbus_ifaces = {} + + def add_dbus_interface(self, dbus_iface, get_props_func, set_props_func, prop_changed_func): + self.__ensure_dbus_ifaces() + self.__dbus_ifaces[dbus_iface] = ExportedObj.DBusInterface(dbus_iface, get_props_func, set_props_func, prop_changed_func) + + def __dbus_interface_get(self, dbus_iface): + if dbus_iface not in self.__dbus_ifaces: + raise UnknownInterfaceException() + return self.__dbus_ifaces[dbus_iface] + + def _dbus_property_get(self, dbus_iface, propname=None): + props = self.__dbus_interface_get(dbus_iface).get_props_func() + if propname is None: + return props + if propname not in props: + raise UnknownPropertyException() + return props[propname] + + def _dbus_property_set(self, dbus_iface, propname, value): + props = self.__dbus_interface_get(dbus_iface).get_props_func() + + try: + if props[propname] == value: + return + except KeyError: + raise UnknownPropertyException() + + if self.__dbus_interface_get(dbus_iface).set_props_func is not None: + self.__dbus_interface_get(dbus_iface).set_props_func(propname, value) + self._dbus_property_notify(dbus_iface, propname) + + def _dbus_property_notify(self, dbus_iface, propname): + prop = self._dbus_property_get(dbus_iface, propname) + self.__dbus_interface_get(dbus_iface).prop_changed_func(self, {propname: prop}) + ExportedObj.PropertiesChanged(self, dbus_iface, {propname: prop}, []) + + @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as') + def PropertiesChanged(self, iface, changed, invalidated): + pass + + @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') + def GetAll(self, dbus_iface): + return self._dbus_property_get(dbus_iface) + + @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') + def Get(self, dbus_iface, name): + return self._dbus_property_get(dbus_iface, name) + + @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ssv', out_signature='') + def Set(self, dbus_iface, name, value): + return self._dbus_property_set(dbus_iface, name, value) + + def get_managed_ifaces(self): + my_ifaces = {} + for iface in self.__dbus_ifaces: + my_ifaces[iface] = self.__dbus_ifaces[iface].get_props_func() + return self.path, my_ifaces + + +################################################################### +IFACE_SIM = 'org.freedesktop.ModemManager1.Sim' + +PS_IMSI = "Imsi" +PS_OPERATOR_IDENTIFIER = "OperatorIdentifier" +PS_OPERATOR_NAME = "OperatorName" +PS_SIM_IDENTIFIER = "SimIdentifier" + +class Sim(ExportedObj): + def __init__(self, bus, counter, iccid, modem): + object_path = "/org/freedesktop/ModemManager1/SIM/%d" % counter + self.iccid = iccid + self.modem = modem + + self.add_dbus_interface(IFACE_SIM, self.__get_props, None, Sim.PropertiesChanged) + super(Sim, self).__init__(bus, object_path) + + # Properties interface + def __get_props(self): + props = {} + props[PS_IMSI] = "Imsi_1" + props[PS_OPERATOR_IDENTIFIER] = "OperatorIdentifier_1" + props[PS_OPERATOR_NAME] = "OperatorName_1" + props[PS_SIM_IDENTIFIER] = self.iccid + return props + + # methods + @dbus.service.method(dbus_interface=IFACE_SIM, in_signature='ss', out_signature='') + def ChangePin(self, old_pin, new_pin): + pass + + @dbus.service.method(dbus_interface=IFACE_SIM, in_signature='sb', out_signature='ao') + def EnablePin(self, pin, enabled): + pass + + @dbus.service.method(dbus_interface=IFACE_SIM, in_signature='s', out_signature='') + def SendPin(self, pin): + if self.modem.equipmentError is not None: + raise MobileEquipmentException(equipment_error=self.modem.equipmentError) + self.modem.unlock() + + @dbus.service.method(dbus_interface=IFACE_SIM, in_signature='ss', out_signature='') + def SendPuk(self, puk, pin): + self.modem.unlock() + + # signals + @dbus.service.signal(IFACE_SIM, signature='a{sv}') + def PropertiesChanged(self, changed): + pass + + +################################################################### +IFACE_MODEM = 'org.freedesktop.ModemManager1.Modem' + +PM_SIM = "Sim" +PM_BEARERS = "Bearers" +PM_SUPPORTED_CAPABILITIES = "SupportedCapabilities" +PM_CURRENT_CAPABILITIES = "CurrentCapabilities" +PM_MAX_BEARERS = "MaxBearers" +PM_MAX_ACTIVE_BEARERS = "MaxActiveBearers" +PM_MANUFACTURER = "Manufacturer" +PM_MODEL = "Model" +PM_REVISION = "Revision" +PM_DEVICE_IDENTIFIER = "DeviceIdentifier" +PM_DEVICE = "Device" +PM_DRIVERS = "Drivers" +PM_PLUGIN = "Plugin" +PM_PRIMARY_PORT = "PrimaryPort" +PM_PORTS = "Ports" +PM_EQUIPMENT_IDENTIFIER = "EquipmentIdentifier" +PM_UNLOCK_REQUIRED = "UnlockRequired" +PM_UNLOCK_RETRIES = "UnlockRetries" +PM_STATE = "State" +PM_STATE_FAILED_REASON = "StateFailedReason" +PM_ACCESS_TECHNOLOGIES = "AccessTechnologies" +PM_SIGNAL_QUALITY = "SignalQuality" +PM_OWN_NUMBERS = "OwnNumbers" +PM_POWER_STATE = "PowerState" +PM_SUPPORTED_MODES = "SupportedModes" +PM_CURRENT_MODES = "CurrentModes" +PM_SUPPORTED_BANDS = "SupportedBands" +PM_CURRENT_BANDS = "CurrentBands" +PM_SUPPORTED_IP_FAMILIES = "SupportedIpFamilies" + +class Modem(ExportedObj): + counter = 0 + + def __init__(self, bus, add_sim, iccid): + object_path = "/org/freedesktop/ModemManager1/Modem/%d" % Modem.counter + self.sim_object = None + if add_sim: + self.sim_object = Sim(bus, Modem.counter, iccid, self) + self.sim_path = to_path(self.sim_object) + self.equipmentError = None + self.reset_status = True + self.reset_status_clear = False + + self.__props = self.__init_default_props() + + Modem.counter = Modem.counter + 1 + + self.add_dbus_interface(IFACE_MODEM, self.__get_props, self.__set_prop, Modem.PropertiesChanged) + super(Modem, self).__init__(bus, object_path) + + # Properties interface + def __init_default_props(self): + props = {} + props[PM_SIM] = dbus.ObjectPath(self.sim_path) + props[PM_DEVICE] = dbus.String("/fake/path") + props[PM_UNLOCK_REQUIRED] = dbus.UInt32(ModemManager.ModemLock.NONE) + props[PM_STATE] = dbus.Int32(ModemManager.ModemState.UNKNOWN) + props[PM_STATE_FAILED_REASON] = dbus.UInt32(ModemManager.ModemStateFailedReason.UNKNOWN) + # Not already used properties + #props[PM_BEARERS] = None + #props[PM_SUPPORTED_CAPABILITIES] = None + #props[PM_CURRENT_CAPABILITIES] = None + #props[PM_MAX_BEARERS] = None + #props[PM_MAX_ACTIVE_BEARERS] = None + #props[PM_MANUFACTURER] = None + #props[PM_MODEL] = None + #props[PM_REVISION] = None + #props[PM_DEVICE_IDENTIFIER] = None + #props[PM_DRIVERS] = None + #props[PM_PLUGIN] = None + #props[PM_PRIMARY_PORT] = None + #props[PM_PORTS] = None + #props[PM_EQUIPMENT_IDENTIFIER] = None + #props[PM_UNLOCK_RETRIES] = dbus.UInt32(0) + #props[PM_ACCESS_TECHNOLOGIES] = None + #props[PM_SIGNAL_QUALITY] = None + #props[PM_OWN_NUMBERS] = None + #props[PM_POWER_STATE] = None + #props[PM_SUPPORTED_MODES] = None + #props[PM_CURRENT_MODES] = None + #props[PM_SUPPORTED_BANDS] = None + #props[PM_CURRENT_BANDS] = None + #props[PM_SUPPORTED_IP_FAMILIES] = None + return props + + def __get_props(self): + return self.__props + + def __set_prop(self, name, value): + try: + self.__props[name] = value + except KeyError: + pass + + def unlock(self): + self._dbus_property_set(IFACE_MODEM, PM_UNLOCK_REQUIRED , dbus.UInt32(ModemManager.ModemLock.NONE)) + + # methods + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='b', out_signature='') + def Enable(self, enable): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='', out_signature='ao') + def ListBearers(self): + return None + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='a{sv}', out_signature='o') + def CreateBearer(self, properties): + return None + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='o', out_signature='') + def DeleteBearer(self, bearer): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='', out_signature='') + def Reset(self): + if not self.reset_status: + if self.reset_status_clear: + self.reset_status = True + self.reset_status_clear = False + + raise Exception("Fake reset exception") + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='s', out_signature='') + def FactoryReset(self, code): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='u', out_signature='') + def SetPowerState(self, state): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='u', out_signature='') + def SetCurrentCapabilities(self, capabilites): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='(uu)', out_signature='') + def SetCurrentModes(self, modes): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='au', out_signature='') + def SetCurrentBands(self, bands): + pass + + @dbus.service.method(dbus_interface=IFACE_MODEM, in_signature='su', out_signature='s') + def Command(self, cmd, timeout): + return None + + # signals + @dbus.service.signal(IFACE_MODEM, signature='a{sv}') + def PropertiesChanged(self, changed): + pass + + @dbus.service.signal(IFACE_MODEM, signature='iiu') + def StateChanged(self, old_state, new_state, reason): + pass + + +################################################################### +IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' + +PATH_OBJECT_MANAGER = '/org/freedesktop/ModemManager1' + +IFACE_TEST = 'org.freedesktop.ModemManager1.LibmmGlibTest' +IFACE_MM = 'org.freedesktop.ModemManager1' + +class ObjectManager(dbus.service.Object): + def __init__(self, bus, object_path): + super(ObjectManager, self).__init__(bus, object_path) + self.objs = [] + self.bus = bus + self.modem = None + + @dbus.service.method(dbus_interface=IFACE_OBJECT_MANAGER, + in_signature='', out_signature='a{oa{sa{sv}}}', + sender_keyword='sender') + def GetManagedObjects(self, sender=None): + managed_objects = {} + for obj in self.objs: + name, ifaces = obj.get_managed_ifaces() + managed_objects[name] = ifaces + return managed_objects + + def add_object(self, obj): + self.objs.append(obj) + name, ifaces = obj.get_managed_ifaces() + self.InterfacesAdded(name, ifaces) + + def remove_object(self, obj): + self.objs.remove(obj) + name, ifaces = obj.get_managed_ifaces() + self.InterfacesRemoved(name, ifaces.keys()) + + @dbus.service.signal(IFACE_OBJECT_MANAGER, signature='oa{sa{sv}}') + def InterfacesAdded(self, name, ifaces): + pass + + @dbus.service.signal(IFACE_OBJECT_MANAGER, signature='oas') + def InterfacesRemoved(self, name, ifaces): + pass + + # ModemManager methods + @dbus.service.method(dbus_interface=IFACE_MM, in_signature='', out_signature='') + def ScanDevices(self): + pass + + @dbus.service.method(dbus_interface=IFACE_MM, in_signature='s', out_signature='') + def SetLogging(self, logging): + pass + + # Testing methods + @dbus.service.method(IFACE_TEST, in_signature='', out_signature='') + def Quit(self): + mainloop.quit() + + @dbus.service.method(IFACE_TEST, in_signature='bs', out_signature='o') + def AddModem(self, add_sim, iccid): + self.modem = Modem(self.bus, add_sim, iccid) + return dbus.ObjectPath(self.modem.path) + + @dbus.service.method(IFACE_TEST, in_signature='iiu', out_signature='') + def EmitStateChanged(self, old_state, new_state, reason): + if self.modem is not None: + self.modem.StateChanged(old_state, new_state, reason) + + @dbus.service.method(IFACE_TEST, in_signature='ub', out_signature='') + def SetMobileEquipmentError(self, error, clear): + if self.modem is not None: + if clear: + self.modem.equipmentError = None + else: + self.modem.equipmentError = error + + @dbus.service.method(IFACE_TEST, in_signature='bb', out_signature='') + def SetResetStatus(self, status, clear): + if self.modem is not None: + self.modem.reset_status = status + self.modem.reset_status_clear = clear + + @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='', out_signature='') + def Restart(self): + bus.release_name("org.freedesktop.ModemManager1") + bus.request_name("org.freedesktop.ModemManager1") + +################################################################### +def stdin_cb(io, condition): + mainloop.quit() + +def quit_cb(user_data): + mainloop.quit() + +def main(): + parser = argparse.ArgumentParser(description="ModemManager dbus interface stub utility") + parser.add_argument("-f", "--log-file", help="Path of a file to log things into") + + cfg = parser.parse_args() + + global log_file + + if cfg.log_file: + try: + log_file = open(cfg.log_file, "w") + except Exception: + log_file = None + else: + log_file = None + + log("Starting mainloop") + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + random.seed() + + global object_manager, bus + + bus = dbus.SessionBus() + log("Creating object manager for /org/freedesktop/ModemManager1") + object_manager = ObjectManager(bus, "/org/freedesktop/ModemManager1") + + log("Requesting name org.freedesktop.ModemManager1") + if not bus.request_name("org.freedesktop.ModemManager1"): + log("Unable to acquire the DBus name") + sys.exit(1) + + # Watch stdin; if it closes, assume our parent has crashed, and exit + id1 = GLib.io_add_watch(0, GLib.IOCondition.HUP, stdin_cb) + + log("Starting the main loop") + try: + mainloop.run() + except (Exception, KeyboardInterrupt): + pass + + GLib.source_remove(id1) + + log("Ending the stub") + if log_file: + log_file.close() + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/tools/tests/Makefile.am b/tools/tests/Makefile.am new file mode 100644 index 00000000..f84a8fec --- /dev/null +++ b/tools/tests/Makefile.am @@ -0,0 +1,49 @@ +include $(top_srcdir)/gtester.make + +################################################################################ +# common +################################################################################ + +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + $(MM_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -I$(top_srcdir)/libmm-glib \ + -I${top_srcdir}/libmm-glib/generated \ + -I${top_builddir}/libmm-glib/generated \ + $(NULL) + +LDADD = \ + $(top_builddir)/libmm-glib/libmm-glib.la \ + $(NULL) + +AM_LDFLAGS = \ + $(WARN_LDFLAGS) \ + $(MM_LIBS) \ + $(MM_LDFLAGS) \ + $(NULL) + +noinst_PROGRAMS = test-stub +test_stub_CPPFLAGS = \ + -DTEST_SERVICES=\""$(abs_top_builddir)/tools/tests/services"\" \ + $(NULL) + +# only run the test if introspection was enabled +if HAVE_INTROSPECTION +TEST_PROGS += $(noinst_PROGRAMS) +endif + +test-wrapper.sh: test-wrapper.sh.in + @sed \ + -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \ + -e 's|@abs_top_srcdir[@]|$(abs_top_srcdir)|g' \ + $< >$@ + @chmod +x $@ + +BUILT_SOURCES = test-wrapper.sh +CLEANFILES = test-wrapper.sh + +EXTRA_DIST += test-wrapper.sh.in services/org.freedesktop.ModemManager1.service.in diff --git a/tools/tests/services/org.freedesktop.ModemManager1.service.in b/tools/tests/services/org.freedesktop.ModemManager1.service.in new file mode 100644 index 00000000..f6113d1f --- /dev/null +++ b/tools/tests/services/org.freedesktop.ModemManager1.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.ModemManager1 +Exec=@abs_top_builddir@/tools/tests/test-wrapper.sh diff --git a/tools/tests/test-stub.c b/tools/tests/test-stub.c new file mode 100644 index 00000000..b88b2a34 --- /dev/null +++ b/tools/tests/test-stub.c @@ -0,0 +1,459 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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: + * + * Copyright (C) 2020 Frederic Martinsons + */ + +#include +#include +#include +#include +#include +#define MM_LOG_NO_OBJECT +#include + +#define MM_TEST_IFACE_NAME "org.freedesktop.ModemManager1.LibmmGlibTest" + +typedef struct { + GMainLoop *loop; + MMManager *mm_manager; + GDBusConnection *gdbus_connection; + GDBusProxy *mm_proxy; + GDBusProxy *mm_modem_prop_proxy; + GTestDBus *test_bus; + gchar *modem_object_path; + guint timeout_id; + MMSim *sim; + gboolean pin_error; +} TestData; + +static void +setup (TestData **ptdata, + gconstpointer data) +{ + GError *error = NULL; + TestData *tdata = NULL; + + tdata = (TestData *)g_malloc0 (sizeof(TestData)); + *ptdata = tdata; + + tdata->loop = g_main_loop_new (NULL, FALSE); + g_assert_nonnull (tdata->loop); + + tdata->test_bus = g_test_dbus_new (G_TEST_DBUS_NONE); + g_assert_nonnull (tdata->test_bus); + + g_test_dbus_add_service_dir (tdata->test_bus, TEST_SERVICES); + g_test_dbus_up (tdata->test_bus); + + /* Grab a proxy to the fake NM service to trigger tests */ + tdata->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + MM_DBUS_SERVICE, + MM_DBUS_PATH, + MM_TEST_IFACE_NAME, + NULL, &error); + g_assert_no_error (error); + + tdata->gdbus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + g_assert_no_error (error); + + tdata->mm_manager = mm_manager_new_sync (tdata->gdbus_connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + NULL, + &error); + g_assert_no_error (error); + g_assert_nonnull (tdata->mm_manager); +} + +static void +teardown (TestData **ptdata, + gconstpointer data) +{ + TestData *tdata = NULL; + + tdata = *ptdata; + g_clear_object (&tdata->mm_modem_prop_proxy); + g_clear_object (&tdata->mm_proxy); + g_clear_object (&tdata->mm_manager); + g_clear_object (&tdata->gdbus_connection); + g_test_dbus_down (tdata->test_bus); + g_clear_object (&tdata->test_bus); + g_main_loop_unref (tdata->loop); + g_free (tdata); +} + +static gboolean +loop_timeout_cb (gpointer user_data) +{ + mm_err ("Timeout has elapsed"); + g_assert_not_reached (); + return G_SOURCE_REMOVE; +} + +static void +run_loop_for_ms (TestData *tdata, + guint32 timeout) +{ + mm_info ("Run loop for %u ms", timeout); + tdata->timeout_id = g_timeout_add (timeout, loop_timeout_cb, tdata); + g_main_loop_run (tdata->loop); +} + +static void +stop_loop (TestData *tdata) +{ + if (tdata->timeout_id) { + g_source_remove (tdata->timeout_id); + tdata->timeout_id = 0; + } + mm_info ("Stop the loop"); + g_main_loop_quit (tdata->loop); +} + +static void +add_modem_completion_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + GVariant *dbus_return = NULL; + GVariant *obj_path_variant = NULL; + TestData *tdata = NULL; + + tdata = (TestData*)user_data; + + mm_info ("AddModem DBus call completed"); + dbus_return = g_dbus_proxy_call_finish (tdata->mm_proxy, res, &error); + g_assert_no_error (error); + g_assert_nonnull (dbus_return); + g_assert_cmpstr (g_variant_get_type_string (dbus_return), == , "(o)"); + + obj_path_variant = g_variant_get_child_value (dbus_return, 0); + tdata->modem_object_path = g_variant_dup_string (obj_path_variant, NULL); + + g_assert_null (tdata->mm_modem_prop_proxy); + tdata->mm_modem_prop_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + MM_DBUS_SERVICE, + tdata->modem_object_path, + "org.freedesktop.DBus.Properties", + NULL, &error); + + g_assert_no_error (error); + g_assert_nonnull (tdata->mm_modem_prop_proxy); + + g_variant_unref (dbus_return); + g_variant_unref (obj_path_variant); + + stop_loop (tdata); +} + +static gchar* +add_modem (TestData *tdata, + gboolean add_sim, + const gchar *iccid) +{ + g_dbus_proxy_call (tdata->mm_proxy, + "AddModem", + g_variant_new ("(bs)", add_sim, iccid), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 1000, + NULL, + add_modem_completion_cb, + tdata); + + run_loop_for_ms (tdata, 1000); + return tdata->modem_object_path; +} + +static void +emit_state_changed_completion_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + GVariant *dbus_return = NULL; + TestData *tdata = NULL; + + tdata = (TestData*)user_data; + + mm_info ("EmitStateChanged DBus call completed"); + dbus_return = g_dbus_proxy_call_finish (tdata->mm_proxy, res, &error); + g_assert_no_error (error); + g_assert_nonnull (dbus_return); + g_variant_unref (dbus_return); + + stop_loop (tdata); +} + +static void +set_modem_state (TestData *tdata, + MMModemState state, + MMModemStateFailedReason reason) +{ + GError *error = NULL; + GVariant *ret = NULL; + GVariant *old_state_variant = NULL; + gint old_state = 0; + + g_assert_nonnull (tdata->mm_modem_prop_proxy); + + /* Get current state */ + ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", + MM_DBUS_INTERFACE_MODEM, + MM_MODEM_PROPERTY_STATE), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + &error); + g_assert_no_error (error); + g_variant_get (ret, "(v)", &old_state_variant); + old_state = g_variant_get_int32 (old_state_variant); + g_variant_unref (ret); + g_variant_unref (old_state_variant); + + ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + MM_DBUS_INTERFACE_MODEM, + MM_MODEM_PROPERTY_STATE, + g_variant_new_int32 (state)), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + &error); + g_assert_no_error (error); + g_variant_unref (ret); + + ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + MM_DBUS_INTERFACE_MODEM, + MM_MODEM_PROPERTY_STATEFAILEDREASON, + g_variant_new_uint32 (reason)), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + &error); + + g_assert_no_error (error); + g_variant_unref (ret); + + /* Emit state change signal */ + g_dbus_proxy_call (tdata->mm_proxy, + "EmitStateChanged", + g_variant_new ("(iiu)", old_state, state, reason), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 1000, + NULL, + emit_state_changed_completion_cb, + tdata); + + run_loop_for_ms (tdata, 1000); +} + +static void +set_modem_unlock_completion_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + GVariant *dbus_return = NULL; + TestData *tdata = NULL; + + tdata = (TestData*)user_data; + + mm_info ("org.freedesktop.DBus.Properties.Set DBus call completed"); + dbus_return = g_dbus_proxy_call_finish (tdata->mm_modem_prop_proxy, res, &error); + g_assert_no_error (error); + g_assert_nonnull (dbus_return); + g_variant_unref (dbus_return); + + stop_loop (tdata); +} + +static void +set_modem_unlock (TestData *tdata, + MMModemLock lock_state) +{ + g_assert_nonnull (tdata->mm_modem_prop_proxy); + + g_dbus_proxy_call (tdata->mm_modem_prop_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + MM_DBUS_INTERFACE_MODEM, + MM_MODEM_PROPERTY_UNLOCKREQUIRED, + g_variant_new_uint32 (lock_state)), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 1000, + NULL, + set_modem_unlock_completion_cb, + tdata); + + run_loop_for_ms (tdata, 1000); +} + +static void +set_modem_equipment_error (TestData *tdata, + MMMobileEquipmentError equipmentError, + gboolean clear) +{ + GError *error = NULL; + GVariant *ret = NULL; + + ret = g_dbus_proxy_call_sync (tdata->mm_proxy, + "SetMobileEquipmentError", + g_variant_new ("(ub)", equipmentError, clear), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + NULL, + &error); + g_assert_no_error (error); + g_variant_unref (ret); +} + +static void +test_modem_interface (TestData **ptdata, + gconstpointer data) +{ + TestData *tdata = NULL; + GDBusObject *modem_object = NULL; + MMModem *mm_modem = NULL; + g_autofree gchar *modem_path = NULL; + + tdata = *ptdata; + /* Add a modem object (with no sim attached) */ + modem_path = add_modem (tdata, FALSE, ""); + modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (tdata->mm_manager), modem_path); + g_assert_nonnull (modem_object); + + mm_modem = mm_object_get_modem (MM_OBJECT (modem_object)); + g_clear_object (&modem_object); + + /* Check the modem states */ + g_assert_cmpuint (mm_modem_get_state (mm_modem), ==, MM_MODEM_STATE_UNKNOWN); + g_assert_cmpuint (mm_modem_get_state_failed_reason (mm_modem), ==, MM_MODEM_STATE_FAILED_REASON_UNKNOWN); + + /* Set new state and check that it is propagated */ + set_modem_state (tdata, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_FAILED_REASON_NONE); + + g_assert_cmpuint (mm_modem_get_state (mm_modem), ==, MM_MODEM_STATE_REGISTERED); + g_assert_cmpuint (mm_modem_get_state_failed_reason (mm_modem), ==, MM_MODEM_STATE_FAILED_REASON_NONE); + + g_clear_object (&mm_modem); +} + +static void +mm_sim_send_pin_completion_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + gboolean ret = FALSE; + TestData *tdata = NULL; + + tdata = (TestData*)user_data; + + mm_info("SendPin DBus method call completed"); + ret = mm_sim_send_pin_finish (tdata->sim, res, &error); + if (tdata->pin_error) { + g_assert_nonnull (error); + g_assert_false (ret); + g_clear_error (&error); + } else { + g_assert_no_error (error); + g_assert_true (ret); + } + stop_loop (tdata); +} + +static void +test_sim_interface (TestData **ptdata, + gconstpointer data) +{ + TestData *tdata = NULL; + GDBusObject *modem_object = NULL; + MMModem *mm_modem = NULL; + GError *error = NULL; + g_autofree gchar *modem_path = NULL; + + tdata = *ptdata; + /* Add a modem with a sim object */ + modem_path = add_modem (tdata, TRUE, "89330122503000800750"); + modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (tdata->mm_manager), modem_path); + g_assert_nonnull (modem_object); + mm_modem = mm_object_get_modem (MM_OBJECT (modem_object)); + g_clear_object (&modem_object); + + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE); + /* Lock the modem */ + set_modem_unlock (tdata, MM_MODEM_LOCK_SIM_PIN); + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN); + + tdata->sim = mm_modem_get_sim_sync (mm_modem, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (tdata->sim); + g_assert_cmpstr (mm_sim_get_identifier(tdata->sim), ==, "89330122503000800750"); + + /* Send a pin code */ + tdata->pin_error = FALSE; + mm_sim_send_pin (tdata->sim, "1234", NULL, mm_sim_send_pin_completion_cb, tdata); + run_loop_for_ms (tdata, 1000); + + /* Check that the modem has been unlocked */ + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE); + + /* Re lock it */ + set_modem_unlock (tdata, MM_MODEM_LOCK_SIM_PIN); + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN); + + /* Set an error that will simulate wrong pin code */ + set_modem_equipment_error (tdata, MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, FALSE); + + tdata->pin_error = TRUE; + mm_sim_send_pin (tdata->sim, "0000", NULL, mm_sim_send_pin_completion_cb, tdata); + run_loop_for_ms (tdata, 1000); + + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN); + + /* Clear the error and retry the pin code */ + set_modem_equipment_error (tdata, 0, TRUE); + tdata->pin_error = FALSE; + mm_sim_send_pin (tdata->sim, "1234", NULL, mm_sim_send_pin_completion_cb, tdata); + run_loop_for_ms (tdata, 1000); + + g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE); + + g_clear_object (&tdata->sim); + g_clear_object (&mm_modem); +} + +int main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add ("/MM/stub/modem/interface", + TestData *, NULL, setup, + test_modem_interface, + teardown); + g_test_add ("/MM/stub/sim/interface", + TestData *, NULL, setup, + test_sim_interface, + teardown); + return g_test_run (); +} diff --git a/tools/tests/test-wrapper.sh.in b/tools/tests/test-wrapper.sh.in new file mode 100644 index 00000000..d64ea4cb --- /dev/null +++ b/tools/tests/test-wrapper.sh.in @@ -0,0 +1,5 @@ +#!/bin/bash + +# For debugging behavior of test-modemmanager-service.py, you can modify +# this line to add --log-file option +GI_TYPELIB_PATH=@abs_top_builddir@/libmm-glib @abs_top_srcdir@/tools/test-modemmanager-service.py